blob: 94a63c11667fd6054c6dcfc32c2d5ba921c28288 [file] [log] [blame]
Benny Prijonoef010c52007-03-30 10:49:46 +00001/* 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
96static 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
145FILE *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
253void 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
290void 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
296void version_short()
297{
298 printf ("speexdec version " SPEEX_VERSION "\n");
299 printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n");
300}
301
302static 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
412int 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}