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