Enabling the CELT post-filter in Opus
[opus.git] / src / test_opus.c
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    - Neither the name of the Xiph.org Foundation nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19
20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <math.h>
40 #include <string.h>
41 #include "opus.h"
42 #include "SKP_debug.h"
43
44
45 #define MAX_PACKET 1024
46
47 void print_usage( char* argv[] ) 
48 {
49     fprintf(stderr, "Usage: %s <mode (0/1/2)> <sampling rate (Hz)> <channels> <frame size (samples)> "
50         "<bits per second>  [options] <input> <output>\n\n", argv[0]);
51     fprintf(stderr, "mode: 0 for SILK, 1 for hybrid, 2 for CELT:\n" );
52     fprintf(stderr, "options:\n" );
53     fprintf(stderr, "-vbr                 : enable variable bitrate (recommended for SILK)\n" );
54     fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB>  : audio bandwidth (from narrowband to fullband)\n" );
55     fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
56     fprintf(stderr, "-complexity <comp>   : SILK complexity, 0: low, 1: medium, 2: high; default: 2\n" );
57     fprintf(stderr, "-inbandfec           : enable SILK inband FEC\n" );
58     fprintf(stderr, "-dtx                 : enable SILK DTX\n" );
59     fprintf(stderr, "-loss <perc>         : simulate packet loss, in percent (0-100); default: 0\n" );
60 }
61
62 #ifdef _WIN32
63 #       define STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
64 #else
65 #       define STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y)
66 #endif 
67
68
69 int main(int argc, char *argv[])
70 {
71    int err;
72    char *inFile, *outFile;
73    FILE *fin, *fout;
74    OpusEncoder *enc;
75    OpusDecoder *dec;
76    int args;
77    int len;
78    int frame_size, channels;
79    int bitrate_bps;
80    unsigned char *data;
81    int sampling_rate;
82    int use_vbr;
83    int internal_sampling_rate_Hz;
84    int max_payload_bytes;
85    int complexity;
86    int use_inbandfec;
87    int use_dtx;
88    int packet_loss_perc;
89    int count=0, count_act=0, k;
90    int skip;
91    int stop=0;
92    int tot_read=0, tot_written=0;
93    short *in, *out;
94    int mode;
95    double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
96
97    if (argc < 8 )
98    {
99       print_usage( argv );
100       return 1;
101    }
102
103    mode = atoi(argv[1]) + MODE_SILK_ONLY;
104    sampling_rate = atoi(argv[2]);
105    channels = atoi(argv[3]);
106    frame_size = atoi(argv[4]);
107    bitrate_bps = atoi(argv[5]);
108
109    /* defaults: */
110    use_vbr = 0;
111    int bandwidth=-1;
112    internal_sampling_rate_Hz = sampling_rate;
113    max_payload_bytes = MAX_PACKET;
114    complexity = 2;
115    use_inbandfec = 0;
116    use_dtx = 0;
117    packet_loss_perc = 0;
118
119    args = 6;
120    while( args < argc - 2 ) {
121        /* process command line options */
122         if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-vbr" ) == 0 ) {
123             use_vbr = 1;
124             args++;
125         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) {
126             if (strcmp(argv[ args + 1 ], "NB")==0)
127                 bandwidth = BANDWIDTH_NARROWBAND;
128             else if (strcmp(argv[ args + 1 ], "MB")==0)
129                 bandwidth = BANDWIDTH_MEDIUMBAND;
130             else if (strcmp(argv[ args + 1 ], "WB")==0)
131                 bandwidth = BANDWIDTH_WIDEBAND;
132             else if (strcmp(argv[ args + 1 ], "SWB")==0)
133                 bandwidth = BANDWIDTH_SUPERWIDEBAND;
134             else if (strcmp(argv[ args + 1 ], "FB")==0)
135                 bandwidth = BANDWIDTH_FULLBAND;
136             else {
137                 fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]);
138                 return 1;
139             }
140             args += 2;
141         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
142             max_payload_bytes = atoi( argv[ args + 1 ] );
143             args += 2;
144         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
145             complexity = atoi( argv[ args + 1 ] );
146             args += 2;
147         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
148             use_inbandfec = 1;
149             args++;
150         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-fec") == 0 ) {
151             use_dtx = 1;
152             args++;
153         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {
154             packet_loss_perc = atoi( argv[ args + 1 ] );
155             args += 2;
156         } else {
157             printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
158             print_usage( argv );
159             return 1;
160         }
161    }
162
163    if( mode < MODE_SILK_ONLY || mode > MODE_CELT_ONLY ) {
164       fprintf (stderr, "mode must be: 0, 1 or 2\n");
165       return 1;
166    }
167
168    if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
169    {
170       fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
171                         MAX_PACKET);
172       return 1;
173    }
174    if (bitrate_bps < 0 || bitrate_bps*frame_size/sampling_rate > max_payload_bytes*8)
175    {
176       fprintf (stderr, "bytes per packet must be between 0 and %d\n",
177                         max_payload_bytes);
178       return 1;
179    }
180
181    inFile = argv[argc-2];
182    fin = fopen(inFile, "rb");
183    if (!fin)
184    {
185       fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
186       return 1;
187    }
188    outFile = argv[argc-1];
189    fout = fopen(outFile, "wb+");
190    if (!fout)
191    {
192       fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
193       return 1;
194    }
195
196    if (mode==MODE_SILK_ONLY)
197    {
198        if (bandwidth == BANDWIDTH_SUPERWIDEBAND || bandwidth == BANDWIDTH_SUPERWIDEBAND)
199        {
200            fprintf (stderr, "Predictive mode only supports up to wideband\n");
201            return 1;
202        }
203    }
204    if (mode==MODE_HYBRID)
205    {
206        if (bandwidth != BANDWIDTH_SUPERWIDEBAND && bandwidth != BANDWIDTH_FULLBAND)
207        {
208            fprintf (stderr, "Hybrid mode only supports superwideband and fullband\n");
209            return 1;
210        }
211    }
212    if (mode==MODE_CELT_ONLY)
213    {
214        if (bandwidth == BANDWIDTH_MEDIUMBAND)
215        {
216            fprintf (stderr, "Transform mode does not support mediumband\n");
217            return 1;
218        }
219    }
220
221    enc = opus_encoder_create(sampling_rate, channels);
222    dec = opus_decoder_create(sampling_rate, channels);
223
224    opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
225    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
226
227    if (bandwidth != -1)
228        opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
229
230    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
231    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
232    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
233    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
234
235    //skip = 5*sampling_rate/1000 + 18;      // 18 is when SILK resamples
236    skip = 5*sampling_rate/1000;
237
238    in = (short*)malloc(frame_size*channels*sizeof(short));
239    out = (short*)malloc(frame_size*channels*sizeof(short));
240    data = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
241    while (!stop)
242    {
243       int write_samples;
244       err = fread(in, sizeof(short), frame_size*channels, fin);
245       tot_read += err;
246       if (err < frame_size*channels)
247       {
248           int i;
249           for (i=err;i<frame_size*channels;i++)
250               in[i] = 0;
251       }
252       len = opus_encode(enc, in, frame_size, data, max_payload_bytes);
253       if (len <= 0)
254       {
255          fprintf (stderr, "opus_encode() returned %d\n", len);
256          return 1;
257       }
258
259       opus_decode(dec, rand()%100<packet_loss_perc ? NULL : data, len, out, frame_size);
260       count++;
261       tot_written += (frame_size-skip)*channels;
262       write_samples = frame_size;
263       if (tot_written > tot_read && skip==0)
264       {
265           write_samples -= (tot_written-tot_read)/channels;
266           stop = 1;
267       }
268       fwrite(out+skip, sizeof(short), (write_samples-skip)*channels, fout);
269       skip = 0;
270
271       /* count bits */
272       bits += len*8;
273       nrg = 0.0;
274       for ( k = 0; k < frame_size * channels; k++ ) {
275           nrg += out[ k ] * (double)out[ k ];
276       }
277       if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
278           bits_act += len*8;
279           count_act++;
280       }
281           /* Variance */
282           bits2 += len*len*64;
283    }
284    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
285    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
286    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
287    DEBUG_STORE_CLOSE_FILES              /* Close any files to which intermediate results were stored */
288    opus_encoder_destroy(enc);
289    opus_decoder_destroy(dec);
290    fclose(fin);
291    fclose(fout);
292    free(in);
293    free(out);
294    return 0;
295 }