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