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