ea9f88b81d31e3315973a800680d4e51be906c89
[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 #include <sys/ioctl.h>
34 #endif
35
36 #include <string.h>
37 #include "wav_io.h"
38 #include "speex_header.h"
39
40 #define MAX_FRAME_SIZE 2000
41
42 FILE *out_file_open(char *outFile, int rate)
43 {
44    FILE *fout;
45    /*Open output file*/
46    if (strlen(outFile)==0)
47    {
48 #ifdef HAVE_SYS_SOUNDCARD_H
49       int audio_fd, format, stereo;
50       audio_fd=open("/dev/dsp", O_WRONLY);
51       
52       format=AFMT_S16_LE;
53       if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
54       {
55          perror("SNDCTL_DSP_SETFMT");
56          close(audio_fd);
57          exit(1);
58       }
59       
60       stereo=0;
61       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)
62       {
63          perror("SNDCTL_DSP_STEREO");
64          close(audio_fd);
65          exit(1);
66       }
67       if (stereo!=0)
68       {
69          fprintf (stderr, "Cannot set mono mode\n");
70          exit(1);
71       }
72
73       if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)
74       {
75          perror("SNDCTL_DSP_SPEED");
76          close(audio_fd);
77          exit(1);
78       }
79       fout = fdopen(audio_fd, "w");
80 #else
81       fprintf (stderr, "No soundcard support\n");
82       exit(1);
83 #endif
84    } else {
85       if (strcmp(outFile,"-")==0)
86          fout=stdout;
87       else 
88       {
89          fout = fopen(outFile, "w");
90          if (!fout)
91          {
92             perror(outFile);
93             exit(1);
94          }
95          if (strcmp(outFile+strlen(outFile)-4,".wav")==0)
96             write_wav_header(fout, rate, 1, 0, 0);
97       }
98    }
99    return fout;
100 }
101
102 void usage()
103 {
104    fprintf (stderr, "speexenc [options] <input file> <output file>\n");
105    fprintf (stderr, "options:\n");
106    fprintf (stderr, "\t--help       -h      This help\n"); 
107    fprintf (stderr, "\t--version    -v      Version information\n"); 
108    fprintf (stderr, "\t--pf         --pf    Enable post-filter\n"); 
109    fprintf (stderr, "\t--no-pf      --no-pf Disable post-filter\n"); 
110 }
111
112 void version()
113 {
114    fprintf (stderr, "Speex decoder version " VERSION "\n");
115 }
116
117 static void *process_header(ogg_packet *op, int pf_enabled, int *frame_size, int *rate)
118 {
119    void *st;
120    SpeexMode *mode;
121    SpeexHeader *header;
122    
123    header = speex_packet_to_header((char*)op->packet, op->bytes);
124    if (!header)
125    {
126       fprintf (stderr, "Cannot read header\n");
127       return NULL;
128    }
129    mode = speex_mode_list[header->mode];
130    st = speex_decoder_init(mode);
131    speex_decoder_ctl(st, SPEEX_SET_PF, &pf_enabled);
132    speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
133    
134    *rate = header->rate;
135
136    free(header);
137    return st;
138 }
139
140 int main(int argc, char **argv)
141 {
142    int c;
143    int option_index = 0;
144    char *inFile, *outFile;
145    FILE *fin, *fout=NULL;
146    short out[MAX_FRAME_SIZE];
147    float output[MAX_FRAME_SIZE];
148    int frame_size=0;
149    void *st=NULL;
150    SpeexBits bits;
151    int packet_count=0;
152    struct option long_options[] =
153    {
154       {"help", no_argument, NULL, 0},
155       {"version", no_argument, NULL, 0},
156       {"pf", no_argument, NULL, 0},
157       {"no-pf", no_argument, NULL, 0},
158       {0, 0, 0, 0}
159    };
160    ogg_sync_state oy;
161    ogg_page       og;
162    ogg_packet     op;
163    ogg_stream_state os;
164    int pf_enabled;
165
166    pf_enabled = 0;
167
168    /*Process options*/
169    while(1)
170    {
171       c = getopt_long (argc, argv, "hv",
172                        long_options, &option_index);
173       if (c==-1)
174          break;
175       
176       switch(c)
177       {
178       case 0:
179          if (strcmp(long_options[option_index].name,"help")==0)
180          {
181             usage();
182             exit(0);
183          } else if (strcmp(long_options[option_index].name,"version")==0)
184          {
185             version();
186             exit(0);
187          } else if (strcmp(long_options[option_index].name,"pf")==0)
188          {
189             pf_enabled=1;
190          } else if (strcmp(long_options[option_index].name,"no-pf")==0)
191          {
192             pf_enabled=0;
193          }
194          break;
195       case 'h':
196          usage();
197          break;
198       case 'v':
199          version();
200          exit(0);
201          break;
202       case '?':
203          usage();
204          exit(1);
205          break;
206       }
207    }
208    if (argc-optind!=2 && argc-optind!=1)
209    {
210       usage();
211       exit(1);
212    }
213    inFile=argv[optind];
214
215    if (argc-optind==2)
216       outFile=argv[optind+1];
217    else
218       outFile = "";
219    /*Open input file*/
220    if (strcmp(inFile, "-")==0)
221       fin=stdin;
222    else 
223    {
224       fin = fopen(inFile, "r");
225       if (!fin)
226       {
227          perror(inFile);
228          exit(1);
229       }
230    }
231
232
233    /*Init Ogg data struct*/
234    ogg_sync_init(&oy);
235    ogg_stream_init(&os, 0);
236    
237    speex_bits_init(&bits);
238    /*Main decoding loop*/
239    while (1)
240    {
241       char *data;
242       int i, nb_read;
243       /*Get the ogg buffer for writing*/
244       data = ogg_sync_buffer(&oy, 200);
245       /*Read bitstream from input file*/
246       nb_read = fread(data, sizeof(char), 200, fin);      
247       ogg_sync_wrote(&oy, nb_read);
248
249       /*Loop for all complete pages we got (most likely only one)*/
250       while (ogg_sync_pageout(&oy, &og)==1)
251       {
252          /*Add page to the bitstream*/
253          ogg_stream_pagein(&os, &og);
254          /*Extract all available packets*/
255          while (ogg_stream_packetout(&os, &op)==1)
256          {
257             /*If first packet, process as Speex header*/
258             if (packet_count==0)
259             {
260                int rate;
261                st = process_header(&op, pf_enabled, &frame_size, &rate);
262                if (!st)
263                   exit(1);
264                fout = out_file_open(outFile, rate);
265
266             } else if (packet_count==1){
267                fwrite(op.packet, 1, op.bytes, stderr);
268                fprintf (stderr, "\n");
269             } else {
270
271                /*End of stream condition*/
272                if (strncmp((char *)op.packet, "END OF STREAM", 13)==0)
273                   break;
274                /*Copy Ogg packet to Speex bitstream*/
275                speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
276                /*Decode a frame*/
277                speex_decode(st, &bits, output, 0);
278                
279                /*PCM saturation (just in case)*/
280                for (i=0;i<frame_size;i++)
281                {
282                   if (output[i]>32000)
283                      output[i]=32000;
284                   else if (output[i]<-32000)
285                      output[i]=-32000;
286                }
287                /*Convert to short and save to output file*/
288                for (i=0;i<frame_size;i++)
289                   out[i]=output[i];
290                fwrite(out, sizeof(short), frame_size, fout);
291             }
292             packet_count++;
293          }
294       }
295       if (feof(fin))
296          break;
297
298    }
299
300    if (st)
301       speex_decoder_destroy(st);
302    speex_bits_destroy(&bits);
303    ogg_stream_clear(&os);
304  
305    exit(0);
306    return 1;
307 }