2a3876a62a75dd16af8a00cbf768d8a97dbbc15c
[speexdsp.git] / src / speexdec.c
1 /* Copyright (C) 2002-2006 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 "wav_io.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-2006 Jean-Marc Valin\n");
294 }
295
296 void version_short()
297 {
298    printf ("speexdec version " SPEEX_VERSION "\n");
299    printf ("Copyright (C) 2002-2006 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 || header->mode<0)
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
327    mode = speex_lib_get_mode (modeID);
328    
329    if (header->speex_version_id > 1)
330    {
331       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);
332       return NULL;
333    }
334
335    if (mode->bitstream_version < header->mode_bitstream_version)
336    {
337       fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n");
338       return NULL;
339    }
340    if (mode->bitstream_version > header->mode_bitstream_version) 
341    {
342       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");
343       return NULL;
344    }
345    
346    st = speex_decoder_init(mode);
347    if (!st)
348    {
349       fprintf (stderr, "Decoder initialization failed.\n");
350       return NULL;
351    }
352    speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
353    speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
354
355    if (!(*channels==1))
356    {
357       callback.callback_id = SPEEX_INBAND_STEREO;
358       callback.func = speex_std_stereo_request_handler;
359       callback.data = stereo;
360       speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
361    }
362    if (!*rate)
363       *rate = header->rate;
364    /* Adjust rate if --force-* options are used */
365    if (forceMode!=-1)
366    {
367       if (header->mode < forceMode)
368          *rate <<= (forceMode - header->mode);
369       if (header->mode > forceMode)
370          *rate >>= (header->mode - forceMode);
371    }
372
373    speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
374
375    *nframes = header->frames_per_packet;
376
377    if (*channels==-1)
378       *channels = header->nb_channels;
379    
380    if (!quiet)
381    {
382       fprintf (stderr, "Decoding %d Hz audio using %s mode", 
383                *rate, mode->modeName);
384
385       if (*channels==1)
386          fprintf (stderr, " (mono");
387       else
388          fprintf (stderr, " (stereo");
389       
390       if (header->vbr)
391          fprintf (stderr, ", VBR)\n");
392       else
393          fprintf(stderr, ")\n");
394       /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n", 
395        *rate, mode->bitrate, mode->modeName);*/
396    }
397
398    *extra_headers = header->extra_headers;
399
400    free(header);
401    return st;
402 }
403
404 int main(int argc, char **argv)
405 {
406    int c;
407    int option_index = 0;
408    char *inFile, *outFile;
409    FILE *fin, *fout=NULL;
410    short out[MAX_FRAME_SIZE];
411    short output[MAX_FRAME_SIZE];
412    int frame_size=0;
413    void *st=NULL;
414    SpeexBits bits;
415    int packet_count=0;
416    int stream_init = 0;
417    int quiet = 0;
418    ogg_int64_t page_granule=0, last_granule=0;
419    int skip_samples=0, page_nb_packets;
420    struct option long_options[] =
421    {
422       {"help", no_argument, NULL, 0},
423       {"quiet", no_argument, NULL, 0},
424       {"version", no_argument, NULL, 0},
425       {"version-short", no_argument, NULL, 0},
426       {"enh", no_argument, NULL, 0},
427       {"no-enh", no_argument, NULL, 0},
428       {"pf", no_argument, NULL, 0},
429       {"no-pf", no_argument, NULL, 0},
430       {"force-nb", no_argument, NULL, 0},
431       {"force-wb", no_argument, NULL, 0},
432       {"force-uwb", no_argument, NULL, 0},
433       {"rate", required_argument, NULL, 0},
434       {"mono", no_argument, NULL, 0},
435       {"stereo", no_argument, NULL, 0},
436       {"packet-loss", required_argument, NULL, 0},
437       {0, 0, 0, 0}
438    };
439    ogg_sync_state oy;
440    ogg_page       og;
441    ogg_packet     op;
442    ogg_stream_state os;
443    int enh_enabled;
444    int nframes=2;
445    int print_bitrate=0;
446    int close_in=0;
447    int eos=0;
448    int forceMode=-1;
449    int audio_size=0;
450    float loss_percent=-1;
451    SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
452    int channels=-1;
453    int rate=0;
454    int extra_headers;
455    int wav_format=0;
456    int lookahead;
457
458    enh_enabled = 1;
459
460    /*Process options*/
461    while(1)
462    {
463       c = getopt_long (argc, argv, "hvV",
464                        long_options, &option_index);
465       if (c==-1)
466          break;
467       
468       switch(c)
469       {
470       case 0:
471          if (strcmp(long_options[option_index].name,"help")==0)
472          {
473             usage();
474             exit(0);
475          } else if (strcmp(long_options[option_index].name,"quiet")==0)
476          {
477             quiet = 1;
478          } else if (strcmp(long_options[option_index].name,"version")==0)
479          {
480             version();
481             exit(0);
482          } else if (strcmp(long_options[option_index].name,"version-short")==0)
483          {
484             version_short();
485             exit(0);
486          } else if (strcmp(long_options[option_index].name,"enh")==0)
487          {
488             enh_enabled=1;
489          } else if (strcmp(long_options[option_index].name,"no-enh")==0)
490          {
491             enh_enabled=0;
492          } else if (strcmp(long_options[option_index].name,"pf")==0)
493          {
494             fprintf (stderr, "--pf is deprecated, use --enh instead\n");
495             enh_enabled=1;
496          } else if (strcmp(long_options[option_index].name,"no-pf")==0)
497          {
498             fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n");
499             enh_enabled=0;
500          } else if (strcmp(long_options[option_index].name,"force-nb")==0)
501          {
502             forceMode=0;
503          } else if (strcmp(long_options[option_index].name,"force-wb")==0)
504          {
505             forceMode=1;
506          } else if (strcmp(long_options[option_index].name,"force-uwb")==0)
507          {
508             forceMode=2;
509          } else if (strcmp(long_options[option_index].name,"mono")==0)
510          {
511             channels=1;
512          } else if (strcmp(long_options[option_index].name,"stereo")==0)
513          {
514             channels=2;
515          } else if (strcmp(long_options[option_index].name,"rate")==0)
516          {
517             rate=atoi (optarg);
518          } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
519          {
520             loss_percent = atof(optarg);
521          }
522          break;
523       case 'h':
524          usage();
525          exit(0);
526          break;
527       case 'v':
528          version();
529          exit(0);
530          break;
531       case 'V':
532          print_bitrate=1;
533          break;
534       case '?':
535          usage();
536          exit(1);
537          break;
538       }
539    }
540    if (argc-optind!=2 && argc-optind!=1)
541    {
542       usage();
543       exit(1);
544    }
545    inFile=argv[optind];
546
547    if (argc-optind==2)
548       outFile=argv[optind+1];
549    else
550       outFile = "";
551    wav_format = strlen(outFile)>=4 && (
552                                        strcmp(outFile+strlen(outFile)-4,".wav")==0
553                                        || strcmp(outFile+strlen(outFile)-4,".WAV")==0);
554    /*Open input file*/
555    if (strcmp(inFile, "-")==0)
556    {
557 #if defined WIN32 || defined _WIN32
558       _setmode(_fileno(stdin), _O_BINARY);
559 #endif
560       fin=stdin;
561    }
562    else 
563    {
564       fin = fopen(inFile, "rb");
565       if (!fin)
566       {
567          perror(inFile);
568          exit(1);
569       }
570       close_in=1;
571    }
572
573
574    /*Init Ogg data struct*/
575    ogg_sync_init(&oy);
576    
577    speex_bits_init(&bits);
578    /*Main decoding loop*/
579    while (1)
580    {
581       char *data;
582       int i, j, nb_read;
583       /*Get the ogg buffer for writing*/
584       data = ogg_sync_buffer(&oy, 200);
585       /*Read bitstream from input file*/
586       nb_read = fread(data, sizeof(char), 200, fin);      
587       ogg_sync_wrote(&oy, nb_read);
588
589       /*Loop for all complete pages we got (most likely only one)*/
590       while (ogg_sync_pageout(&oy, &og)==1)
591       {
592          int packet_no;
593          if (stream_init == 0) {
594             ogg_stream_init(&os, ogg_page_serialno(&og));
595             stream_init = 1;
596          }
597          /*Add page to the bitstream*/
598          ogg_stream_pagein(&os, &og);
599          page_granule = ogg_page_granulepos(&og);
600          page_nb_packets = ogg_page_packets(&og);
601          if (page_granule>0 && frame_size)
602          {
603             /* FIXME: shift the granule values if --force-* is specified */
604             skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule);
605             if (ogg_page_eos(&og))
606                skip_samples = -skip_samples;
607             /*else if (!ogg_page_bos(&og))
608                skip_samples = 0;*/
609          } else
610          {
611             skip_samples = 0;
612          }
613          /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
614          last_granule = page_granule;
615          /*Extract all available packets*/
616          packet_no=0;
617          while (!eos && ogg_stream_packetout(&os, &op)==1)
618          {
619             /*If first packet, process as Speex header*/
620             if (packet_count==0)
621             {
622                st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet);
623                speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
624                if (!nframes)
625                   nframes=1;
626                if (!st)
627                   exit(1);
628                fout = out_file_open(outFile, rate, &channels);
629
630             } else if (packet_count==1)
631             {
632                if (!quiet)
633                   print_comments((char*)op.packet, op.bytes);
634             } else if (packet_count<=1+extra_headers)
635             {
636                /* Ignore extra headers */
637             } else {
638                int lost=0;
639                packet_no++;
640                if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
641                   lost=1;
642
643                /*End of stream condition*/
644                if (op.e_o_s)
645                   eos=1;
646
647                /*Copy Ogg packet to Speex bitstream*/
648                speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
649                for (j=0;j!=nframes;j++)
650                {
651                   int ret;
652                   /*Decode frame*/
653                   if (!lost)
654                      ret = speex_decode_int(st, &bits, output);
655                   else
656                      ret = speex_decode_int(st, NULL, output);
657
658                   /*for (i=0;i<frame_size*channels;i++)
659                     printf ("%d\n", (int)output[i]);*/
660
661                   if (ret==-1)
662                      break;
663                   if (ret==-2)
664                   {
665                      fprintf (stderr, "Decoding error: corrupted stream?\n");
666                      break;
667                   }
668                   if (speex_bits_remaining(&bits)<0)
669                   {
670                      fprintf (stderr, "Decoding overflow: corrupted stream?\n");
671                      break;
672                   }
673                   if (channels==2)
674                      speex_decode_stereo_int(output, frame_size, &stereo);
675
676                   if (print_bitrate) {
677                      int tmp;
678                      char ch=13;
679                      speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
680                      fputc (ch, stderr);
681                      fprintf (stderr, "Bitrate is use: %d bps     ", tmp);
682                   }
683                   /*Convert to short and save to output file*/
684                   if (strlen(outFile)!=0)
685                   {
686                      for (i=0;i<frame_size*channels;i++)
687                         out[i]=le_short(output[i]);
688                   } else {
689                      for (i=0;i<frame_size*channels;i++)
690                         out[i]=output[i];
691                   }
692                   {
693                      int frame_offset = 0;
694                      int new_frame_size = frame_size;
695                      /*printf ("packet %d %d\n", packet_no, skip_samples);*/
696                      /*fprintf (stderr, "packet %d %d %d\n", packet_no, skip_samples, lookahead);*/
697                      if (packet_no == 1 && j==0 && skip_samples > 0)
698                      {
699                         /*printf ("chopping first packet\n");*/
700                         new_frame_size -= skip_samples+lookahead;
701                         frame_offset = skip_samples+lookahead;
702                      }
703                      if (packet_no == page_nb_packets && skip_samples < 0)
704                      {
705                         int packet_length = nframes*frame_size+skip_samples+lookahead;
706                         new_frame_size = packet_length - j*frame_size;
707                         if (new_frame_size<0)
708                            new_frame_size = 0;
709                         if (new_frame_size>frame_size)
710                            new_frame_size = frame_size;
711                         /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/
712                      }
713                      if (new_frame_size>0)
714                      {  
715 #if defined WIN32 || defined _WIN32
716                         if (strlen(outFile)==0)
717                            WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
718                         else
719 #endif
720                            fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
721                   
722                         audio_size+=sizeof(short)*new_frame_size*channels;
723                      }
724                   }
725                }
726             }
727             packet_count++;
728          }
729       }
730       if (feof(fin))
731          break;
732
733    }
734
735    if (wav_format)
736    {
737       if (fseek(fout,4,SEEK_SET)==0)
738       {
739          int tmp;
740          tmp = le_int(audio_size+36);
741          fwrite(&tmp,4,1,fout);
742          if (fseek(fout,32,SEEK_CUR)==0)
743          {
744             tmp = le_int(audio_size);
745             fwrite(&tmp,4,1,fout);
746          } else
747          {
748             fprintf (stderr, "First seek worked, second didn't\n");
749          }
750       } else {
751          fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
752       }
753    }
754
755    if (st)
756       speex_decoder_destroy(st);
757    else 
758    {
759       fprintf (stderr, "This doesn't look like a Speex file\n");
760    }
761    speex_bits_destroy(&bits);
762    if (stream_init)
763       ogg_stream_clear(&os);
764    ogg_sync_clear(&oy);
765
766 #if defined WIN32 || defined _WIN32
767    if (strlen(outFile)==0)
768       WIN_Audio_close ();
769 #endif
770
771    if (close_in)
772       fclose(fin);
773    if (fout != NULL)
774       fclose(fout);   
775
776    return 0;
777 }