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