remove DISABLE_GLOBAL_POINTERS stuff from speexdec,
[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
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
457    enh_enabled = 1;
458
459    /*Process options*/
460    while(1)
461    {
462       c = getopt_long (argc, argv, "hvV",
463                        long_options, &option_index);
464       if (c==-1)
465          break;
466       
467       switch(c)
468       {
469       case 0:
470          if (strcmp(long_options[option_index].name,"help")==0)
471          {
472             usage();
473             exit(0);
474          } else if (strcmp(long_options[option_index].name,"quiet")==0)
475          {
476             quiet = 1;
477          } else if (strcmp(long_options[option_index].name,"version")==0)
478          {
479             version();
480             exit(0);
481          } else if (strcmp(long_options[option_index].name,"version-short")==0)
482          {
483             version_short();
484             exit(0);
485          } else if (strcmp(long_options[option_index].name,"enh")==0)
486          {
487             enh_enabled=1;
488          } else if (strcmp(long_options[option_index].name,"no-enh")==0)
489          {
490             enh_enabled=0;
491          } else if (strcmp(long_options[option_index].name,"pf")==0)
492          {
493             fprintf (stderr, "--pf is deprecated, use --enh instead\n");
494             enh_enabled=1;
495          } else if (strcmp(long_options[option_index].name,"no-pf")==0)
496          {
497             fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n");
498             enh_enabled=0;
499          } else if (strcmp(long_options[option_index].name,"force-nb")==0)
500          {
501             forceMode=0;
502          } else if (strcmp(long_options[option_index].name,"force-wb")==0)
503          {
504             forceMode=1;
505          } else if (strcmp(long_options[option_index].name,"force-uwb")==0)
506          {
507             forceMode=2;
508          } else if (strcmp(long_options[option_index].name,"mono")==0)
509          {
510             channels=1;
511          } else if (strcmp(long_options[option_index].name,"stereo")==0)
512          {
513             channels=2;
514          } else if (strcmp(long_options[option_index].name,"rate")==0)
515          {
516             rate=atoi (optarg);
517          } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
518          {
519             loss_percent = atof(optarg);
520          }
521          break;
522       case 'h':
523          usage();
524          exit(0);
525          break;
526       case 'v':
527          version();
528          exit(0);
529          break;
530       case 'V':
531          print_bitrate=1;
532          break;
533       case '?':
534          usage();
535          exit(1);
536          break;
537       }
538    }
539    if (argc-optind!=2 && argc-optind!=1)
540    {
541       usage();
542       exit(1);
543    }
544    inFile=argv[optind];
545
546    if (argc-optind==2)
547       outFile=argv[optind+1];
548    else
549       outFile = "";
550    wav_format = strlen(outFile)>=4 && (
551                                        strcmp(outFile+strlen(outFile)-4,".wav")==0
552                                        || strcmp(inFile+strlen(inFile)-4,".WAV")==0);
553    /*Open input file*/
554    if (strcmp(inFile, "-")==0)
555    {
556 #if defined WIN32 || defined _WIN32
557       _setmode(_fileno(stdin), _O_BINARY);
558 #endif
559       fin=stdin;
560    }
561    else 
562    {
563       fin = fopen(inFile, "rb");
564       if (!fin)
565       {
566          perror(inFile);
567          exit(1);
568       }
569       close_in=1;
570    }
571
572
573    /*Init Ogg data struct*/
574    ogg_sync_init(&oy);
575    
576    speex_bits_init(&bits);
577    /*Main decoding loop*/
578    while (1)
579    {
580       char *data;
581       int i, j, nb_read;
582       /*Get the ogg buffer for writing*/
583       data = ogg_sync_buffer(&oy, 200);
584       /*Read bitstream from input file*/
585       nb_read = fread(data, sizeof(char), 200, fin);      
586       ogg_sync_wrote(&oy, nb_read);
587
588       /*Loop for all complete pages we got (most likely only one)*/
589       while (ogg_sync_pageout(&oy, &og)==1)
590       {
591          int packet_no;
592          if (stream_init == 0) {
593             ogg_stream_init(&os, ogg_page_serialno(&og));
594             stream_init = 1;
595          }
596          /*Add page to the bitstream*/
597          ogg_stream_pagein(&os, &og);
598          page_granule = ogg_page_granulepos(&og);
599          page_nb_packets = ogg_page_packets(&og);
600          if (page_granule>0 && frame_size)
601          {
602             skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule);
603             if (ogg_page_eos(&og))
604                skip_samples = -skip_samples;
605             /*else if (!ogg_page_bos(&og))
606                skip_samples = 0;*/
607          } else
608          {
609             skip_samples = 0;
610          }
611          /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
612          last_granule = page_granule;
613          /*Extract all available packets*/
614          packet_no=0;
615          while (!eos && ogg_stream_packetout(&os, &op)==1)
616          {
617             /*If first packet, process as Speex header*/
618             if (packet_count==0)
619             {
620                st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet);
621                if (!nframes)
622                   nframes=1;
623                if (!st)
624                   exit(1);
625                fout = out_file_open(outFile, rate, &channels);
626
627             } else if (packet_count==1)
628             {
629                if (!quiet)
630                   print_comments((char*)op.packet, op.bytes);
631             } else if (packet_count<=1+extra_headers)
632             {
633                /* Ignore extra headers */
634             } else {
635                int lost=0;
636                packet_no++;
637                if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
638                   lost=1;
639
640                /*End of stream condition*/
641                if (op.e_o_s)
642                   eos=1;
643
644                /*Copy Ogg packet to Speex bitstream*/
645                speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
646                for (j=0;j!=nframes;j++)
647                {
648                   int ret;
649                   /*Decode frame*/
650                   if (!lost)
651                      ret = speex_decode_int(st, &bits, output);
652                   else
653                      ret = speex_decode_int(st, NULL, output);
654
655                   /*for (i=0;i<frame_size*channels;i++)
656                     printf ("%d\n", (int)output[i]);*/
657
658                   if (ret==-1)
659                      break;
660                   if (ret==-2)
661                   {
662                      fprintf (stderr, "Decoding error: corrupted stream?\n");
663                      break;
664                   }
665                   if (speex_bits_remaining(&bits)<0)
666                   {
667                      fprintf (stderr, "Decoding overflow: corrupted stream?\n");
668                      break;
669                   }
670                   if (channels==2)
671                      speex_decode_stereo_int(output, frame_size, &stereo);
672
673                   if (print_bitrate) {
674                      int tmp;
675                      char ch=13;
676                      speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
677                      fputc (ch, stderr);
678                      fprintf (stderr, "Bitrate is use: %d bps     ", tmp);
679                   }
680                   /*Convert to short and save to output file*/
681                   if (strlen(outFile)!=0)
682                   {
683                      for (i=0;i<frame_size*channels;i++)
684                         out[i]=le_short(output[i]);
685                   } else {
686                      for (i=0;i<frame_size*channels;i++)
687                         out[i]=output[i];
688                   }
689                   {
690                      int frame_offset = 0;
691                      int new_frame_size = frame_size;
692                      /*printf ("packet %d %d\n", packet_no, skip_samples);*/
693                      if (packet_no == 1 && j==0 && skip_samples > 0)
694                      {
695                         /*printf ("chopping first packet\n");*/
696                         new_frame_size -= skip_samples;
697                         frame_offset = skip_samples;
698                      }
699                      if (packet_no == page_nb_packets && skip_samples < 0)
700                      {
701                         int packet_length = nframes*frame_size+skip_samples;
702                         new_frame_size = packet_length - j*frame_size;
703                         if (new_frame_size<0)
704                            new_frame_size = 0;
705                         if (new_frame_size>frame_size)
706                            new_frame_size = frame_size;
707                         /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/
708                      }
709                      if (new_frame_size)
710                      {  
711 #if defined WIN32 || defined _WIN32
712                         if (strlen(outFile)==0)
713                            WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
714                         else
715 #endif
716                            fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
717                   
718                         audio_size+=sizeof(short)*new_frame_size*channels;
719                      }
720                   }
721                }
722             }
723             packet_count++;
724          }
725       }
726       if (feof(fin))
727          break;
728
729    }
730
731    if (wav_format)
732    {
733       if (fseek(fout,4,SEEK_SET)==0)
734       {
735          int tmp;
736          tmp = le_int(audio_size+36);
737          fwrite(&tmp,4,1,fout);
738          if (fseek(fout,32,SEEK_CUR)==0)
739          {
740             tmp = le_int(audio_size);
741             fwrite(&tmp,4,1,fout);
742          } else
743          {
744             fprintf (stderr, "First seek worked, second didn't\n");
745          }
746       } else {
747          fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
748       }
749    }
750
751    if (st)
752       speex_decoder_destroy(st);
753    else 
754    {
755       fprintf (stderr, "This doesn't look like a Speex file\n");
756    }
757    speex_bits_destroy(&bits);
758    if (stream_init)
759       ogg_stream_clear(&os);
760    ogg_sync_clear(&oy);
761
762 #if defined WIN32 || defined _WIN32
763    if (strlen(outFile)==0)
764       WIN_Audio_close ();
765 #endif
766
767    if (close_in)
768       fclose(fin);
769    if (fout != NULL)
770       fclose(fout);   
771
772    return 0;
773 }