04efe874d23ebd55c1361e9dab92f6bf8a5a5028
[speexdsp.git] / src / speexdec.c
1 /* Copyright (C) 2002 Jean-Marc Valin 
2    File: speexdec.c
3
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8    
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13    
14    You should have received a copy of the GNU Lesser General Public
15    License along with this library; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "speex.h"
26 #include "ogg/ogg.h"
27
28 #ifdef HAVE_SYS_SOUNDCARD_H
29 #include <sys/soundcard.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #endif
34
35 #include <string.h>
36
37 #define MAX_FRAME_SIZE 2000
38
39 FILE *out_file_open(char *outFile, int rate)
40 {
41    FILE *fout;
42    /*Open output file*/
43    if (strlen(outFile)==0)
44    {
45 #ifdef HAVE_SYS_SOUNDCARD_H
46       int audio_fd, format, stereo;
47       audio_fd=open("/dev/dsp", O_WRONLY);
48       
49       format=AFMT_S16_LE;
50       if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
51       {
52          perror("SNDCTL_DSP_SETFMT");
53          close(audio_fd);
54          exit(1);
55       }
56       
57       stereo=0;
58       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)
59       {
60          perror("SNDCTL_DSP_STEREO");
61          close(audio_fd);
62          exit(1);
63       }
64       if (stereo!=0)
65       {
66          fprintf (stderr, "Cannot set mono mode\n");
67          exit(1);
68       }
69
70       if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)
71       {
72          perror("SNDCTL_DSP_SPEED");
73          close(audio_fd);
74          exit(1);
75       }
76       fout = fdopen(audio_fd, "w");
77 #else
78       fprintf (stderr, "No soundcard support\n");
79       exit(1);
80 #endif
81    } else {
82       if (strcmp(outFile,"-")==0)
83          fout=stdout;
84       else 
85       {
86          fout = fopen(outFile, "w");
87          if (!fout)
88          {
89             perror(outFile);
90             exit(1);
91          }
92          if (strcmp(outFile+strlen(outFile)-4,".wav")==0)
93             write_wav_header(fout, rate, 1, 0, 0);
94       }
95    }
96    return fout;
97 }
98
99 void usage()
100 {
101    fprintf (stderr, "speexenc [options] <input file> <output file>\n");
102    fprintf (stderr, "options:\n");
103    fprintf (stderr, "\t--help       -h      This help\n"); 
104    fprintf (stderr, "\t--version    -v      Version information\n"); 
105    fprintf (stderr, "\t--pf         --pf    Enable post-filter\n"); 
106    fprintf (stderr, "\t--no-pf      --no-pf Disable post-filter\n"); 
107 }
108
109 void version()
110 {
111    fprintf (stderr, "Speex decoder version " VERSION "\n");
112 }
113
114 int main(int argc, char **argv)
115 {
116    int c;
117    int option_index = 0;
118    char *inFile, *outFile;
119    FILE *fin, *fout;
120    short out[MAX_FRAME_SIZE];
121    float output[MAX_FRAME_SIZE];
122    int frame_size=0;
123    SpeexMode *mode=NULL;
124    void *st=NULL;
125    SpeexBits bits;
126    int first = 1;
127    struct option long_options[] =
128    {
129       {"help", no_argument, NULL, 0},
130       {"version", no_argument, NULL, 0},
131       {"pf", no_argument, NULL, 0},
132       {"no-pf", no_argument, NULL, 0},
133       {0, 0, 0, 0}
134    };
135    ogg_sync_state oy;
136    ogg_page       og;
137    ogg_packet     op;
138    ogg_stream_state os;
139    int pf_enabled;
140
141    pf_enabled = 0;
142
143    /*Process options*/
144    while(1)
145    {
146       c = getopt_long (argc, argv, "hv",
147                        long_options, &option_index);
148       if (c==-1)
149          break;
150       
151       switch(c)
152       {
153       case 0:
154          if (strcmp(long_options[option_index].name,"help")==0)
155          {
156             usage();
157             exit(0);
158          } else if (strcmp(long_options[option_index].name,"version")==0)
159          {
160             version();
161             exit(0);
162          } else if (strcmp(long_options[option_index].name,"pf")==0)
163          {
164             pf_enabled=1;
165          } else if (strcmp(long_options[option_index].name,"no-pf")==0)
166          {
167             pf_enabled=0;
168          }
169          break;
170       case 'h':
171          usage();
172          break;
173       case 'v':
174          version();
175          exit(0);
176          break;
177       case '?':
178          usage();
179          exit(1);
180          break;
181       }
182    }
183    if (argc-optind!=2 && argc-optind!=1)
184    {
185       usage();
186       exit(1);
187    }
188    inFile=argv[optind];
189
190    if (argc-optind==2)
191       outFile=argv[optind+1];
192    else
193       outFile = "";
194    /*Open input file*/
195    if (strcmp(inFile, "-")==0)
196       fin=stdin;
197    else 
198    {
199       fin = fopen(inFile, "r");
200       if (!fin)
201       {
202          perror(inFile);
203          exit(1);
204       }
205    }
206
207
208    /*Init Ogg data struct*/
209    ogg_sync_init(&oy);
210    ogg_stream_init(&os, 0);
211    
212    speex_bits_init(&bits);
213    /*Main decoding loop*/
214    while (1)
215    {
216       char *data;
217       int i, nb_read;
218       /*Get the ogg buffer for writing*/
219       data = ogg_sync_buffer(&oy, 200);
220       /*Read bitstream from input file*/
221       nb_read = fread(data, sizeof(char), 200, fin);      
222       ogg_sync_wrote(&oy, nb_read);
223
224       /*Loop for all complete pages we got (most likely only one)*/
225       while (ogg_sync_pageout(&oy, &og)==1)
226       {
227          /*Add page to the bitstream*/
228          ogg_stream_pagein(&os, &og);
229          /*Extract all available packets*/
230          while (ogg_stream_packetout(&os, &op)==1)
231          {
232             /*If first packet, process as Speex header*/
233             if (first)
234             {
235                int rate;
236                if (strncmp((char *)op.packet, "speex wideband**", 12)==0)
237                {
238                   rate=16000;
239                   mode = &speex_wb_mode;
240                } else if (strncmp((char *)op.packet, "speex narrowband", 12)==0)
241                {
242                   rate=8000;
243                   mode = &speex_nb_mode;
244                } else {
245                   fprintf (stderr, "This Ogg file is not a Speex bitstream\n");
246                   exit(1);
247                }
248                /*Initialize Speex decoder*/
249                st = speex_decoder_init(mode);
250                speex_decoder_ctl(st, SPEEX_SET_PF, &pf_enabled);
251                speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size);
252
253                fout = out_file_open(outFile, rate);
254
255                first=0;
256             } else {
257                /*End of stream condition*/
258                if (strncmp((char *)op.packet, "END OF STREAM", 13)==0)
259                   break;
260                /*Copy Ogg packet to Speex bitstream*/
261                speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
262                /*Decode a frame*/
263                speex_decode(st, &bits, output, 0);
264                
265                /*PCM saturation (just in case)*/
266                for (i=0;i<frame_size;i++)
267                {
268                   if (output[i]>32000)
269                      output[i]=32000;
270                   else if (output[i]<-32000)
271                      output[i]=-32000;
272                }
273                /*Convert to short and save to output file*/
274                for (i=0;i<frame_size;i++)
275                   out[i]=output[i];
276                fwrite(out, sizeof(short), frame_size, fout);
277             }
278          }
279       }
280       if (feof(fin))
281          break;
282
283    }
284
285    speex_decoder_destroy(st);
286    speex_bits_destroy(&bits);
287    ogg_stream_clear(&os);
288  
289    exit(0);
290    return 1;
291 }