1/* Copyright (c) 2007-2008 CSIRO
2   Copyright (c) 2007-2009 Xiph.Org Foundation
3   Written by Jean-Marc Valin */
4/*
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions
7   are met:
8
9   - Redistributions of source code must retain the above copyright
10   notice, this list of conditions and the following disclaimer.
11
12   - Redistributions in binary form must reproduce the above copyright
13   notice, this list of conditions and the following disclaimer in the
14   documentation and/or other materials provided with the distribution.
15
16   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "opus_custom.h"
34#include "arch.h"
35#include <stdio.h>
36#include <stdlib.h>
37#include <math.h>
38#include <string.h>
39
40#define MAX_PACKET 1275
41
42int main(int argc, char *argv[])
43{
44   int err;
45   char *inFile, *outFile;
46   FILE *fin, *fout;
47   OpusCustomMode *mode=NULL;
48   OpusCustomEncoder *enc;
49   OpusCustomDecoder *dec;
50   int len;
51   opus_int32 frame_size, channels, rate;
52   int bytes_per_packet;
53   unsigned char data[MAX_PACKET];
54   int complexity;
55#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
56   int i;
57   double rmsd = 0;
58#endif
59   int count = 0;
60   opus_int32 skip;
61   opus_int16 *in, *out;
62   if (argc != 9 && argc != 8 && argc != 7)
63   {
64      fprintf (stderr, "Usage: test_opus_custom <rate> <channels> <frame size> "
65               " <bytes per packet> [<complexity> [packet loss rate]] "
66               "<input> <output>\n");
67      return 1;
68   }
69
70   rate = (opus_int32)atol(argv[1]);
71   channels = atoi(argv[2]);
72   frame_size = atoi(argv[3]);
73   mode = opus_custom_mode_create(rate, frame_size, NULL);
74   if (mode == NULL)
75   {
76      fprintf(stderr, "failed to create a mode\n");
77      return 1;
78   }
79
80   bytes_per_packet = atoi(argv[4]);
81   if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET)
82   {
83      fprintf (stderr, "bytes per packet must be between 0 and %d\n",
84                        MAX_PACKET);
85      return 1;
86   }
87
88   inFile = argv[argc-2];
89   fin = fopen(inFile, "rb");
90   if (!fin)
91   {
92      fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
93      return 1;
94   }
95   outFile = argv[argc-1];
96   fout = fopen(outFile, "wb+");
97   if (!fout)
98   {
99      fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
100      fclose(fin);
101      return 1;
102   }
103
104   enc = opus_custom_encoder_create(mode, channels, &err);
105   if (err != 0)
106   {
107      fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err));
108      fclose(fin);
109      fclose(fout);
110      return 1;
111   }
112   dec = opus_custom_decoder_create(mode, channels, &err);
113   if (err != 0)
114   {
115      fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err));
116      fclose(fin);
117      fclose(fout);
118      return 1;
119   }
120   opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip));
121
122   if (argc>7)
123   {
124      complexity=atoi(argv[5]);
125      opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity));
126   }
127
128   in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
129   out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
130
131   while (!feof(fin))
132   {
133      int ret;
134      err = fread(in, sizeof(short), frame_size*channels, fin);
135      if (feof(fin))
136         break;
137      len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet);
138      if (len <= 0)
139         fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len));
140
141      /* This is for simulating bit errors */
142#if 0
143      int errors = 0;
144      int eid = 0;
145      /* This simulates random bit error */
146      for (i=0;i<len*8;i++)
147      {
148         if (rand()%atoi(argv[8])==0)
149         {
150            if (i<64)
151            {
152               errors++;
153               eid = i;
154            }
155            data[i/8] ^= 1<<(7-(i%8));
156         }
157      }
158      if (errors == 1)
159         data[eid/8] ^= 1<<(7-(eid%8));
160      else if (errors%2 == 1)
161         data[rand()%8] ^= 1<<rand()%8;
162#endif
163
164#if 1 /* Set to zero to use the encoder's output instead */
165      /* This is to simulate packet loss */
166      if (argc==9 && rand()%1000<atoi(argv[argc-3]))
167      /*if (errors && (errors%2==0))*/
168         ret = opus_custom_decode(dec, NULL, len, out, frame_size);
169      else
170         ret = opus_custom_decode(dec, data, len, out, frame_size);
171      if (ret < 0)
172         fprintf(stderr, "opus_custom_decode() failed: %s\n", opus_strerror(ret));
173#else
174      for (i=0;i<ret*channels;i++)
175         out[i] = in[i];
176#endif
177#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
178      for (i=0;i<ret*channels;i++)
179      {
180         rmsd += (in[i]-out[i])*1.0*(in[i]-out[i]);
181         /*out[i] -= in[i];*/
182      }
183#endif
184      count++;
185      fwrite(out+skip*channels, sizeof(short), (ret-skip)*channels, fout);
186      skip = 0;
187   }
188   PRINT_MIPS(stderr);
189
190   opus_custom_encoder_destroy(enc);
191   opus_custom_decoder_destroy(dec);
192   fclose(fin);
193   fclose(fout);
194   opus_custom_mode_destroy(mode);
195   free(in);
196   free(out);
197#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
198   if (rmsd > 0)
199   {
200      rmsd = sqrt(rmsd/(1.0*frame_size*channels*count));
201      fprintf (stderr, "Error: encoder doesn't match decoder\n");
202      fprintf (stderr, "RMS mismatch is %f\n", rmsd);
203      return 1;
204   } else {
205      fprintf (stderr, "Encoder matches decoder!!\n");
206   }
207#endif
208   return 0;
209}
210
211