1
/* Copyright (C) 2002-2003 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
41
#ifndef HAVE_GETOPT_LONG
42
#include "getopt_win.h"
47
#include <speex/speex.h>
50
#if defined WIN32 || defined _WIN32
52
#include "getopt_win.h"
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>
89
#ifdef DISABLE_GLOBAL_POINTERS
90
#include <speex/speex_noglobals.h>
93
#define MAX_FRAME_SIZE 2000
95
#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
96
((buf[base+2]<<16)&0xff0000)| \
97
((buf[base+1]<<8)&0xff00)| \
100
static void print_comments(char *comments, int length)
103
int len, i, nb_fields;
108
fprintf (stderr, "Invalid/corrupted comments\n");
116
fprintf (stderr, "Invalid/corrupted comments\n");
119
fwrite(c, 1, len, stderr);
121
fprintf (stderr, "\n");
124
fprintf (stderr, "Invalid/corrupted comments\n");
127
nb_fields=readint(c, 0);
129
for (i=0;i<nb_fields;i++)
133
fprintf (stderr, "Invalid/corrupted comments\n");
140
fprintf (stderr, "Invalid/corrupted comments\n");
143
fwrite(c, 1, len, stderr);
145
fprintf (stderr, "\n");
149
FILE *out_file_open(char *outFile, int rate, int *channels)
153
if (strlen(outFile)==0)
155
#if defined HAVE_SYS_SOUNDCARD_H
156
int audio_fd, format, stereo;
157
audio_fd=open("/dev/dsp", O_WRONLY);
160
perror("Cannot open /dev/dsp");
165
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
167
perror("SNDCTL_DSP_SETFMT");
175
if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)
177
perror("SNDCTL_DSP_STEREO");
184
fprintf (stderr, "Cannot set mono mode, will decode in stereo\n");
188
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)
190
perror("SNDCTL_DSP_SPEED");
194
fout = fdopen(audio_fd, "w");
195
#elif defined HAVE_SYS_AUDIOIO_H
199
audio_fd = open("/dev/audio", O_WRONLY);
202
perror("Cannot open /dev/audio");
206
AUDIO_INITINFO(&info);
207
#ifdef AUMODE_PLAY /* NetBSD/OpenBSD */
208
info.mode = AUMODE_PLAY;
210
info.play.encoding = AUDIO_ENCODING_SLINEAR;
211
info.play.precision = 16;
212
info.play.sample_rate = rate;
213
info.play.channels = *channels;
215
if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0)
217
perror ("AUDIO_SETINFO");
220
fout = fdopen(audio_fd, "w");
221
#elif defined WIN32 || defined _WIN32
223
unsigned int speex_channels = *channels;
224
if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, speex_channels))
226
fprintf (stderr, "Can't access %s\n", "WAVE OUT");
231
fprintf (stderr, "No soundcard support\n");
235
if (strcmp(outFile,"-")==0)
237
#if defined WIN32 || defined _WIN32
238
_setmode(_fileno(stdout), _O_BINARY);
244
fout = fopen(outFile, "wb");
250
if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0)
251
write_wav_header(fout, rate, *channels, 0, 0);
259
printf ("Usage: speexdec [options] input_file.spx [output_file]\n");
261
printf ("Decodes a Speex file and produce a WAV file or raw file\n");
263
printf ("input_file can be:\n");
264
printf (" filename.spx regular Speex file\n");
265
printf (" - stdin\n");
267
printf ("output_file can be:\n");
268
printf (" filename.wav Wav file\n");
269
printf (" filename.* Raw PCM file (any extension other that .wav)\n");
270
printf (" - stdout\n");
271
printf (" (nothing) Will be played to soundcard\n");
273
printf ("Options:\n");
274
printf (" --enh Enable perceptual enhancement (default)\n");
275
printf (" --no-enh Disable perceptual enhancement\n");
276
printf (" --force-nb Force decoding in narrowband\n");
277
printf (" --force-wb Force decoding in wideband\n");
278
printf (" --force-uwb Force decoding in ultra-wideband\n");
279
printf (" --mono Force decoding in mono\n");
280
printf (" --stereo Force decoding in stereo\n");
281
printf (" --rate n Force decoding at sampling rate n Hz\n");
282
printf (" --packet-loss n Simulate n %% random packet loss\n");
283
printf (" -V Verbose mode (show bit-rate)\n");
284
printf (" -h, --help This help\n");
285
printf (" -v, --version Version information\n");
286
printf (" --pf Deprecated, use --enh instead\n");
287
printf (" --no-pf Deprecated, use --no-enh instead\n");
289
printf ("More information is available from the Speex site: http://www.speex.org\n");
291
printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n");
296
printf ("speexdec (Speex decoder) version " SPEEX_VERSION " (compiled " __DATE__ ")\n");
297
printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
302
printf ("speexdec version " SPEEX_VERSION "\n");
303
printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
306
static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet)
309
const SpeexMode *mode;
312
SpeexCallback callback;
314
header = speex_packet_to_header((char*)op->packet, op->bytes);
317
fprintf (stderr, "Cannot read header\n");
320
if (header->mode >= SPEEX_NB_MODES)
322
fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n",
327
modeID = header->mode;
331
#ifdef DISABLE_GLOBAL_POINTERS
332
mode = speex_mode_new (modeID);
334
mode = speex_mode_list[modeID];
337
if (header->speex_version_id > 1)
339
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);
343
if (mode->bitstream_version < header->mode_bitstream_version)
345
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");
354
st = speex_decoder_init(mode);
357
fprintf (stderr, "Decoder initialization failed.\n");
360
speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
361
speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
365
callback.callback_id = SPEEX_INBAND_STEREO;
366
callback.func = speex_std_stereo_request_handler;
367
callback.data = stereo;
368
speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
371
*rate = header->rate;
372
/* Adjust rate if --force-* options are used */
375
if (header->mode < forceMode)
376
*rate <<= (forceMode - header->mode);
377
if (header->mode > forceMode)
378
*rate >>= (header->mode - forceMode);
381
speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
383
*nframes = header->frames_per_packet;
386
*channels = header->nb_channels;
390
fprintf (stderr, "Decoding %d Hz audio using %s mode",
391
*rate, mode->modeName);
394
fprintf (stderr, " (mono");
396
fprintf (stderr, " (stereo");
399
fprintf (stderr, ", VBR)\n");
401
fprintf(stderr, ")\n");
402
/*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n",
403
*rate, mode->bitrate, mode->modeName);*/
406
*extra_headers = header->extra_headers;
412
int main(int argc, char **argv)
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];
426
ogg_int64_t page_granule=0, last_granule=0;
427
int skip_samples=0, page_nb_packets;
428
struct option long_options[] =
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},
458
float loss_percent=-1;
459
SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
470
c = getopt_long (argc, argv, "hvV",
471
long_options, &option_index);
478
if (strcmp(long_options[option_index].name,"help")==0)
482
} else if (strcmp(long_options[option_index].name,"quiet")==0)
485
} else if (strcmp(long_options[option_index].name,"version")==0)
489
} else if (strcmp(long_options[option_index].name,"version-short")==0)
493
} else if (strcmp(long_options[option_index].name,"enh")==0)
496
} else if (strcmp(long_options[option_index].name,"no-enh")==0)
499
} else if (strcmp(long_options[option_index].name,"pf")==0)
501
fprintf (stderr, "--pf is deprecated, use --enh instead\n");
503
} else if (strcmp(long_options[option_index].name,"no-pf")==0)
505
fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n");
507
} else if (strcmp(long_options[option_index].name,"force-nb")==0)
510
} else if (strcmp(long_options[option_index].name,"force-wb")==0)
513
} else if (strcmp(long_options[option_index].name,"force-uwb")==0)
516
} else if (strcmp(long_options[option_index].name,"mono")==0)
519
} else if (strcmp(long_options[option_index].name,"stereo")==0)
522
} else if (strcmp(long_options[option_index].name,"rate")==0)
525
} else if (strcmp(long_options[option_index].name,"packet-loss")==0)
527
loss_percent = atof(optarg);
547
if (argc-optind!=2 && argc-optind!=1)
555
outFile=argv[optind+1];
558
wav_format = strlen(outFile)>=4 && (
559
strcmp(outFile+strlen(outFile)-4,".wav")==0
560
|| strcmp(inFile+strlen(inFile)-4,".WAV")==0);
562
if (strcmp(inFile, "-")==0)
564
#if defined WIN32 || defined _WIN32
565
_setmode(_fileno(stdin), _O_BINARY);
571
fin = fopen(inFile, "rb");
581
/*Init Ogg data struct*/
584
speex_bits_init(&bits);
585
/*Main decoding loop*/
590
/*Get the ogg buffer for writing*/
591
data = ogg_sync_buffer(&oy, 200);
592
/*Read bitstream from input file*/
593
nb_read = fread(data, sizeof(char), 200, fin);
594
ogg_sync_wrote(&oy, nb_read);
596
/*Loop for all complete pages we got (most likely only one)*/
597
while (ogg_sync_pageout(&oy, &og)==1)
600
if (stream_init == 0) {
601
ogg_stream_init(&os, ogg_page_serialno(&og));
604
/*Add page to the bitstream*/
605
ogg_stream_pagein(&os, &og);
606
page_granule = ogg_page_granulepos(&og);
607
page_nb_packets = ogg_page_packets(&og);
608
if (page_granule>0 && frame_size)
610
skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule);
611
if (ogg_page_eos(&og))
612
skip_samples = -skip_samples;
613
/*else if (!ogg_page_bos(&og))
619
/*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
620
last_granule = page_granule;
621
/*Extract all available packets*/
623
while (!eos && ogg_stream_packetout(&os, &op)==1)
625
/*If first packet, process as Speex header*/
628
st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet);
633
fout = out_file_open(outFile, rate, &channels);
635
} else if (packet_count==1)
638
print_comments((char*)op.packet, op.bytes);
639
} else if (packet_count<=1+extra_headers)
641
/* Ignore extra headers */
645
if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
648
/*End of stream condition*/
652
/*Copy Ogg packet to Speex bitstream*/
653
speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
654
for (j=0;j!=nframes;j++)
659
ret = speex_decode_int(st, &bits, output);
661
ret = speex_decode_int(st, NULL, output);
663
/*for (i=0;i<frame_size*channels;i++)
664
printf ("%d\n", (int)output[i]);*/
670
fprintf (stderr, "Decoding error: corrupted stream?\n");
673
if (speex_bits_remaining(&bits)<0)
675
fprintf (stderr, "Decoding overflow: corrupted stream?\n");
679
speex_decode_stereo_int(output, frame_size, &stereo);
684
speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
686
fprintf (stderr, "Bitrate is use: %d bps ", tmp);
688
/*Convert to short and save to output file*/
689
if (strlen(outFile)!=0)
691
for (i=0;i<frame_size*channels;i++)
692
out[i]=le_short(output[i]);
694
for (i=0;i<frame_size*channels;i++)
698
int frame_offset = 0;
699
int new_frame_size = frame_size;
700
/*printf ("packet %d %d\n", packet_no, skip_samples);*/
701
if (packet_no == 1 && j==0 && skip_samples > 0)
703
/*printf ("chopping first packet\n");*/
704
new_frame_size -= skip_samples;
705
frame_offset = skip_samples;
707
if (packet_no == page_nb_packets && skip_samples < 0)
709
int packet_length = nframes*frame_size+skip_samples;
710
new_frame_size = packet_length - j*frame_size;
711
if (new_frame_size<0)
713
if (new_frame_size>frame_size)
714
new_frame_size = frame_size;
715
/*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/
719
#if defined WIN32 || defined _WIN32
720
if (strlen(outFile)==0)
721
WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
724
fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
726
audio_size+=sizeof(short)*new_frame_size*channels;
741
if (fseek(fout,4,SEEK_SET)==0)
744
tmp = le_int(audio_size+36);
745
fwrite(&tmp,4,1,fout);
746
if (fseek(fout,32,SEEK_CUR)==0)
748
tmp = le_int(audio_size);
749
fwrite(&tmp,4,1,fout);
752
fprintf (stderr, "First seek worked, second didn't\n");
755
fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
760
speex_decoder_destroy(st);
763
fprintf (stderr, "This doesn't look like a Speex file\n");
765
speex_bits_destroy(&bits);
767
ogg_stream_clear(&os);
770
#if defined WIN32 || defined _WIN32
771
if (strlen(outFile)==0)