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