1 /* Copyright (C) 2002-2006 Jean-Marc Valin
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
8 - Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
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.
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.
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.
37 #if !defined WIN32 && !defined _WIN32
43 #ifndef HAVE_GETOPT_LONG
44 #include "getopt_win.h"
49 #include <ext/speex/speex.h>
50 #include <ext/libogg/ogg.h>
52 #if defined WIN32 || defined _WIN32
54 /* We need the following two to set stdout to binary */
64 #ifdef HAVE_SYS_SOUNDCARD_H
65 #include <sys/soundcard.h>
66 #include <sys/types.h>
69 #include <sys/ioctl.h>
71 #elif defined HAVE_SYS_AUDIOIO_H
72 #include <sys/types.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 */
84 #include <speex/speex_header.h>
85 #include <speex/speex_stereo.h>
86 #include <speex/speex_callbacks.h>
88 #define MAX_FRAME_SIZE 2000
90 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
91 ((buf[base+2]<<16)&0xff0000)| \
92 ((buf[base+1]<<8)&0xff00)| \
95 static void print_comments(char *comments, int length)
98 int len, i, nb_fields;
103 fprintf (stderr, "Invalid/corrupted comments\n");
109 if (len < 0 || c+len>end)
111 fprintf (stderr, "Invalid/corrupted comments\n");
114 fwrite(c, 1, len, stderr);
116 fprintf (stderr, "\n");
119 fprintf (stderr, "Invalid/corrupted comments\n");
122 nb_fields=readint(c, 0);
124 for (i=0;i<nb_fields;i++)
128 fprintf (stderr, "Invalid/corrupted comments\n");
133 if (len < 0 || c+len>end)
135 fprintf (stderr, "Invalid/corrupted comments\n");
138 fwrite(c, 1, len, stderr);
140 fprintf (stderr, "\n");
144 FILE *out_file_open(char *outFile, int rate, int *channels)
148 if (strlen(outFile)==0)
150 #if defined HAVE_SYS_SOUNDCARD_H
151 int audio_fd, format, stereo;
152 audio_fd=open("/dev/dsp", O_WRONLY);
155 perror("Cannot open /dev/dsp");
160 if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
162 perror("SNDCTL_DSP_SETFMT");
170 if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)
172 perror("SNDCTL_DSP_STEREO");
179 fprintf (stderr, "Cannot set mono mode, will decode in stereo\n");
183 if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)
185 perror("SNDCTL_DSP_SPEED");
189 fout = fdopen(audio_fd, "w");
190 #elif defined HAVE_SYS_AUDIOIO_H
194 audio_fd = open("/dev/audio", O_WRONLY);
197 perror("Cannot open /dev/audio");
201 AUDIO_INITINFO(&info);
202 #ifdef AUMODE_PLAY /* NetBSD/OpenBSD */
203 info.mode = AUMODE_PLAY;
205 info.play.encoding = AUDIO_ENCODING_SLINEAR;
206 info.play.precision = 16;
207 info.play.sample_rate = rate;
208 info.play.channels = *channels;
210 if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0)
212 perror ("AUDIO_SETINFO");
215 fout = fdopen(audio_fd, "w");
216 #elif defined WIN32 || defined _WIN32
218 unsigned int speex_channels = *channels;
219 if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, speex_channels))
221 fprintf (stderr, "Can't access %s\n", "WAVE OUT");
226 fprintf (stderr, "No soundcard support\n");
230 if (strcmp(outFile,"-")==0)
232 #if defined WIN32 || defined _WIN32
233 _setmode(_fileno(stdout), _O_BINARY);
235 _fsetmode(stdout,"b");
241 fout = fopen(outFile, "wb");
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);
256 printf ("Usage: speexdec [options] input_file.spx [output_file]\n");
258 printf ("Decodes a Speex file and produce a WAV file or raw file\n");
260 printf ("input_file can be:\n");
261 printf (" filename.spx regular Speex file\n");
262 printf (" - stdin\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");
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");
286 printf ("More information is available from the Speex site: http://www.speex.org\n");
288 printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n");
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");
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");
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)
310 const SpeexMode *mode;
313 SpeexCallback callback;
315 header = speex_packet_to_header((char*)op->packet, op->bytes);
318 fprintf (stderr, "Cannot read header\n");
321 if (header->mode >= SPEEX_NB_MODES || header->mode<0)
323 fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n",
329 modeID = header->mode;
333 mode = speex_lib_get_mode (modeID);
335 if (header->speex_version_id > 1)
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);
342 if (mode->bitstream_version < header->mode_bitstream_version)
344 fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n");
348 if (mode->bitstream_version > header->mode_bitstream_version)
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");
355 st = speex_decoder_init(mode);
358 fprintf (stderr, "Decoder initialization failed.\n");
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;
367 *rate = header->rate;
368 /* Adjust rate if --force-* options are used */
371 if (header->mode < forceMode)
373 *rate <<= (forceMode - header->mode);
374 *granule_frame_size >>= (forceMode - header->mode);
376 if (header->mode > forceMode)
378 *rate >>= (header->mode - forceMode);
379 *granule_frame_size <<= (header->mode - forceMode);
384 speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
386 *nframes = header->frames_per_packet;
389 *channels = header->nb_channels;
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);
402 fprintf (stderr, "Decoding %d Hz audio using %s mode",
403 *rate, mode->modeName);
406 fprintf (stderr, " (mono");
408 fprintf (stderr, " (stereo");
411 fprintf (stderr, ", VBR)\n");
413 fprintf(stderr, ")\n");
414 /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n",
415 *rate, mode->bitrate, mode->modeName);*/
418 *extra_headers = header->extra_headers;
424 int main(int argc, char **argv)
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;
438 ogg_int64_t page_granule=0, last_granule=0;
439 int skip_samples=0, page_nb_packets;
440 struct option long_options[] =
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},
470 float loss_percent=-1;
471 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
477 int speex_serialno = -1;
484 c = getopt_long (argc, argv, "hvV",
485 long_options, &option_index);
492 if (strcmp(long_options[option_index].name,"help")==0)
496 } else if (strcmp(long_options[option_index].name,"quiet")==0)
499 } else if (strcmp(long_options[option_index].name,"version")==0)
503 } else if (strcmp(long_options[option_index].name,"version-short")==0)
507 } else if (strcmp(long_options[option_index].name,"enh")==0)
510 } else if (strcmp(long_options[option_index].name,"no-enh")==0)
513 } else if (strcmp(long_options[option_index].name,"pf")==0)
515 fprintf (stderr, "--pf is deprecated, use --enh instead\n");
517 } else if (strcmp(long_options[option_index].name,"no-pf")==0)
519 fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n");
521 } else if (strcmp(long_options[option_index].name,"force-nb")==0)
524 } else if (strcmp(long_options[option_index].name,"force-wb")==0)
527 } else if (strcmp(long_options[option_index].name,"force-uwb")==0)
530 } else if (strcmp(long_options[option_index].name,"mono")==0)
533 } else if (strcmp(long_options[option_index].name,"stereo")==0)
536 } else if (strcmp(long_options[option_index].name,"rate")==0)
539 } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
541 loss_percent = atof(optarg);
561 if (argc-optind!=2 && argc-optind!=1)
569 outFile=argv[optind+1];
572 wav_format = strlen(outFile)>=4 && (
573 strcmp(outFile+strlen(outFile)-4,".wav")==0
574 || strcmp(outFile+strlen(outFile)-4,".WAV")==0);
576 if (strcmp(inFile, "-")==0)
578 #if defined WIN32 || defined _WIN32
579 _setmode(_fileno(stdin), _O_BINARY);
585 fin = fopen(inFile, "rb");
595 /*Init Ogg data struct*/
598 speex_bits_init(&bits);
599 /*Main decoding loop*/
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);
611 /*Loop for all complete pages we got (most likely only one)*/
612 while (ogg_sync_pageout(&oy, &og)==1)
615 if (stream_init == 0) {
616 ogg_stream_init(&os, ogg_page_serialno(&og));
619 if (ogg_page_serialno(&og) != os.serialno) {
620 /* so all streams are read. */
621 ogg_stream_reset_serialno(&os, ogg_page_serialno(&og));
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)
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))
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*/
643 while (!eos && ogg_stream_packetout(&os, &op) == 1)
645 if (op.bytes>=5 && !memcmp(op.packet, "Speex", 5)) {
646 speex_serialno = os.serialno;
648 if (speex_serialno == -1 || os.serialno != speex_serialno)
650 /*If first packet, process as Speex header*/
653 st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet);
656 speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
659 fout = out_file_open(outFile, rate, &channels);
661 } else if (packet_count==1)
664 print_comments((char*)op.packet, op.bytes);
665 } else if (packet_count<=1+extra_headers)
667 /* Ignore extra headers */
671 if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
674 /*End of stream condition*/
675 if (op.e_o_s && os.serialno == speex_serialno) /* don't care for anything except speex eos */
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++)
685 ret = speex_decode_int(st, &bits, output);
687 ret = speex_decode_int(st, NULL, output);
689 /*for (i=0;i<frame_size*channels;i++)
690 printf ("%d\n", (int)output[i]);*/
696 fprintf (stderr, "Decoding error: corrupted stream?\n");
699 if (speex_bits_remaining(&bits)<0)
701 fprintf (stderr, "Decoding overflow: corrupted stream?\n");
705 speex_decode_stereo_int(output, frame_size, &stereo);
710 speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
712 fprintf (stderr, "Bitrate is use: %d bps ", tmp);
714 /*Convert to short and save to output file*/
715 if (strlen(outFile)!=0)
717 for (i=0;i<frame_size*channels;i++)
718 out[i]=le_short(output[i]);
720 for (i=0;i<frame_size*channels;i++)
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)
730 /*printf ("chopping first packet\n");*/
731 new_frame_size -= skip_samples+lookahead;
732 frame_offset = skip_samples+lookahead;
734 if (packet_no == page_nb_packets && skip_samples < 0)
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)
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);*/
744 if (new_frame_size>0)
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);
751 fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
753 audio_size+=sizeof(short)*new_frame_size*channels;
766 if (fout && wav_format)
768 if (fseek(fout,4,SEEK_SET)==0)
771 tmp = le_int(audio_size+36);
772 fwrite(&tmp,4,1,fout);
773 if (fseek(fout,32,SEEK_CUR)==0)
775 tmp = le_int(audio_size);
776 fwrite(&tmp,4,1,fout);
779 fprintf (stderr, "First seek worked, second didn't\n");
782 fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
787 speex_decoder_destroy(st);
790 fprintf (stderr, "This doesn't look like a Speex file\n");
792 speex_bits_destroy(&bits);
794 ogg_stream_clear(&os);
797 #if defined WIN32 || defined _WIN32
798 if (strlen(outFile)==0)