moved declaration of integer up to the top of code block in speexdec.c
[speexdsp.git] / src / speexdec.c
1 /* Copyright (C) 2002-2003 Jean-Marc Valin 
2    File: speexdec.c
3
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions
6    are met:
7    
8    - Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10    
11    - Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14    
15    - Neither the name of the Xiph.org Foundation nor the names of its
16    contributors may be used to endorse or promote products derived from
17    this software without specific prior written permission.
18    
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #if !defined WIN32 && !defined _WIN32
38 #include <unistd.h>
39 #include <getopt.h>
40 #endif
41 #ifndef HAVE_GETOPT_LONG
42 #include "getopt_win.h"
43 #endif
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include <speex/speex.h>
48 #include <ogg/ogg.h>
49
50 #if defined WIN32 || defined _WIN32
51 #include <windows.h>
52 #include "getopt_win.h"
53 #include "wave_out.h"
54 /* We need the following two to set stdout to binary */
55 #include <io.h>
56 #include <fcntl.h>
57 #endif
58 #include <math.h>
59
60 #ifdef __MINGW32__
61 #include "wave_out.c"
62 #endif
63
64 #ifdef HAVE_SYS_SOUNDCARD_H
65 #include <sys/soundcard.h>
66 #include <sys/types.h>
67 #include <sys/stat.h>
68 #include <fcntl.h>
69 #include <sys/ioctl.h>
70
71 #elif defined HAVE_SYS_AUDIOIO_H
72 #include <sys/types.h>
73 #include <fcntl.h>
74 #include <sys/ioctl.h>
75 #include <sys/audioio.h>
76 #ifndef AUDIO_ENCODING_SLINEAR
77 #define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR /* Solaris */
78 #endif
79
80 #endif
81
82 #include <string.h>
83 #include "wav_io.h"
84 #include <speex/speex_header.h>
85 #include <speex/speex_stereo.h>
86 #include <speex/speex_callbacks.h>
87 #include "misc.h"
88
89 #define MAX_FRAME_SIZE 2000
90
91 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
92                            ((buf[base+2]<<16)&0xff0000)| \
93                            ((buf[base+1]<<8)&0xff00)| \
94                             (buf[base]&0xff))
95
96 static void print_comments(char *comments, int length)
97 {
98    char *c=comments;
99    int len, i, nb_fields;
100    char *end;
101    
102    if (length<8)
103    {
104       fprintf (stderr, "Invalid/corrupted comments\n");
105       return;
106    }
107    end = c+length;
108    len=readint(c, 0);
109    c+=4;
110    if (c+len>end)
111    {
112       fprintf (stderr, "Invalid/corrupted comments\n");
113       return;
114    }
115    fwrite(c, 1, len, stderr);
116    c+=len;
117    fprintf (stderr, "\n");
118    if (c+4>end)
119    {
120       fprintf (stderr, "Invalid/corrupted comments\n");
121       return;
122    }
123    nb_fields=readint(c, 0);
124    c+=4;
125    for (i=0;i<nb_fields;i++)
126    {
127       if (c+4>end)
128       {
129          fprintf (stderr, "Invalid/corrupted comments\n");
130          return;
131       }
132       len=readint(c, 0);
133       c+=4;
134       if (c+len>end)
135       {
136          fprintf (stderr, "Invalid/corrupted comments\n");
137          return;
138       }
139       fwrite(c, 1, len, stderr);
140       c+=len;
141       fprintf (stderr, "\n");
142    }
143 }
144
145 FILE *out_file_open(char *outFile, int rate, int *channels)
146 {
147    FILE *fout=NULL;
148    /*Open output file*/
149    if (strlen(outFile)==0)
150    {
151 #if defined HAVE_SYS_SOUNDCARD_H
152       int audio_fd, format, stereo;
153       audio_fd=open("/dev/dsp", O_WRONLY);
154       if (audio_fd<0)
155       {
156          perror("Cannot open /dev/dsp");
157          exit(1);         
158       }
159
160       format=AFMT_S16_NE;
161       if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
162       {
163          perror("SNDCTL_DSP_SETFMT");
164          close(audio_fd);
165          exit(1);
166       }
167
168       stereo=0;
169       if (*channels==2)
170          stereo=1;
171       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)
172       {
173          perror("SNDCTL_DSP_STEREO");
174          close(audio_fd);
175          exit(1);
176       }
177       if (stereo!=0)
178       {
179          if (*channels==1)
180             fprintf (stderr, "Cannot set mono mode, will decode in stereo\n");
181          *channels=2;
182       }
183
184       if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)
185       {
186          perror("SNDCTL_DSP_SPEED");
187          close(audio_fd);
188          exit(1);
189       }
190       fout = fdopen(audio_fd, "w");
191 #elif defined HAVE_SYS_AUDIOIO_H
192       audio_info_t info;
193       int audio_fd;
194       
195       audio_fd = open("/dev/audio", O_WRONLY);
196       if (audio_fd<0)
197       {
198          perror("Cannot open /dev/audio");
199          exit(1);
200       }
201
202       AUDIO_INITINFO(&info);
203 #ifdef AUMODE_PLAY    /* NetBSD/OpenBSD */
204       info.mode = AUMODE_PLAY;
205 #endif
206       info.play.encoding = AUDIO_ENCODING_SLINEAR;
207       info.play.precision = 16;
208       info.play.sample_rate = rate;
209       info.play.channels = *channels;
210       
211       if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0)
212       {
213          perror ("AUDIO_SETINFO");
214          exit(1);
215       }
216       fout = fdopen(audio_fd, "w");
217 #elif defined WIN32 || defined _WIN32
218       {
219          unsigned int speex_channels = *channels;
220          if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, speex_channels))
221          {
222             fprintf (stderr, "Can't access %s\n", "WAVE OUT");
223             exit(1);
224          }
225       }
226 #else
227       fprintf (stderr, "No soundcard support\n");
228       exit(1);
229 #endif
230    } else {
231       if (strcmp(outFile,"-")==0)
232       {
233 #if defined WIN32 || defined _WIN32
234          _setmode(_fileno(stdout), _O_BINARY);
235 #endif
236          fout=stdout;
237       }
238       else 
239       {
240          fout = fopen(outFile, "wb");
241          if (!fout)
242          {
243             perror(outFile);
244             exit(1);
245          }
246          if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0)
247             write_wav_header(fout, rate, *channels, 0, 0);
248       }
249    }
250    return fout;
251 }
252
253 void usage()
254 {
255    printf ("Usage: speexdec [options] input_file.spx [output_file]\n");
256    printf ("\n");
257    printf ("Decodes a Speex file and produce a WAV file or raw file\n");
258    printf ("\n");
259    printf ("input_file can be:\n");
260    printf ("  filename.spx         regular Speex file\n");
261    printf ("  -                    stdin\n");
262    printf ("\n");  
263    printf ("output_file can be:\n");
264    printf ("  filename.wav         Wav file\n");
265    printf ("  filename.*           Raw PCM file (any extension other that .wav)\n");
266    printf ("  -                    stdout\n");
267    printf ("  (nothing)            Will be played to soundcard\n");
268    printf ("\n");  
269    printf ("Options:\n");
270    printf (" --enh                 Enable perceptual enhancement (default)\n");
271    printf (" --no-enh              Disable perceptual enhancement\n");
272    printf (" --force-nb            Force decoding in narrowband\n");
273    printf (" --force-wb            Force decoding in wideband\n");
274    printf (" --force-uwb           Force decoding in ultra-wideband\n");
275    printf (" --mono                Force decoding in mono\n");
276    printf (" --stereo              Force decoding in stereo\n");
277    printf (" --rate n              Force decoding at sampling rate n Hz\n");
278    printf (" --packet-loss n       Simulate n %% random packet loss\n");
279    printf (" -V                    Verbose mode (show bit-rate)\n"); 
280    printf (" -h, --help            This help\n");
281    printf (" -v, --version         Version information\n");
282    printf (" --pf                  Deprecated, use --enh instead\n");
283    printf (" --no-pf               Deprecated, use --no-enh instead\n");
284    printf ("\n");
285    printf ("More information is available from the Speex site: http://www.speex.org\n");
286    printf ("\n");
287    printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n");
288 }
289
290 void version()
291 {
292    printf ("speexdec (Speex decoder) version " SPEEX_VERSION " (compiled " __DATE__ ")\n");
293    printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
294 }
295
296 void version_short()
297 {
298    printf ("speexdec version " SPEEX_VERSION "\n");
299    printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
300 }
301
302 static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet)
303 {
304    void *st;
305    const SpeexMode *mode;
306    SpeexHeader *header;
307    int modeID;
308    SpeexCallback callback;
309       
310    header = speex_packet_to_header((char*)op->packet, op->bytes);
311    if (!header)
312    {
313       fprintf (stderr, "Cannot read header\n");
314       return NULL;
315    }
316    if (header->mode >= SPEEX_NB_MODES)
317    {
318       fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n", 
319                header->mode);
320       return NULL;
321    }
322       
323    modeID = header->mode;
324    if (forceMode!=-1)
325       modeID = forceMode;
326    mode = speex_mode_list[modeID];
327    
328    if (header->speex_version_id > 1)
329    {
330       fprintf (stderr, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", header->speex_version_id);
331       return NULL;
332    }
333
334    if (mode->bitstream_version < header->mode_bitstream_version)
335    {
336       fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n");
337       return NULL;
338    }
339    if (mode->bitstream_version > header->mode_bitstream_version) 
340    {
341       fprintf (stderr, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n");
342       return NULL;
343    }
344    
345    st = speex_decoder_init(mode);
346    if (!st)
347    {
348       fprintf (stderr, "Decoder initialization failed.\n");
349       return NULL;
350    }
351    speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
352    speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
353
354    if (!(*channels==1))
355    {
356       callback.callback_id = SPEEX_INBAND_STEREO;
357       callback.func = speex_std_stereo_request_handler;
358       callback.data = stereo;
359       speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
360    }
361    if (!*rate)
362       *rate = header->rate;
363    /* Adjust rate if --force-* options are used */
364    if (forceMode!=-1)
365    {
366       if (header->mode < forceMode)
367          *rate <<= (forceMode - header->mode);
368       if (header->mode > forceMode)
369          *rate >>= (header->mode - forceMode);
370    }
371
372    speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
373
374    *nframes = header->frames_per_packet;
375
376    if (*channels==-1)
377       *channels = header->nb_channels;
378    
379    if (!quiet)
380    {
381       fprintf (stderr, "Decoding %d Hz audio using %s mode", 
382                *rate, mode->modeName);
383
384       if (*channels==1)
385          fprintf (stderr, " (mono");
386       else
387          fprintf (stderr, " (stereo");
388       
389       if (header->vbr)
390          fprintf (stderr, ", VBR)\n");
391       else
392          fprintf(stderr, ")\n");
393       /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n", 
394        *rate, mode->bitrate, mode->modeName);*/
395    }
396
397    *extra_headers = header->extra_headers;
398
399    free(header);
400    return st;
401 }
402
403 int main(int argc, char **argv)
404 {
405    int c;
406    int option_index = 0;
407    char *inFile, *outFile;
408    FILE *fin, *fout=NULL;
409    short out[MAX_FRAME_SIZE];
410    short output[MAX_FRAME_SIZE];
411    int frame_size=0;
412    void *st=NULL;
413    SpeexBits bits;
414    int packet_count=0;
415    int stream_init = 0;
416    int quiet = 0;
417    ogg_int64_t page_granule=0, last_granule=0;
418    int skip_samples=0, page_nb_packets;
419    struct option long_options[] =
420    {
421       {"help", no_argument, NULL, 0},
422       {"quiet", no_argument, NULL, 0},
423       {"version", no_argument, NULL, 0},
424       {"version-short", no_argument, NULL, 0},
425       {"enh", no_argument, NULL, 0},
426       {"no-enh", no_argument, NULL, 0},
427       {"pf", no_argument, NULL, 0},
428       {"no-pf", no_argument, NULL, 0},
429       {"force-nb", no_argument, NULL, 0},
430       {"force-wb", no_argument, NULL, 0},
431       {"force-uwb", no_argument, NULL, 0},
432       {"rate", required_argument, NULL, 0},
433       {"mono", no_argument, NULL, 0},
434       {"stereo", no_argument, NULL, 0},
435       {"packet-loss", required_argument, NULL, 0},
436       {0, 0, 0, 0}
437    };
438    ogg_sync_state oy;
439    ogg_page       og;
440    ogg_packet     op;
441    ogg_stream_state os;
442    int enh_enabled;
443    int nframes=2;
444    int print_bitrate=0;
445    int close_in=0;
446    int eos=0;
447    int forceMode=-1;
448    int audio_size=0;
449    float loss_percent=-1;
450    SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
451    int channels=-1;
452    int rate=0;
453    int extra_headers;
454    int wav_format=0;
455
456    enh_enabled = 1;
457
458    /*Process options*/
459    while(1)
460    {
461       c = getopt_long (argc, argv, "hvV",
462                        long_options, &option_index);
463       if (c==-1)
464          break;
465       
466       switch(c)
467       {
468       case 0:
469          if (strcmp(long_options[option_index].name,"help")==0)
470          {
471             usage();
472             exit(0);
473          } else if (strcmp(long_options[option_index].name,"quiet")==0)
474          {
475             quiet = 1;
476          } else if (strcmp(long_options[option_index].name,"version")==0)
477          {
478             version();
479             exit(0);
480          } else if (strcmp(long_options[option_index].name,"version-short")==0)
481          {
482             version_short();
483             exit(0);
484          } else if (strcmp(long_options[option_index].name,"enh")==0)
485          {
486             enh_enabled=1;
487          } else if (strcmp(long_options[option_index].name,"no-enh")==0)
488          {
489             enh_enabled=0;
490          } else if (strcmp(long_options[option_index].name,"pf")==0)
491          {
492             fprintf (stderr, "--pf is deprecated, use --enh instead\n");
493             enh_enabled=1;
494          } else if (strcmp(long_options[option_index].name,"no-pf")==0)
495          {
496             fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n");
497             enh_enabled=0;
498          } else if (strcmp(long_options[option_index].name,"force-nb")==0)
499          {
500             forceMode=0;
501          } else if (strcmp(long_options[option_index].name,"force-wb")==0)
502          {
503             forceMode=1;
504          } else if (strcmp(long_options[option_index].name,"force-uwb")==0)
505          {
506             forceMode=2;
507          } else if (strcmp(long_options[option_index].name,"mono")==0)
508          {
509             channels=1;
510          } else if (strcmp(long_options[option_index].name,"stereo")==0)
511          {
512             channels=2;
513          } else if (strcmp(long_options[option_index].name,"rate")==0)
514          {
515             rate=atoi (optarg);
516          } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
517          {
518             loss_percent = atof(optarg);
519          }
520          break;
521       case 'h':
522          usage();
523          exit(0);
524          break;
525       case 'v':
526          version();
527          exit(0);
528          break;
529       case 'V':
530          print_bitrate=1;
531          break;
532       case '?':
533          usage();
534          exit(1);
535          break;
536       }
537    }
538    if (argc-optind!=2 && argc-optind!=1)
539    {
540       usage();
541       exit(1);
542    }
543    inFile=argv[optind];
544
545    if (argc-optind==2)
546       outFile=argv[optind+1];
547    else
548       outFile = "";
549    wav_format = strlen(outFile)>=4 && (
550                                        strcmp(outFile+strlen(outFile)-4,".wav")==0
551                                        || strcmp(inFile+strlen(inFile)-4,".WAV")==0);
552    /*Open input file*/
553    if (strcmp(inFile, "-")==0)
554    {
555 #if defined WIN32 || defined _WIN32
556       _setmode(_fileno(stdin), _O_BINARY);
557 #endif
558       fin=stdin;
559    }
560    else 
561    {
562       fin = fopen(inFile, "rb");
563       if (!fin)
564       {
565          perror(inFile);
566          exit(1);
567       }
568       close_in=1;
569    }
570
571
572    /*Init Ogg data struct*/
573    ogg_sync_init(&oy);
574    
575    speex_bits_init(&bits);
576    /*Main decoding loop*/
577    while (1)
578    {
579       char *data;
580       int i, j, nb_read;
581       /*Get the ogg buffer for writing*/
582       data = ogg_sync_buffer(&oy, 200);
583       /*Read bitstream from input file*/
584       nb_read = fread(data, sizeof(char), 200, fin);      
585       ogg_sync_wrote(&oy, nb_read);
586
587       /*Loop for all complete pages we got (most likely only one)*/
588       while (ogg_sync_pageout(&oy, &og)==1)
589       {
590          int packet_no;
591          if (stream_init == 0) {
592             ogg_stream_init(&os, ogg_page_serialno(&og));
593             stream_init = 1;
594          }
595          /*Add page to the bitstream*/
596          ogg_stream_pagein(&os, &og);
597          page_granule = ogg_page_granulepos(&og);
598          page_nb_packets = ogg_page_packets(&og);
599          if (page_granule>0 && frame_size)
600          {
601             skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule);
602             if (ogg_page_eos(&og))
603                skip_samples = -skip_samples;
604             /*else if (!ogg_page_bos(&og))
605                skip_samples = 0;*/
606          } else
607          {
608             skip_samples = 0;
609          }
610          /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
611          last_granule = page_granule;
612          /*Extract all available packets*/
613          packet_no=0;
614          while (!eos && ogg_stream_packetout(&os, &op)==1)
615          {
616             /*If first packet, process as Speex header*/
617             if (packet_count==0)
618             {
619                st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet);
620                if (!nframes)
621                   nframes=1;
622                if (!st)
623                   exit(1);
624                fout = out_file_open(outFile, rate, &channels);
625
626             } else if (packet_count==1)
627             {
628                if (!quiet)
629                   print_comments((char*)op.packet, op.bytes);
630             } else if (packet_count<=1+extra_headers)
631             {
632                /* Ignore extra headers */
633             } else {
634                int lost=0;
635                packet_no++;
636                if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
637                   lost=1;
638
639                /*End of stream condition*/
640                if (op.e_o_s)
641                   eos=1;
642
643                /*Copy Ogg packet to Speex bitstream*/
644                speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
645                for (j=0;j!=nframes;j++)
646                {
647                   int ret;
648                   /*Decode frame*/
649                   if (!lost)
650                      ret = speex_decode_int(st, &bits, output);
651                   else
652                      ret = speex_decode_int(st, NULL, output);
653
654                   /*for (i=0;i<frame_size*channels;i++)
655                     printf ("%d\n", (int)output[i]);*/
656
657                   if (ret==-1)
658                      break;
659                   if (ret==-2)
660                   {
661                      fprintf (stderr, "Decoding error: corrupted stream?\n");
662                      break;
663                   }
664                   if (speex_bits_remaining(&bits)<0)
665                   {
666                      fprintf (stderr, "Decoding overflow: corrupted stream?\n");
667                      break;
668                   }
669                   if (channels==2)
670                      speex_decode_stereo_int(output, frame_size, &stereo);
671
672                   if (print_bitrate) {
673                      int tmp;
674                      char ch=13;
675                      speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
676                      fputc (ch, stderr);
677                      fprintf (stderr, "Bitrate is use: %d bps     ", tmp);
678                   }
679                   /*Convert to short and save to output file*/
680                   if (strlen(outFile)!=0)
681                   {
682                      for (i=0;i<frame_size*channels;i++)
683                         out[i]=le_short(output[i]);
684                   } else {
685                      for (i=0;i<frame_size*channels;i++)
686                         out[i]=output[i];
687                   }
688                   {
689                      int frame_offset = 0;
690                      int new_frame_size = frame_size;
691                      /*printf ("packet %d %d\n", packet_no, skip_samples);*/
692                      if (packet_no == 1 && j==0 && skip_samples > 0)
693                      {
694                         /*printf ("chopping first packet\n");*/
695                         new_frame_size -= skip_samples;
696                         frame_offset = skip_samples;
697                      }
698                      if (packet_no == page_nb_packets && skip_samples < 0)
699                      {
700                         int packet_length = nframes*frame_size+skip_samples;
701                         new_frame_size = packet_length - j*frame_size;
702                         if (new_frame_size<0)
703                            new_frame_size = 0;
704                         if (new_frame_size>frame_size)
705                            new_frame_size = frame_size;
706                         /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/
707                      }
708                      if (new_frame_size)
709                      {  
710 #if defined WIN32 || defined _WIN32
711                         if (strlen(outFile)==0)
712                            WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
713                         else
714 #endif
715                            fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
716                   
717                         audio_size+=sizeof(short)*new_frame_size*channels;
718                      }
719                   }
720                }
721             }
722             packet_count++;
723          }
724       }
725       if (feof(fin))
726          break;
727
728    }
729
730    if (wav_format)
731    {
732       if (fseek(fout,4,SEEK_SET)==0)
733       {
734          int tmp;
735          tmp = le_int(audio_size+36);
736          fwrite(&tmp,4,1,fout);
737          if (fseek(fout,32,SEEK_CUR)==0)
738          {
739             tmp = le_int(audio_size);
740             fwrite(&tmp,4,1,fout);
741          } else
742          {
743             fprintf (stderr, "First seek worked, second didn't\n");
744          }
745       } else {
746          fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
747       }
748    }
749
750    if (st)
751       speex_decoder_destroy(st);
752    else 
753    {
754       fprintf (stderr, "This doesn't look like a Speex file\n");
755    }
756    speex_bits_destroy(&bits);
757    if (stream_init)
758       ogg_stream_clear(&os);
759    ogg_sync_clear(&oy);
760
761 #if defined WIN32 || defined _WIN32
762    if (strlen(outFile)==0)
763       WIN_Audio_close ();
764 #endif
765
766    if (close_in)
767       fclose(fin);
768    if (fout != NULL)
769       fclose(fout);   
770
771    return 0;
772 }