1 /*
2  * Copyright 2015 The Emscripten Authors.  All rights reserved.
3  * Emscripten is available under two separate licenses, the MIT license and the
4  * University of Illinois/NCSA Open Source License.  Both these licenses can be
5  * found in the LICENSE file.
6  */
7 
8 /********************************************************************
9  *                                                                  *
10  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
11  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
12  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
13  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
14  *                                                                  *
15  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
16  * by the Xiph.Org Foundation http://www.xiph.org/                  *
17  *                                                                  *
18  ********************************************************************
19 
20  function: vorbis coded test suite using vorbisfile
21  last mod: $Id$
22 
23  ********************************************************************/
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <math.h>
28 #include <string.h>
29 #include <errno.h>
30 
31 #include <vorbis/codec.h>
32 #include <vorbis/vorbisenc.h>
33 
34 
35 #define DATA_LEN        2048
36 
37 #define MAX(a,b)        ((a) > (b) ? (a) : (b))
38 #define ARRAY_LEN(x)   (sizeof(x)/sizeof(x[0]))
39 
40 /* The following function is basically a hacked version of the code in
41  * examples/encoder_example.c */
42 void
write_vorbis_data_or_die(const char * filename,int srate,float q,const float * data,int count,int ch)43 write_vorbis_data_or_die (const char *filename, int srate, float q, const float * data, int count, int ch)
44 {
45   FILE * file ;
46   ogg_stream_state os;
47   ogg_page         og;
48   ogg_packet       op;
49   vorbis_info      vi;
50   vorbis_comment   vc;
51   vorbis_dsp_state vd;
52   vorbis_block     vb;
53 
54   int eos = 0, ret;
55 
56   if ((file = fopen (filename, "wb")) == NULL) {
57     printf("\n\nError : fopen failed : %s\n", strerror (errno)) ;
58     exit (1) ;
59   }
60 
61   /********** Encode setup ************/
62 
63   vorbis_info_init (&vi);
64 
65   ret = vorbis_encode_init_vbr (&vi,ch,srate,q);
66   if (ret) {
67     printf ("vorbis_encode_init_vbr return %d\n", ret) ;
68     exit (1) ;
69   }
70 
71   vorbis_comment_init (&vc);
72   vorbis_comment_add_tag (&vc,"ENCODER","test/util.c");
73   vorbis_analysis_init (&vd,&vi);
74   vorbis_block_init (&vd,&vb);
75 
76   ogg_stream_init (&os,12345678);
77 
78   {
79     ogg_packet header;
80     ogg_packet header_comm;
81     ogg_packet header_code;
82 
83     vorbis_analysis_headerout (&vd,&vc,&header,&header_comm,&header_code);
84     ogg_stream_packetin (&os,&header);
85     ogg_stream_packetin (&os,&header_comm);
86     ogg_stream_packetin (&os,&header_code);
87 
88     /* Ensures the audio data will start on a new page. */
89     while (!eos){
90         int result = ogg_stream_flush (&os,&og);
91         if (result == 0)
92             break;
93         fwrite (og.header,1,og.header_len,file);
94         fwrite (og.body,1,og.body_len,file);
95     }
96 
97   }
98 
99   {
100     /* expose the buffer to submit data */
101     float **buffer = vorbis_analysis_buffer (&vd,count);
102     int i;
103 
104     for(i=0;i<ch;i++)
105       memcpy (buffer [i], data, count * sizeof (float)) ;
106 
107     /* tell the library how much we actually submitted */
108     vorbis_analysis_wrote (&vd,count);
109     vorbis_analysis_wrote (&vd,0);
110   }
111 
112   while (vorbis_analysis_blockout (&vd,&vb) == 1) {
113     vorbis_analysis (&vb,NULL);
114     vorbis_bitrate_addblock (&vb);
115 
116     while (vorbis_bitrate_flushpacket (&vd,&op)) {
117       ogg_stream_packetin (&os,&op);
118 
119       while (!eos) {
120           int result = ogg_stream_pageout (&os,&og);
121           if (result == 0)
122               break;
123           fwrite (og.header,1,og.header_len,file);
124           fwrite (og.body,1,og.body_len,file);
125 
126           if (ogg_page_eos (&og))
127               eos = 1;
128       }
129     }
130   }
131 
132   ogg_stream_clear (&os);
133   vorbis_block_clear (&vb);
134   vorbis_dsp_clear (&vd);
135   vorbis_comment_clear (&vc);
136   vorbis_info_clear (&vi);
137 
138  fclose (file) ;
139 }
140 
141 /* The following function is basically a hacked version of the code in
142  * examples/decoder_example.c */
143 void
read_vorbis_data_or_die(const char * filename,int srate,float * data,int count)144 read_vorbis_data_or_die (const char *filename, int srate, float * data, int count)
145 {
146   ogg_sync_state   oy;
147   ogg_stream_state os;
148   ogg_page         og;
149   ogg_packet       op;
150 
151   vorbis_info      vi;
152   vorbis_comment   vc;
153   vorbis_dsp_state vd;
154   vorbis_block     vb;
155 
156   FILE *file;
157   char *buffer;
158   int  bytes;
159   int eos = 0;
160   int i;
161   int read_total = 0 ;
162 
163   if ((file = fopen (filename, "rb")) == NULL) {
164     printf("\n\nError : fopen failed : %s\n", strerror (errno)) ;
165     exit (1) ;
166   }
167 
168   ogg_sync_init (&oy);
169 
170   {
171     /* fragile!  Assumes all of our headers will fit in the first 8kB,
172        which currently they will */
173     buffer = ogg_sync_buffer (&oy,8192);
174     bytes = fread (buffer,1,8192,file);
175     ogg_sync_wrote (&oy,bytes);
176 
177     if(ogg_sync_pageout (&oy,&og) != 1) {
178       if(bytes < 8192) {
179         printf ("Out of data.\n") ;
180           goto done_decode ;
181       }
182 
183       fprintf (stderr,"Input does not appear to be an Ogg bitstream.\n");
184       exit (1);
185     }
186 
187     ogg_stream_init (&os,ogg_page_serialno(&og));
188 
189     vorbis_info_init (&vi);
190     vorbis_comment_init (&vc);
191     if (ogg_stream_pagein (&os,&og) < 0) {
192       fprintf (stderr,"Error reading first page of Ogg bitstream data.\n");
193       exit (1);
194     }
195 
196     if (ogg_stream_packetout(&os,&op) != 1) {
197       fprintf (stderr,"Error reading initial header packet.\n");
198       exit (1);
199     }
200 
201     if (vorbis_synthesis_headerin (&vi,&vc,&op) < 0) {
202       fprintf (stderr,"This Ogg bitstream does not contain Vorbis "
203           "audio data.\n");
204       exit (1);
205     }
206 
207     i = 0;
208     while ( i < 2) {
209       while (i < 2) {
210 
211         int result = ogg_sync_pageout (&oy,&og);
212         if(result == 0)
213           break;
214         if(result==1) {
215           ogg_stream_pagein(&os,&og);
216 
217           while (i < 2) {
218             result = ogg_stream_packetout (&os,&op);
219             if (result == 0) break;
220             if (result < 0) {
221               fprintf (stderr,"Corrupt secondary header.  Exiting.\n");
222               exit(1);
223             }
224             vorbis_synthesis_headerin (&vi,&vc,&op);
225             i++;
226           }
227         }
228       }
229 
230       buffer = ogg_sync_buffer (&oy,4096);
231       bytes = fread (buffer,1,4096,file);
232       if (bytes == 0 && i < 2) {
233         fprintf (stderr,"End of file before finding all Vorbis headers!\n");
234         exit (1);
235       }
236 
237       ogg_sync_wrote (&oy,bytes);
238     }
239 
240     if (vi.rate != srate) {
241       printf ("\n\nError : File '%s' has sample rate of %ld when it should be %d.\n\n", filename, vi.rate, srate);
242       exit (1) ;
243     }
244 
245     vorbis_synthesis_init (&vd,&vi);
246     vorbis_block_init (&vd,&vb);
247 
248     while(!eos) {
249       while (!eos) {
250         int result = ogg_sync_pageout (&oy,&og);
251         if (result == 0)
252           break;
253         if (result < 0) {
254           fprintf (stderr,"Corrupt or missing data in bitstream; "
255                    "continuing...\n");
256         } else {
257           ogg_stream_pagein (&os,&og);
258           while (1) {
259             result = ogg_stream_packetout (&os,&op);
260 
261             if (result == 0)
262               break;
263             if (result < 0) {
264               /* no reason to complain; already complained above */
265             } else {
266               float **pcm;
267               int samples;
268 
269               if (vorbis_synthesis (&vb,&op) == 0)
270                 vorbis_synthesis_blockin(&vd,&vb);
271               while ((samples = vorbis_synthesis_pcmout (&vd,&pcm)) > 0 && read_total < count) {
272                 int bout = samples < count ? samples : count;
273                 bout = read_total + bout > count ? count - read_total : bout;
274 
275                 memcpy (data + read_total, pcm[0], bout * sizeof (float)) ;
276 
277                 vorbis_synthesis_read (&vd,bout);
278                 read_total += bout ;
279               }
280             }
281           }
282 
283           if (ogg_page_eos (&og)) eos = 1;
284         }
285       }
286 
287       if (!eos) {
288         buffer = ogg_sync_buffer (&oy,4096);
289         bytes = fread (buffer,1,4096,file);
290         ogg_sync_wrote (&oy,bytes);
291         if (bytes == 0) eos = 1;
292       }
293     }
294 
295     ogg_stream_clear (&os);
296 
297     vorbis_block_clear (&vb);
298     vorbis_dsp_clear (&vd);
299     vorbis_comment_clear (&vc);
300     vorbis_info_clear (&vi);
301   }
302 done_decode:
303 
304   /* OK, clean up the framer */
305   ogg_sync_clear (&oy);
306 
307   fclose (file) ;
308 }
309 
310 void
gen_windowed_sine(float * data,int len,float maximum)311 gen_windowed_sine (float *data, int len, float maximum)
312 {    int k ;
313 
314     memset (data, 0, len * sizeof (float)) ;
315 
316     len /= 2 ;
317 
318     for (k = 0 ; k < len ; k++)
319     {    data [k] = sin (2.0 * k * M_PI * 1.0 / 32.0 + 0.4) ;
320 
321         /* Apply Hanning Window. */
322         data [k] *= maximum * (0.5 - 0.5 * cos (2.0 * M_PI * k / ((len) - 1))) ;
323         }
324 
325     return ;
326 }
327 
328 void
set_data_in(float * data,unsigned len,float value)329 set_data_in (float * data, unsigned len, float value)
330 {        unsigned k ;
331 
332         for (k = 0 ; k < len ; k++)
333                 data [k] = value ;
334 }
335 
336 static int check_output (const float * data_in, unsigned len, float allowable);
337 
338 int
main(void)339 main(void){
340   static float data_out [DATA_LEN] ;
341   static float data_in [DATA_LEN] ;
342 
343   /* Do safest and most used sample rates first. */
344   int sample_rates [] = { 44100, 48000, 32000, 22050, 16000, 96000 } ;
345   unsigned k ;
346   int errors = 0 ;
347   int ch;
348 
349   gen_windowed_sine (data_out, ARRAY_LEN (data_out), 0.95);
350 
351   for(ch=1;ch<=8;ch++){
352     float q=-.05;
353     printf("\nTesting %d channel%s\n\n",ch,ch==1?"":"s");
354     while(q<1.){
355       for (k = 0 ; k < ARRAY_LEN (sample_rates); k ++) {
356         char filename [64] ;
357         snprintf (filename, sizeof (filename), "vorbis_%dch_q%.1f_%u.ogg", ch,q*10,sample_rates [k]);
358 
359         printf ("    %-20s : ", filename);
360         fflush (stdout);
361 
362         /* Set to know value. */
363         set_data_in (data_in, ARRAY_LEN (data_in), 3.141);
364 
365         write_vorbis_data_or_die (filename, sample_rates [k], q, data_out, ARRAY_LEN (data_out),ch);
366         read_vorbis_data_or_die (filename, sample_rates [k], data_in, ARRAY_LEN (data_in));
367 
368         if (check_output (data_in, ARRAY_LEN (data_in), (.15f - .1f*q)) != 0)
369           errors ++ ;
370         else {
371           puts ("ok");
372           remove (filename);
373         }
374       }
375       q+=.1;
376     }
377   }
378 
379   if (errors)
380     exit (1);
381 
382   printf("ALL OK\n");
383 
384   return 0;
385 }
386 
387 static int
check_output(const float * data_in,unsigned len,float allowable)388 check_output (const float * data_in, unsigned len, float allowable)
389 {
390   float max_abs = 0.0 ;
391   unsigned k ;
392 
393   for (k = 0 ; k < len ; k++) {
394     float temp = fabs (data_in [k]);
395     max_abs = MAX (max_abs, temp);
396   }
397 
398   if (max_abs < 0.95-allowable) {
399     printf ("Error : max_abs (%f) too small.\n", max_abs);
400     return 1 ;
401   } else if (max_abs > .95+allowable) {
402     printf ("Error : max_abs (%f) too big.\n", max_abs);
403     return 1 ;
404   }
405 
406   return 0 ;
407 }
408 
409