SILK update with LBRR and some bugfixes
[opus.git] / test / Encoder.c
1 /***********************************************************************\r
2 Copyright (c) 2006-2011, Skype Limited. All rights reserved. \r
3 Redistribution and use in source and binary forms, with or without \r
4 modification, (subject to the limitations in the disclaimer below) \r
5 are permitted provided that the following conditions are met:\r
6 - Redistributions of source code must retain the above copyright notice,\r
7 this list of conditions and the following disclaimer.\r
8 - Redistributions in binary form must reproduce the above copyright \r
9 notice, this list of conditions and the following disclaimer in the \r
10 documentation and/or other materials provided with the distribution.\r
11 - Neither the name of Skype Limited, nor the names of specific \r
12 contributors, may be used to endorse or promote products derived from \r
13 this software without specific prior written permission.\r
14 NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED \r
15 BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND \r
16 CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
17 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND \r
18 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE \r
19 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, \r
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF \r
22 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON \r
23 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
26 ***********************************************************************/\r
27 \r
28 \r
29 /*****************************/\r
30 /* Silk encoder test program */\r
31 /*****************************/\r
32 \r
33 #ifdef _WIN32\r
34 #define _CRT_SECURE_NO_DEPRECATE    1\r
35 #endif\r
36 \r
37 #include <stdio.h>\r
38 #include <stdlib.h>\r
39 #include <string.h>\r
40 #include <math.h>\r
41 #include "SKP_Silk_SDK_API.h"\r
42 #include "../src_SigProc_FIX/SKP_Silk_SigProc_FIX.h"\r
43 \r
44 /* Define codec specific settings */\r
45 #define MAX_BYTES_PER_FRAME     250 // Equals peak bitrate of 100 kbps \r
46 #define MAX_INPUT_FRAMES        5\r
47 #define MAX_LBRR_DELAY          2\r
48 #define MAX_FRAME_LENGTH        320\r
49 #define MAX_FRAME_LENGTH_MS     20\r
50 #define MAX_API_FS_KHZ          48\r
51 \r
52 #ifdef SKP_MACRO_COUNT\r
53     varDefine /* Define and reset global counters */\r
54 #endif\r
55 \r
56 #ifdef _SYSTEM_IS_BIG_ENDIAN\r
57 /* Function to convert a little endian int16 to a */\r
58 /* big endian int16 or vica verca                 */\r
59 void swap_endian(\r
60     SKP_int16       vec[],              /*  I/O array of */\r
61     SKP_int         len                 /*  I   length      */\r
62 )\r
63 {\r
64     SKP_int i;\r
65     SKP_int16 tmp;\r
66     SKP_uint8 *p1, *p2;\r
67 \r
68     for( i = 0; i < len; i++ ){\r
69         tmp = vec[ i ];\r
70         p1 = (SKP_uint8 *)&vec[ i ]; p2 = (SKP_uint8 *)&tmp;\r
71         p1[ 0 ] = p2[ 1 ]; p1[ 1 ] = p2[ 0 ];\r
72     }\r
73 }\r
74 #endif\r
75 \r
76 static void print_usage( char* argv[] ) {\r
77     printf( "\nusage: %s in.pcm out.bit [settings]\n", argv[ 0 ] );\r
78     printf( "\nin.pcm               : Speech input to encoder" );\r
79     printf( "\nout.bit              : Bitstream output from encoder" );\r
80     printf( "\n   settings:" );\r
81     printf( "\n-Fs_API <Hz>         : API sampling rate in Hz, default: 16000" );\r
82     printf( "\n-Fs_maxInternal <Hz> : Maximum internal sampling rate in Hz, default: 16000" ); \r
83     printf( "\n-packetlength <ms>   : Packet interval in ms, default: 20" );\r
84     printf( "\n-rate <bps>          : Target bitrate; default: 25000" );\r
85     printf( "\n-loss <perc>         : Uplink loss estimate, in percent (0-100); default: 0" );\r
86     printf( "\n-inbandFEC <flag>    : Enable inband FEC usage (0/1); default: 0" );\r
87     printf( "\n-complexity <comp>   : Set complexity, 0: low, 1: medium, 2: high; default: 2" );\r
88     printf( "\n-DTX <flag>          : Enable DTX (0/1); default: 0" );\r
89     printf( "\n-quiet               : Print only some basic values" );\r
90     printf( "\n");\r
91 }\r
92 \r
93 int main( int argc, char* argv[] )\r
94 {\r
95     double    filetime;\r
96     size_t    counter;\r
97     SKP_int32 k, args, totPackets, totActPackets, ret, nBytes;\r
98     double    sumBytes, sumActBytes, avg_rate, act_rate, nrg;\r
99     SKP_int16 in[ MAX_FRAME_LENGTH_MS * MAX_API_FS_KHZ * MAX_INPUT_FRAMES ];\r
100     char      speechInFileName[ 150 ], bitOutFileName[ 150 ];\r
101     FILE      *bitOutFile, *speechInFile;\r
102     SKP_int32 encSizeBytes;\r
103     void      *psEnc;\r
104 #ifdef SKP_MACRO_COUNT\r
105     SKP_int64  Ops, maxOps = 0, totOps = 0;\r
106 #endif\r
107 #ifdef _SYSTEM_IS_BIG_ENDIAN\r
108     SKP_int16 nBytes_LE;\r
109 #endif\r
110     SKP_uint8      range_buf[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES ];\r
111     ec_enc         range_enc_celt_state;\r
112 \r
113     /* default settings */\r
114     SKP_int32 API_fs_Hz = 16000;\r
115     SKP_int32 max_internal_fs_Hz = 16000;\r
116     SKP_int32 min_internal_fs_Hz = 8000;\r
117     SKP_int32 targetRate_bps = 25000;\r
118     SKP_int32 packetSize_ms = 20;\r
119     SKP_int32 frameSizeReadFromFile_ms = 10;\r
120     SKP_int32 packetLoss_perc = 0, complexity_mode = 2, smplsSinceLastPacket;\r
121     SKP_int32 INBandFEC_enabled = 0, DTX_enabled = 0, quiet = 0;\r
122     SKP_SILK_SDK_EncControlStruct encControl; // Struct for input to encoder\r
123 \r
124         \r
125     if( argc < 3 ) {\r
126         print_usage( argv );\r
127         exit( 0 );\r
128     } \r
129     \r
130     /* get arguments */\r
131     args = 1;\r
132     strcpy( speechInFileName, argv[ args ] );\r
133     args++;\r
134     strcpy( bitOutFileName,   argv[ args ] );\r
135     args++;\r
136     while( args < argc ) {\r
137         if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-Fs_API" ) == 0 ) {\r
138             sscanf( argv[ args + 1 ], "%d", &API_fs_Hz );\r
139             args += 2;\r
140         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-Fs_maxInternal" ) == 0 ) {\r
141             sscanf( argv[ args + 1 ], "%d", &max_internal_fs_Hz );\r
142             args += 2;\r
143         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-packetlength" ) == 0 ) {\r
144             sscanf( argv[ args + 1 ], "%d", &packetSize_ms );\r
145             args += 2;\r
146         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-rate" ) == 0 ) {\r
147             sscanf( argv[ args + 1 ], "%d", &targetRate_bps );\r
148             args += 2;\r
149         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {\r
150             sscanf( argv[ args + 1 ], "%d", &packetLoss_perc );\r
151             args += 2;\r
152         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {\r
153             sscanf( argv[ args + 1 ], "%d", &complexity_mode );\r
154             args += 2;\r
155         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandFEC" ) == 0 ) {\r
156             sscanf( argv[ args + 1 ], "%d", &INBandFEC_enabled );\r
157             args += 2;\r
158         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-DTX") == 0 ) {\r
159             sscanf( argv[ args + 1 ], "%d", &DTX_enabled );\r
160             args += 2;\r
161         } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-quiet" ) == 0 ) {\r
162             quiet = 1;\r
163             args++;\r
164         } else {\r
165             printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );\r
166             print_usage( argv );\r
167             exit( 0 );\r
168         }\r
169     }\r
170 \r
171     /* If no max internal set set to API fs */\r
172     if( max_internal_fs_Hz == 0 ) {\r
173         max_internal_fs_Hz = API_fs_Hz;\r
174     }\r
175 \r
176     /* Print options */\r
177     if( !quiet ) {\r
178         printf("******************* Compiled for %d bit cpu ********* \n", (int)sizeof(void*) * 8 );\r
179         printf( "Input:                          %s\n",     speechInFileName );\r
180         printf( "Output:                         %s\n",     bitOutFileName );\r
181         printf( "API sampling rate:              %d Hz\n",  API_fs_Hz );\r
182         printf( "Maximum internal sampling rate: %d Hz\n",  max_internal_fs_Hz );\r
183         printf( "Packet interval:                %d ms\n",  packetSize_ms );\r
184         printf( "Inband FEC used:                %d\n",     INBandFEC_enabled );\r
185         printf( "DTX used:                       %d\n",     DTX_enabled );\r
186         printf( "Complexity:                     %d\n",     complexity_mode );\r
187         printf( "Target bitrate:                 %d bps\n", targetRate_bps );\r
188     }\r
189 \r
190     /* Open files */\r
191     speechInFile = fopen( speechInFileName, "rb" );\r
192     if( speechInFile == NULL ) {\r
193         printf( "Error: could not open input file %s\n", speechInFileName );\r
194         exit( 0 );\r
195     }\r
196     bitOutFile = fopen( bitOutFileName, "wb" );\r
197     if( bitOutFile == NULL ) {\r
198         printf( "Error: could not open output file %s\n", bitOutFileName );\r
199         exit( 0 );\r
200     }\r
201 \r
202     /* Create Encoder */\r
203     ret = SKP_Silk_SDK_Get_Encoder_Size( &encSizeBytes );\r
204     if( ret ) {\r
205         printf( "\nSKP_Silk_create_encoder returned %d", ret );\r
206     }\r
207 \r
208     psEnc = malloc( encSizeBytes );\r
209 \r
210     /* Reset Encoder */\r
211     ret = SKP_Silk_SDK_InitEncoder( psEnc, &encControl );\r
212     if( ret ) {\r
213         printf( "\nSKP_Silk_reset_encoder returned %d", ret );\r
214     }\r
215     \r
216     /* Set Encoder parameters */\r
217     encControl.API_sampleRate        = API_fs_Hz;\r
218     encControl.maxInternalSampleRate = max_internal_fs_Hz;\r
219     encControl.minInternalSampleRate = min_internal_fs_Hz;\r
220     encControl.payloadSize_ms        = packetSize_ms;\r
221     encControl.packetLossPercentage  = packetLoss_perc;\r
222     encControl.useInBandFEC          = INBandFEC_enabled;\r
223     encControl.useDTX                = DTX_enabled;\r
224     encControl.complexity            = complexity_mode;\r
225     encControl.bitRate               = ( targetRate_bps > 0 ? targetRate_bps : 0 );\r
226 \r
227     if( API_fs_Hz > MAX_API_FS_KHZ * 1000 || API_fs_Hz < 0 ) {\r
228         printf( "\nError: API sampling rate = %d out of range, valid range 8000 - 48000 \n \n", API_fs_Hz );\r
229         exit( 0 );\r
230     }\r
231 \r
232     totPackets           = 0;\r
233     totActPackets        = 0;\r
234     smplsSinceLastPacket = 0;\r
235     sumBytes             = 0.0;\r
236     sumActBytes          = 0.0;\r
237     \r
238     while( 1 ) {\r
239         if( smplsSinceLastPacket == 0 ) {\r
240             /* Init range coder */\r
241             ec_enc_init( &range_enc_celt_state, range_buf, MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES );\r
242         }\r
243 \r
244         /* Read input from file */\r
245         counter = fread( in, sizeof( SKP_int16 ), ( frameSizeReadFromFile_ms * API_fs_Hz ) / 1000, speechInFile );\r
246 #ifdef _SYSTEM_IS_BIG_ENDIAN\r
247         swap_endian( in, counter );\r
248 #endif\r
249         if( (SKP_int)counter < ( ( frameSizeReadFromFile_ms * API_fs_Hz ) / 1000 ) ) {\r
250             break;\r
251         }\r
252 \r
253         /* max payload size */\r
254         nBytes = MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES;\r
255 \r
256         /* Silk Encoder */\r
257         ret = SKP_Silk_SDK_Encode( psEnc, &encControl, in, (SKP_int16)counter, &range_enc_celt_state, &nBytes );\r
258         if( ret ) {\r
259             printf( "\nSKP_Silk_Encode returned %d", ret );\r
260             break;\r
261         }\r
262 \r
263 #ifdef SKP_MACRO_COUNT\r
264         Ops = SKP_SaveResetCount();\r
265         if( Ops > maxOps ){ maxOps = Ops; }\r
266         totOps += Ops;\r
267 #endif\r
268 \r
269         /* Get packet size */\r
270         packetSize_ms = encControl.payloadSize_ms;\r
271 \r
272         smplsSinceLastPacket += ( SKP_int )counter;\r
273         \r
274         if( ( ( 1000 * smplsSinceLastPacket ) / API_fs_Hz ) == packetSize_ms ) {\r
275             \r
276             /* Finish up the range coder */\r
277             ec_enc_done( &range_enc_celt_state );\r
278             \r
279             /* Sends a dummy zero size packet in case of DTX period  */\r
280             /* to make it work with the decoder test program.        */\r
281             /* In practice should be handled by RTP sequence numbers */\r
282             totPackets++;\r
283             sumBytes += nBytes;\r
284             nrg = 0.0;\r
285             for( k = 0; k < ( SKP_int )counter; k++ ) {\r
286                 nrg += in[ k ] * (double)in[ k ];\r
287             }\r
288             if( ( nrg / ( SKP_int )counter ) > 1e3 ) {\r
289                 sumActBytes += nBytes;\r
290                 totActPackets++;\r
291             }\r
292 \r
293             /* Write payload size */\r
294 #ifdef _SYSTEM_IS_BIG_ENDIAN\r
295             nBytes_LE = nBytes;\r
296             swap_endian( &nBytes_LE, 1 );\r
297             fwrite( &nBytes_LE, sizeof( SKP_int16 ), 1, bitOutFile );\r
298 #else\r
299             fwrite( &nBytes, sizeof( SKP_int32 ), 1, bitOutFile );\r
300 #endif\r
301 \r
302             /* Write payload */\r
303             fwrite( range_buf, sizeof( SKP_uint8 ), nBytes, bitOutFile );\r
304         \r
305             if( !quiet && totPackets % 100 == 0 ) {\r
306                 fprintf( stderr, "\rPackets encoded:              %d", totPackets );\r
307             }\r
308             smplsSinceLastPacket = 0;\r
309         }\r
310     }\r
311 \r
312     /* Write dummy because it can not end with 0 bytes */\r
313     nBytes = -1;\r
314 \r
315     /* Write payload size */\r
316     fwrite( &nBytes, sizeof( SKP_int32 ), 1, bitOutFile );\r
317 \r
318     /* Free Encoder */\r
319     free( psEnc );\r
320 \r
321     fclose( speechInFile );\r
322     fclose( bitOutFile   );\r
323 \r
324     filetime  = totPackets * 1e-3 * packetSize_ms;\r
325     avg_rate  = 8.0 / packetSize_ms * sumBytes       / totPackets;\r
326     act_rate  = 8.0 / packetSize_ms * sumActBytes    / totActPackets;\r
327     if( !quiet ) {\r
328         printf( "\nFile length:                 %.3f s", filetime );\r
329         printf( "\nAverage bitrate:             %.3f kbps", avg_rate  );\r
330         printf( "\nActive bitrate:              %.3f kbps", act_rate  );\r
331 #ifdef SKP_MACRO_COUNT\r
332         printf( "\n \nWMOPS calculation");\r
333         printf( "\nMean:                        %.3f WMOPS", (float)totOps / ((float)packetSize_ms * (float)totPackets * 1e3));\r
334         printf( "\nMax:                         %.3f WMOPS", (float)maxOps / ((float)packetSize_ms * 1e3));\r
335 #endif\r
336         printf( "\n\n" );\r
337     } else {\r
338         /* print average and active bitrates */\r
339         printf( "%.3f %.3f ", avg_rate, act_rate );\r
340 #ifdef SKP_MACRO_COUNT\r
341         /* print average and max WMOPS */\r
342         printf( "%.3f %.3f \n", (float)totOps / ((float)packetSize_ms * (float)totPackets * 1e3), \r
343             (float)maxOps / ((float)packetSize_ms * 1e3));\r
344 #else\r
345         printf( "%.3f %.3f \n", 0, 0);\r
346 #endif\r
347     }\r
348 \r
349     return 0;\r
350 }\r