Decoder can now play to soundcard
[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       }
93    }
94    return fout;
95 }
96
97 void usage()
98 {
99    fprintf (stderr, "speexenc [options] <input file> <output file>\n");
100    fprintf (stderr, "options:\n");
101    fprintf (stderr, "\t--help       -h      This help\n"); 
102    fprintf (stderr, "\t--version    -v      Version information\n"); 
103    fprintf (stderr, "\t--pf         --pf    Enable post-filter\n"); 
104    fprintf (stderr, "\t--no-pf      --no-pf Disable post-filter\n"); 
105 }
106
107 void version()
108 {
109    fprintf (stderr, "Speex decoder version " VERSION "\n");
110 }
111
112 int main(int argc, char **argv)
113 {
114    int c;
115    int option_index = 0;
116    char *inFile, *outFile;
117    FILE *fin, *fout;
118    short out[MAX_FRAME_SIZE];
119    float output[MAX_FRAME_SIZE];
120    int frame_size=0;
121    SpeexMode *mode=NULL;
122    void *st=NULL;
123    SpeexBits bits;
124    int first = 1;
125    struct option long_options[] =
126    {
127       {"help", no_argument, NULL, 0},
128       {"version", no_argument, NULL, 0},
129       {"pf", no_argument, NULL, 0},
130       {"no-pf", no_argument, NULL, 0},
131       {0, 0, 0, 0}
132    };
133    ogg_sync_state oy;
134    ogg_page       og;
135    ogg_packet     op;
136    ogg_stream_state os;
137    int pf_enabled;
138
139    pf_enabled = 0;
140
141    /*Process options*/
142    while(1)
143    {
144       c = getopt_long (argc, argv, "hv",
145                        long_options, &option_index);
146       if (c==-1)
147          break;
148       
149       switch(c)
150       {
151       case 0:
152          if (strcmp(long_options[option_index].name,"help")==0)
153          {
154             usage();
155             exit(0);
156          } else if (strcmp(long_options[option_index].name,"version")==0)
157          {
158             version();
159             exit(0);
160          } else if (strcmp(long_options[option_index].name,"pf")==0)
161          {
162             pf_enabled=1;
163          } else if (strcmp(long_options[option_index].name,"no-pf")==0)
164          {
165             pf_enabled=0;
166          }
167          break;
168       case 'h':
169          usage();
170          break;
171       case 'v':
172          version();
173          exit(0);
174          break;
175       case '?':
176          usage();
177          exit(1);
178          break;
179       }
180    }
181    if (argc-optind!=2 && argc-optind!=1)
182    {
183       usage();
184       exit(1);
185    }
186    inFile=argv[optind];
187
188    if (argc-optind==2)
189       outFile=argv[optind+1];
190    else
191       outFile = "";
192    /*Open input file*/
193    if (strcmp(inFile, "-")==0)
194       fin=stdin;
195    else 
196    {
197       fin = fopen(inFile, "r");
198       if (!fin)
199       {
200          perror(inFile);
201          exit(1);
202       }
203    }
204
205
206    /*Init Ogg data struct*/
207    ogg_sync_init(&oy);
208    ogg_stream_init(&os, 0);
209    
210    speex_bits_init(&bits);
211    /*Main decoding loop*/
212    while (1)
213    {
214       char *data;
215       int i, nb_read;
216       /*Get the ogg buffer for writing*/
217       data = ogg_sync_buffer(&oy, 200);
218       /*Read bitstream from input file*/
219       nb_read = fread(data, sizeof(char), 200, fin);      
220       ogg_sync_wrote(&oy, nb_read);
221
222       /*Loop for all complete pages we got (most likely only one)*/
223       while (ogg_sync_pageout(&oy, &og)==1)
224       {
225          /*Add page to the bitstream*/
226          ogg_stream_pagein(&os, &og);
227          /*Extract all available packets*/
228          while (ogg_stream_packetout(&os, &op)==1)
229          {
230             /*If first packet, process as Speex header*/
231             if (first)
232             {
233                int rate;
234                if (strncmp((char *)op.packet, "speex wideband**", 12)==0)
235                {
236                   rate=16000;
237                   mode = &speex_wb_mode;
238                } else if (strncmp((char *)op.packet, "speex narrowband", 12)==0)
239                {
240                   rate=8000;
241                   mode = &speex_nb_mode;
242                } else {
243                   fprintf (stderr, "This Ogg file is not a Speex bitstream\n");
244                   exit(1);
245                }
246                /*Initialize Speex decoder*/
247                st = speex_decoder_init(mode);
248                speex_decoder_ctl(st, SPEEX_SET_PF, &pf_enabled);
249                speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size);
250
251                fout = out_file_open(outFile, rate);
252
253                first=0;
254             } else {
255                /*End of stream condition*/
256                if (strncmp((char *)op.packet, "END OF STREAM", 13)==0)
257                   break;
258                /*Copy Ogg packet to Speex bitstream*/
259                speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
260                /*Decode a frame*/
261                speex_decode(st, &bits, output, 0);
262                
263                /*PCM saturation (just in case)*/
264                for (i=0;i<frame_size;i++)
265                {
266                   if (output[i]>32000)
267                      output[i]=32000;
268                   else if (output[i]<-32000)
269                      output[i]=-32000;
270                }
271                /*Convert to short and save to output file*/
272                for (i=0;i<frame_size;i++)
273                   out[i]=output[i];
274                fwrite(out, sizeof(short), frame_size, fout);
275             }
276          }
277       }
278       if (feof(fin))
279          break;
280
281    }
282
283    speex_decoder_destroy(st);
284    speex_bits_destroy(&bits);
285    ogg_stream_clear(&os);
286  
287    exit(0);
288    return 1;
289 }