Think DTX now works for wideband too
[speexdsp.git] / src / speexdec.c
1 /* Copyright (C) 2002 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 #include <stdio.h>
33 #if !defined WIN32 && !defined _WIN32
34 #include <unistd.h>
35 #include <getopt.h>
36 #endif
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "speex.h"
41 #include "ogg/ogg.h"
42
43 #if defined WIN32 || defined _WIN32
44 #include <windows.h>
45 #include "getopt_win.h"
46 #include "wave_out.h"
47 /* We need the following two to set stdout to binary */
48 #include <io.h>
49 #include <fcntl.h>
50 #endif
51 #include <math.h>
52
53 #ifdef HAVE_SYS_SOUNDCARD_H
54 #include <sys/soundcard.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <sys/ioctl.h>
59 #endif
60
61 #include <string.h>
62 #include "wav_io.h"
63 #include "speex_header.h"
64 #include "speex_stereo.h"
65 #include "speex_callbacks.h"
66 #include "misc.h"
67
68 #define MAX_FRAME_SIZE 2000
69
70 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
71                            ((buf[base+2]<<16)&0xff0000)| \
72                            ((buf[base+1]<<8)&0xff00)| \
73                             (buf[base]&0xff))
74
75 static void print_comments(char *comments, int length)
76 {
77    char *c=comments;
78    int len, i, nb_fields;
79
80    len=readint(c, 0);
81    c+=4;
82    fwrite(c, 1, len, stderr);
83    c+=len;
84    fprintf (stderr, "\n");
85    nb_fields=readint(c, 0);
86    c+=4;
87    for (i=0;i<nb_fields;i++)
88    {
89       len=readint(c, 0);
90       c+=4;
91       fwrite(c, 1, len, stderr);
92       c+=len;
93       fprintf (stderr, "\n");
94    }
95 }
96
97 FILE *out_file_open(char *outFile, int rate, int *channels)
98 {
99    FILE *fout=NULL;
100    /*Open output file*/
101    if (strlen(outFile)==0)
102    {
103 #if defined HAVE_SYS_SOUNDCARD_H
104       int audio_fd, format, stereo;
105       audio_fd=open("/dev/dsp", O_WRONLY);
106       if (audio_fd<0)
107       {
108          perror("Cannot open /dev/dsp");
109          exit(1);         
110       }
111
112       format=AFMT_S16_LE;
113       if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
114       {
115          perror("SNDCTL_DSP_SETFMT");
116          close(audio_fd);
117          exit(1);
118       }
119
120       stereo=0;
121       if (*channels==2)
122          stereo=1;
123       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)
124       {
125          perror("SNDCTL_DSP_STEREO");
126          close(audio_fd);
127          exit(1);
128       }
129       if (stereo!=0)
130       {
131          if (*channels==1)
132             fprintf (stderr, "Cannot set mono mode, will decode in stereo\n");
133          *channels=2;
134       }
135
136       if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)
137       {
138          perror("SNDCTL_DSP_SPEED");
139          close(audio_fd);
140          exit(1);
141       }
142       fout = fdopen(audio_fd, "w");
143 #elif defined WIN32 || defined _WIN32
144       {
145          unsigned int speex_channels = *channels;
146          if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, speex_channels))
147          {
148             fprintf (stderr, "Can't access %s\n", "WAVE OUT");
149             exit(1);
150          }
151       }
152 #else
153       fprintf (stderr, "No soundcard support\n");
154       exit(1);
155 #endif
156    } else {
157       if (strcmp(outFile,"-")==0)
158       {
159 #if defined WIN32 || defined _WIN32
160          _setmode(_fileno(stdout), _O_BINARY);
161 #endif
162          fout=stdout;
163       }
164       else 
165       {
166 #if defined WIN32 || defined _WIN32
167          fout = fopen(outFile, "wb");
168 #else
169          fout = fopen(outFile, "w");
170 #endif
171          if (!fout)
172          {
173             perror(outFile);
174             exit(1);
175          }
176          if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0)
177             write_wav_header(fout, rate, *channels, 0, 0);
178       }
179    }
180    return fout;
181 }
182
183 void usage()
184 {
185    printf ("Usage: speexdec [options] input_file.spx [output_file]\n");
186    printf ("\n");
187    printf ("Decodes a Speex file and produce a WAV file or raw file\n");
188    printf ("\n");
189    printf ("input_file can be:\n");
190    printf ("  filename.spx         regular Speex file\n");
191    printf ("  -                    stdin\n");
192    printf ("\n");  
193    printf ("output_file can be:\n");
194    printf ("  filename.wav         Wav file\n");
195    printf ("  filename.*           Raw PCM file (any extension other that .wav)\n");
196    printf ("  -                    stdout\n");
197    printf ("  (nothing)            Will be played to soundcard\n");
198    printf ("\n");  
199    printf ("Options:\n");
200    printf (" --enh                 Enable perceptual enhancement\n");
201    printf (" --no-enh              Disable perceptual enhancement (default FOR NOW)\n");
202    printf (" --force-nb            Force decoding in narrowband\n");
203    printf (" --force-wb            Force decoding in wideband\n");
204    printf (" --force-uwb           Force decoding in ultra-wideband\n");
205    printf (" --mono                Force decoding in mono\n");
206    printf (" --stereo              Force decoding in stereo\n");
207    printf (" --rate n              Force decoding at sampling rate n Hz\n");
208    printf (" --packet-loss n       Simulate n %% random packet loss\n");
209    printf (" -V                    Verbose mode (show bit-rate)\n"); 
210    printf (" -h, --help            This help\n");
211    printf (" -v, --version         Version information\n");
212    printf (" --pf                  Deprecated, use --pf instead\n");
213    printf (" --no-pf               Deprecated, use --no-pf instead\n");
214    printf ("\n");
215    printf ("More information is available from the Speex site: http://www.speex.org\n");
216    printf ("\n");
217    printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n");
218 }
219
220 void version()
221 {
222    printf ("speexdec (Speex decoder) version " VERSION " (compiled " __DATE__ ")\n");
223    printf ("Copyright (C) 2002 Jean-Marc Valin\n");
224 }
225
226 void version_short()
227 {
228    printf ("speexdec version " VERSION "\n");
229    printf ("Copyright (C) 2002 Jean-Marc Valin\n");
230 }
231
232 static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo)
233 {
234    void *st;
235    SpeexMode *mode;
236    SpeexHeader *header;
237    int modeID;
238    SpeexCallback callback;
239       
240    header = speex_packet_to_header((char*)op->packet, op->bytes);
241    if (!header)
242    {
243       fprintf (stderr, "Cannot read header\n");
244       return NULL;
245    }
246    if (header->mode >= SPEEX_NB_MODES)
247    {
248       fprintf (stderr, "Mode number %d does not (any longer) exist in this version\n", 
249                header->mode);
250       return NULL;
251    }
252       
253    modeID = header->mode;
254    if (forceMode!=-1)
255       modeID = forceMode;
256    mode = speex_mode_list[modeID];
257    
258    if (mode->bitstream_version < header->mode_bitstream_version)
259    {
260       fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n");
261       return NULL;
262    }
263    if (mode->bitstream_version > header->mode_bitstream_version) 
264    {
265       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");
266       return NULL;
267    }
268    
269    st = speex_decoder_init(mode);
270    speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
271    speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
272
273    callback.callback_id = SPEEX_INBAND_STEREO;
274    callback.func = speex_std_stereo_request_handler;
275    callback.data = stereo;
276    speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
277    
278    if (!*rate)
279       *rate = header->rate;
280    /* Adjust rate if --force-* options are used */
281    if (forceMode!=-1)
282    {
283       if (header->mode < forceMode)
284          *rate <<= (forceMode - header->mode);
285       if (header->mode > forceMode)
286          *rate >>= (header->mode - forceMode);
287    }
288
289    speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
290
291    *nframes = header->frames_per_packet;
292
293    if (*channels==-1)
294       *channels = header->nb_channels;
295    
296    fprintf (stderr, "Decoding %d Hz audio using %s mode", 
297             *rate, mode->modeName);
298
299    if (header->vbr)
300       fprintf (stderr, " (VBR)\n");
301    else
302       fprintf(stderr, "\n");
303    /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n", 
304     *rate, mode->bitrate, mode->modeName);*/
305
306    free(header);
307    return st;
308 }
309
310 int main(int argc, char **argv)
311 {
312    int c;
313    int option_index = 0;
314    char *inFile, *outFile;
315    FILE *fin, *fout=NULL;
316    short out[MAX_FRAME_SIZE];
317    float output[MAX_FRAME_SIZE];
318    int frame_size=0;
319    void *st=NULL;
320    SpeexBits bits;
321    int packet_count=0;
322    int stream_init = 0;
323    struct option long_options[] =
324    {
325       {"help", no_argument, NULL, 0},
326       {"version", no_argument, NULL, 0},
327       {"version-short", no_argument, NULL, 0},
328       {"enh", no_argument, NULL, 0},
329       {"no-enh", no_argument, NULL, 0},
330       {"pf", no_argument, NULL, 0},
331       {"no-pf", no_argument, NULL, 0},
332       {"force-nb", no_argument, NULL, 0},
333       {"force-wb", no_argument, NULL, 0},
334       {"force-uwb", no_argument, NULL, 0},
335       {"rate", required_argument, NULL, 0},
336       {"mono", no_argument, NULL, 0},
337       {"stereo", no_argument, NULL, 0},
338       {"packet-loss", required_argument, NULL, 0},
339       {0, 0, 0, 0}
340    };
341    ogg_sync_state oy;
342    ogg_page       og;
343    ogg_packet     op;
344    ogg_stream_state os;
345    int enh_enabled;
346    int nframes=2;
347    int print_bitrate=0;
348    int close_in=0;
349    int eos=0;
350    int forceMode=-1;
351    int audio_size=0;
352    float loss_percent=-1;
353    SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
354    int channels=-1;
355    int rate=0;
356
357    enh_enabled = 0;
358
359    /*Process options*/
360    while(1)
361    {
362       c = getopt_long (argc, argv, "hvV",
363                        long_options, &option_index);
364       if (c==-1)
365          break;
366       
367       switch(c)
368       {
369       case 0:
370          if (strcmp(long_options[option_index].name,"help")==0)
371          {
372             usage();
373             exit(0);
374          } else if (strcmp(long_options[option_index].name,"version")==0)
375          {
376             version();
377             exit(0);
378          } else if (strcmp(long_options[option_index].name,"version-short")==0)
379          {
380             version_short();
381             exit(0);
382          } else if (strcmp(long_options[option_index].name,"enh")==0)
383          {
384             enh_enabled=1;
385          } else if (strcmp(long_options[option_index].name,"no-enh")==0)
386          {
387             enh_enabled=0;
388          } else if (strcmp(long_options[option_index].name,"pf")==0)
389          {
390             fprintf (stderr, "--pf is deprecated, use --enh instead\n");
391             enh_enabled=1;
392          } else if (strcmp(long_options[option_index].name,"no-pf")==0)
393          {
394             fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n");
395             enh_enabled=0;
396          } else if (strcmp(long_options[option_index].name,"force-nb")==0)
397          {
398             forceMode=0;
399          } else if (strcmp(long_options[option_index].name,"force-wb")==0)
400          {
401             forceMode=1;
402          } else if (strcmp(long_options[option_index].name,"force-uwb")==0)
403          {
404             forceMode=2;
405          } else if (strcmp(long_options[option_index].name,"mono")==0)
406          {
407             channels=1;
408          } else if (strcmp(long_options[option_index].name,"stereo")==0)
409          {
410             channels=2;
411          } else if (strcmp(long_options[option_index].name,"rate")==0)
412          {
413             rate=atoi (optarg);
414          } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
415          {
416             loss_percent = atof(optarg);
417          }
418          break;
419       case 'h':
420          usage();
421          exit(0);
422          break;
423       case 'v':
424          version();
425          exit(0);
426          break;
427       case 'V':
428          print_bitrate=1;
429          break;
430       case '?':
431          usage();
432          exit(1);
433          break;
434       }
435    }
436    if (argc-optind!=2 && argc-optind!=1)
437    {
438       usage();
439       exit(1);
440    }
441    inFile=argv[optind];
442
443    if (argc-optind==2)
444       outFile=argv[optind+1];
445    else
446       outFile = "";
447    /*Open input file*/
448    if (strcmp(inFile, "-")==0)
449    {
450 #if defined WIN32 || defined _WIN32
451       _setmode(_fileno(stdin), _O_BINARY);
452 #endif
453       fin=stdin;
454    }
455    else 
456    {
457 #if defined WIN32 || defined _WIN32
458       fin = fopen(inFile, "rb");
459 #else
460       fin = fopen(inFile, "r");
461 #endif
462       if (!fin)
463       {
464          perror(inFile);
465          exit(1);
466       }
467       close_in=1;
468    }
469
470
471    /*Init Ogg data struct*/
472    ogg_sync_init(&oy);
473    
474    speex_bits_init(&bits);
475    /*Main decoding loop*/
476    while (1)
477    {
478       char *data;
479       int i, j, nb_read;
480       /*Get the ogg buffer for writing*/
481       data = ogg_sync_buffer(&oy, 200);
482       /*Read bitstream from input file*/
483       nb_read = fread(data, sizeof(char), 200, fin);      
484       ogg_sync_wrote(&oy, nb_read);
485
486       /*Loop for all complete pages we got (most likely only one)*/
487       while (ogg_sync_pageout(&oy, &og)==1)
488       {
489          if (stream_init == 0) {
490             ogg_stream_init(&os, ogg_page_serialno(&og));
491             stream_init = 1;
492          }
493          /*Add page to the bitstream*/
494          ogg_stream_pagein(&os, &og);
495          /*Extract all available packets*/
496          while (!eos && ogg_stream_packetout(&os, &op)==1)
497          {
498             /*If first packet, process as Speex header*/
499             if (packet_count==0)
500             {
501                st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo);
502                if (!nframes)
503                   nframes=1;
504                if (!st)
505                   exit(1);
506                fout = out_file_open(outFile, rate, &channels);
507
508             } else if (packet_count==1){
509                print_comments((char*)op.packet, op.bytes);
510                /*
511                fprintf (stderr, "File comments: ");
512                fwrite(op.packet, 1, op.bytes, stderr);
513                fprintf (stderr, "\n");
514                */
515             } else {
516                
517                int lost=0;
518                if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
519                   lost=1;
520
521                /*End of stream condition*/
522                if (op.e_o_s)
523                   eos=1;
524
525                /*Copy Ogg packet to Speex bitstream*/
526                speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
527                for (j=0;j<nframes;j++)
528                {
529                   /*Decode frame*/
530                   if (!lost)
531                      speex_decode(st, &bits, output);
532                   else
533                      speex_decode(st, NULL, output);
534
535                   if (channels==2)
536                      speex_decode_stereo(output, frame_size, &stereo);
537
538                   if (print_bitrate) {
539                      int tmp;
540                      char ch=13;
541                      speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
542                      fputc (ch, stderr);
543                      fprintf (stderr, "Bitrate is use: %d bps     ", tmp);
544                   }
545                   /*PCM saturation (just in case)*/
546                   for (i=0;i<frame_size*channels;i++)
547                   {
548                      if (output[i]>32000.0)
549                         output[i]=32000.0;
550                      else if (output[i]<-32000.0)
551                         output[i]=-32000.0;
552                   }
553                   /*Convert to short and save to output file*/
554                   for (i=0;i<frame_size*channels;i++)
555                      out[i]=(short)le_short((short)floor(.5+output[i]));
556 #if defined WIN32 || defined _WIN32
557                   if (strlen(outFile)==0)
558                       WIN_Play_Samples (out, sizeof(short) * frame_size*channels);
559                   else
560 #endif
561                   fwrite(out, sizeof(short), frame_size*channels, fout);
562                   
563                   audio_size+=sizeof(short)*frame_size*channels;
564                }
565             }
566             packet_count++;
567          }
568       }
569       if (feof(fin))
570          break;
571
572    }
573
574    if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(inFile+strlen(inFile)-4,".WAV")==0)
575    {
576       if (fseek(fout,4,SEEK_SET)==0)
577       {
578          int tmp;
579          tmp = le_int(audio_size+36);
580          fwrite(&tmp,4,1,fout);
581          if (fseek(fout,32,SEEK_CUR)==0)
582          {
583             tmp = le_int(audio_size);
584             fwrite(&tmp,4,1,fout);
585          } else
586          {
587             fprintf (stderr, "First seek worked, second didn't\n");
588          }
589       } else {
590          fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
591       }
592    }
593
594    if (st)
595       speex_decoder_destroy(st);
596    speex_bits_destroy(&bits);
597    ogg_sync_clear(&oy);
598    ogg_stream_clear(&os);
599
600 #if defined WIN32 || defined _WIN32
601    if (strlen(outFile)==0)
602       WIN_Audio_close ();
603 #endif
604
605    if (close_in)
606       fclose(fin);
607    if (fout != NULL)
608       fclose(fout);   
609
610    return 0;
611 }