Minor quality tweak to 3.95 kbps mode.
[speexdsp.git] / src / speexenc.c
1 /* Copyright (C) 2002-2006 Jean-Marc Valin 
2    File: speexenc.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 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #if !defined WIN32 && !defined _WIN32
38 #include <unistd.h>
39 #include <getopt.h>
40 #endif
41 #ifndef HAVE_GETOPT_LONG
42 #include "getopt_win.h"
43 #endif
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47
48 #include <speex/speex.h>
49 #include <ogg/ogg.h>
50 #include "wav_io.h"
51 #include <speex/speex_header.h>
52 #include <speex/speex_stereo.h>
53 #include <speex/speex_preprocess.h>
54
55 #if defined WIN32 || defined _WIN32
56 /* We need the following two to set stdout to binary */
57 #include <io.h>
58 #include <fcntl.h>
59 #endif
60
61 #include "skeleton.h"
62
63
64 void comment_init(char **comments, int* length, char *vendor_string);
65 void comment_add(char **comments, int* length, char *tag, char *val);
66
67
68 /*Write an Ogg page to a file pointer*/
69 int oe_write_page(ogg_page *page, FILE *fp)
70 {
71    int written;
72    written = fwrite(page->header,1,page->header_len, fp);
73    written += fwrite(page->body,1,page->body_len, fp);
74    
75    return written;
76 }
77
78 #define MAX_FRAME_SIZE 2000
79 #define MAX_FRAME_BYTES 2000
80
81 /* Convert input audio bits, endians and channels */
82 static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, spx_int32_t *size)
83 {   
84    unsigned char in[MAX_FRAME_BYTES*2];
85    int i;
86    short *s;
87    int nb_read;
88
89    if (size && *size<=0)
90    {
91       return 0;
92    }
93    /*Read input audio*/
94    if (size)
95       *size -= bits/8*channels*frame_size;
96    if (buff)
97    {
98       for (i=0;i<12;i++)
99          in[i]=buff[i];
100       nb_read = fread(in+12,1,bits/8*channels*frame_size-12, fin) + 12;
101       if (size)
102          *size += 12;
103    } else {
104       nb_read = fread(in,1,bits/8*channels* frame_size, fin);
105    }
106    nb_read /= bits/8*channels;
107
108    /*fprintf (stderr, "%d\n", nb_read);*/
109    if (nb_read==0)
110       return 0;
111
112    s=(short*)in;
113    if(bits==8)
114    {
115       /* Convert 8->16 bits */
116       for(i=frame_size*channels-1;i>=0;i--)
117       {
118          s[i]=(in[i]<<8)^0x8000;
119       }
120    } else
121    {
122       /* convert to our endian format */
123       for(i=0;i<frame_size*channels;i++)
124       {
125          if(lsb) 
126             s[i]=le_short(s[i]); 
127          else
128             s[i]=be_short(s[i]);
129       }
130    }
131
132    /* FIXME: This is probably redundent now */
133    /* copy to float input buffer */
134    for (i=0;i<frame_size*channels;i++)
135    {
136       input[i]=(short)s[i];
137    }
138
139    for (i=nb_read*channels;i<frame_size*channels;i++)
140    {
141       input[i]=0;
142    }
143
144
145    return nb_read;
146 }
147
148 void add_fishead_packet (ogg_stream_state *os) {
149
150    fishead_packet fp;
151
152    memset(&fp, 0, sizeof(fp));
153    fp.ptime_n = 0;
154    fp.ptime_d = 1000;
155    fp.btime_n = 0;
156    fp.btime_d = 1000;
157
158    add_fishead_to_stream(os, &fp);
159 }
160
161 /*
162  * Adds the fishead packets in the skeleton output stream along with the e_o_s packet
163  */
164 void add_fisbone_packet (ogg_stream_state *os, spx_int32_t serialno, SpeexHeader *header) {
165
166    fisbone_packet fp;
167
168    memset(&fp, 0, sizeof(fp));
169    fp.serial_no = serialno;
170    fp.nr_header_packet = 2 + header->extra_headers;
171    fp.granule_rate_n = header->rate;
172    fp.granule_rate_d = 1;
173    fp.start_granule = 0;
174    fp.preroll = 3;
175    fp.granule_shift = 0;
176
177    add_message_header_field(&fp, "Content-Type", "audio/x-speex");
178
179    add_fisbone_to_stream(os, &fp);
180 }
181
182 void version()
183 {
184    const char* speex_version;
185    speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version);
186    printf ("speexenc (Speex encoder) version %s (compiled " __DATE__ ")\n", speex_version);
187    printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n");
188 }
189
190 void version_short()
191 {
192    const char* speex_version;
193    speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version);
194    printf ("speexenc version %s\n", speex_version);
195    printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n");
196 }
197
198 void usage()
199 {
200    printf ("Usage: speexenc [options] input_file output_file\n");
201    printf ("\n");
202    printf ("Encodes input_file using Speex. It can read the WAV or raw files.\n");
203    printf ("\n");
204    printf ("input_file can be:\n");
205    printf ("  filename.wav      wav file\n");
206    printf ("  filename.*        Raw PCM file (any extension other than .wav)\n");
207    printf ("  -                 stdin\n");
208    printf ("\n");  
209    printf ("output_file can be:\n");
210    printf ("  filename.spx      Speex file\n");
211    printf ("  -                 stdout\n");
212    printf ("\n");  
213    printf ("Options:\n");
214    printf (" -n, --narrowband   Narrowband (8 kHz) input file\n"); 
215    printf (" -w, --wideband     Wideband (16 kHz) input file\n"); 
216    printf (" -u, --ultra-wideband \"Ultra-wideband\" (32 kHz) input file\n"); 
217    printf (" --quality n        Encoding quality (0-10), default 8\n"); 
218    printf (" --bitrate n        Encoding bit-rate (use bit-rate n or lower)\n"); 
219    printf (" --vbr              Enable variable bit-rate (VBR)\n"); 
220    printf (" --vbr-max-bitrate  Set max VBR bit-rate allowed\n"); 
221    printf (" --abr rate         Enable average bit-rate (ABR) at rate bps\n"); 
222    printf (" --vad              Enable voice activity detection (VAD)\n"); 
223    printf (" --dtx              Enable file-based discontinuous transmission (DTX)\n"); 
224    printf (" --comp n           Set encoding complexity (0-10), default 3\n"); 
225    printf (" --nframes n        Number of frames per Ogg packet (1-10), default 1\n"); 
226    printf (" --denoise          Denoise the input before encoding\n"); 
227    printf (" --agc              Apply adaptive gain control (AGC) before encoding\n"); 
228    printf (" --skeleton         Outputs ogg skeleton metadata (may cause incompatibilities)\n");
229    printf (" --comment          Add the given string as an extra comment. This may be\n");
230    printf ("                     used multiple times\n");
231    printf (" --author           Author of this track\n");
232    printf (" --title            Title for this track\n");
233    printf (" -h, --help         This help\n"); 
234    printf (" -v, --version      Version information\n"); 
235    printf (" -V                 Verbose mode (show bit-rate)\n"); 
236    printf ("Raw input options:\n");
237    printf (" --rate n           Sampling rate for raw input\n"); 
238    printf (" --stereo           Consider raw input as stereo\n"); 
239    printf (" --le               Raw input is little-endian\n"); 
240    printf (" --be               Raw input is big-endian\n"); 
241    printf (" --8bit             Raw input is 8-bit unsigned\n"); 
242    printf (" --16bit            Raw input is 16-bit signed\n"); 
243    printf ("Default raw PCM input is 16-bit, little-endian, mono\n"); 
244    printf ("\n");
245    printf ("More information is available from the Speex site: http://www.speex.org\n");
246    printf ("\n");
247    printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n");
248 }
249
250
251 int main(int argc, char **argv)
252 {
253    int nb_samples, total_samples=0, nb_encoded;
254    int c;
255    int option_index = 0;
256    char *inFile, *outFile;
257    FILE *fin, *fout;
258    short input[MAX_FRAME_SIZE];
259    spx_int32_t frame_size;
260    int quiet=0;
261    spx_int32_t vbr_enabled=0;
262    spx_int32_t vbr_max=0;
263    int abr_enabled=0;
264    spx_int32_t vad_enabled=0;
265    spx_int32_t dtx_enabled=0;
266    int nbBytes;
267    const SpeexMode *mode=NULL;
268    int modeID = -1;
269    void *st;
270    SpeexBits bits;
271    char cbits[MAX_FRAME_BYTES];
272    int with_skeleton = 0;
273    struct option long_options[] =
274    {
275       {"wideband", no_argument, NULL, 0},
276       {"ultra-wideband", no_argument, NULL, 0},
277       {"narrowband", no_argument, NULL, 0},
278       {"vbr", no_argument, NULL, 0},
279       {"vbr-max-bitrate", required_argument, NULL, 0},
280       {"abr", required_argument, NULL, 0},
281       {"vad", no_argument, NULL, 0},
282       {"dtx", no_argument, NULL, 0},
283       {"quality", required_argument, NULL, 0},
284       {"bitrate", required_argument, NULL, 0},
285       {"nframes", required_argument, NULL, 0},
286       {"comp", required_argument, NULL, 0},
287       {"denoise", no_argument, NULL, 0},
288       {"agc", no_argument, NULL, 0},
289       {"skeleton",no_argument,NULL, 0},
290       {"help", no_argument, NULL, 0},
291       {"quiet", no_argument, NULL, 0},
292       {"le", no_argument, NULL, 0},
293       {"be", no_argument, NULL, 0},
294       {"8bit", no_argument, NULL, 0},
295       {"16bit", no_argument, NULL, 0},
296       {"stereo", no_argument, NULL, 0},
297       {"rate", required_argument, NULL, 0},
298       {"version", no_argument, NULL, 0},
299       {"version-short", no_argument, NULL, 0},
300       {"comment", required_argument, NULL, 0},
301       {"author", required_argument, NULL, 0},
302       {"title", required_argument, NULL, 0},
303       {0, 0, 0, 0}
304    };
305    int print_bitrate=0;
306    spx_int32_t rate=0;
307    spx_int32_t size;
308    int chan=1;
309    int fmt=16;
310    spx_int32_t quality=-1;
311    float vbr_quality=-1;
312    int lsb=1;
313    ogg_stream_state os;
314    ogg_stream_state so; /* ogg stream for skeleton bitstream */
315    ogg_page              og;
316    ogg_packet            op;
317    int bytes_written=0, ret, result;
318    int id=-1;
319    SpeexHeader header;
320    int nframes=1;
321    spx_int32_t complexity=3;
322    const char* speex_version;
323    char vendor_string[64];
324    char *comments;
325    int comments_length;
326    int close_in=0, close_out=0;
327    int eos=0;
328    spx_int32_t bitrate=0;
329    double cumul_bits=0, enc_frames=0;
330    char first_bytes[12];
331    int wave_input=0;
332    spx_int32_t tmp;
333    SpeexPreprocessState *preprocess = NULL;
334    int denoise_enabled=0, agc_enabled=0;
335    spx_int32_t lookahead = 0;
336
337    speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version);
338    snprintf(vendor_string, sizeof(vendor_string), "Encoded with Speex %s", speex_version);
339    
340    comment_init(&comments, &comments_length, vendor_string);
341
342    /*Process command-line options*/
343    while(1)
344    {
345       c = getopt_long (argc, argv, "nwuhvV",
346                        long_options, &option_index);
347       if (c==-1)
348          break;
349       
350       switch(c)
351       {
352       case 0:
353          if (strcmp(long_options[option_index].name,"narrowband")==0)
354          {
355             modeID = SPEEX_MODEID_NB;
356          } else if (strcmp(long_options[option_index].name,"wideband")==0)
357          {
358             modeID = SPEEX_MODEID_WB;
359          } else if (strcmp(long_options[option_index].name,"ultra-wideband")==0)
360          {
361             modeID = SPEEX_MODEID_UWB;
362          } else if (strcmp(long_options[option_index].name,"vbr")==0)
363          {
364             vbr_enabled=1;
365          } else if (strcmp(long_options[option_index].name,"vbr-max-bitrate")==0)
366          {
367             vbr_max=atoi(optarg);
368             if (vbr_max<1)
369             {
370                fprintf (stderr, "Invalid VBR max bit-rate value: %d\n", vbr_max);
371                exit(1);
372             }
373          } else if (strcmp(long_options[option_index].name,"abr")==0)
374          {
375             abr_enabled=atoi(optarg);
376             if (!abr_enabled)
377             {
378                fprintf (stderr, "Invalid ABR value: %d\n", abr_enabled);
379                exit(1);
380             }
381          } else if (strcmp(long_options[option_index].name,"vad")==0)
382          {
383             vad_enabled=1;
384          } else if (strcmp(long_options[option_index].name,"dtx")==0)
385          {
386             dtx_enabled=1;
387          } else if (strcmp(long_options[option_index].name,"quality")==0)
388          {
389             quality = atoi (optarg);
390             vbr_quality=atof(optarg);
391          } else if (strcmp(long_options[option_index].name,"bitrate")==0)
392          {
393             bitrate = atoi (optarg);
394          } else if (strcmp(long_options[option_index].name,"nframes")==0)
395          {
396             nframes = atoi (optarg);
397             if (nframes<1)
398                nframes=1;
399             if (nframes>10)
400                nframes=10;
401          } else if (strcmp(long_options[option_index].name,"comp")==0)
402          {
403             complexity = atoi (optarg);
404          } else if (strcmp(long_options[option_index].name,"denoise")==0)
405          {
406             denoise_enabled=1;
407          } else if (strcmp(long_options[option_index].name,"agc")==0)
408          {
409             agc_enabled=1;
410          } else if (strcmp(long_options[option_index].name,"skeleton")==0)
411          {
412             with_skeleton=1;
413          } else if (strcmp(long_options[option_index].name,"help")==0)
414          {
415             usage();
416             exit(0);
417          } else if (strcmp(long_options[option_index].name,"quiet")==0)
418          {
419             quiet = 1;
420          } else if (strcmp(long_options[option_index].name,"version")==0)
421          {
422             version();
423             exit(0);
424          } else if (strcmp(long_options[option_index].name,"version-short")==0)
425          {
426             version_short();
427             exit(0);
428          } else if (strcmp(long_options[option_index].name,"le")==0)
429          {
430             lsb=1;
431          } else if (strcmp(long_options[option_index].name,"be")==0)
432          {
433             lsb=0;
434          } else if (strcmp(long_options[option_index].name,"8bit")==0)
435          {
436             fmt=8;
437          } else if (strcmp(long_options[option_index].name,"16bit")==0)
438          {
439             fmt=16;
440          } else if (strcmp(long_options[option_index].name,"stereo")==0)
441          {
442             chan=2;
443          } else if (strcmp(long_options[option_index].name,"rate")==0)
444          {
445             rate=atoi (optarg);
446          } else if (strcmp(long_options[option_index].name,"comment")==0)
447          {
448            if (!strchr(optarg, '='))
449            {
450              fprintf (stderr, "Invalid comment: %s\n", optarg);
451              fprintf (stderr, "Comments must be of the form name=value\n");
452              exit(1);
453            }
454            comment_add(&comments, &comments_length, NULL, optarg); 
455          } else if (strcmp(long_options[option_index].name,"author")==0)
456          {
457            comment_add(&comments, &comments_length, "author=", optarg); 
458          } else if (strcmp(long_options[option_index].name,"title")==0)
459          {
460            comment_add(&comments, &comments_length, "title=", optarg); 
461          }
462
463          break;
464       case 'n':
465          modeID = SPEEX_MODEID_NB;
466          break;
467       case 'h':
468          usage();
469          exit(0);
470          break;
471       case 'v':
472          version();
473          exit(0);
474          break;
475       case 'V':
476          print_bitrate=1;
477          break;
478       case 'w':
479          modeID = SPEEX_MODEID_WB;
480          break;
481       case 'u':
482          modeID = SPEEX_MODEID_UWB;
483          break;
484       case '?':
485          usage();
486          exit(1);
487          break;
488       }
489    }
490    if (argc-optind!=2)
491    {
492       usage();
493       exit(1);
494    }
495    inFile=argv[optind];
496    outFile=argv[optind+1];
497
498    /*Initialize Ogg stream struct*/
499    srand(time(NULL));
500    if (ogg_stream_init(&os, rand())==-1)
501    {
502       fprintf(stderr,"Error: stream init failed\n");
503       exit(1);
504    }
505    if (with_skeleton && ogg_stream_init(&so, rand())==-1)
506    {
507       fprintf(stderr,"Error: stream init failed\n");
508       exit(1);
509    }
510
511    if (strcmp(inFile, "-")==0)
512    {
513 #if defined WIN32 || defined _WIN32
514          _setmode(_fileno(stdin), _O_BINARY);
515 #endif
516       fin=stdin;
517    }
518    else 
519    {
520       fin = fopen(inFile, "rb");
521       if (!fin)
522       {
523          perror(inFile);
524          exit(1);
525       }
526       close_in=1;
527    }
528
529    {
530       fread(first_bytes, 1, 12, fin);
531       if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0)
532       {
533          if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1)
534             exit(1);
535          wave_input=1;
536          lsb=1; /* CHECK: exists big-endian .wav ?? */
537       }
538    }
539
540    if (modeID==-1 && !rate)
541    {
542       /* By default, use narrowband/8 kHz */
543       modeID = SPEEX_MODEID_NB;
544       rate=8000;
545    } else if (modeID!=-1 && rate)
546    {
547       mode = speex_lib_get_mode (modeID);
548       if (rate>48000)
549       {
550          fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate);
551          exit(1);
552       } else if (rate>25000)
553       {
554          if (modeID != SPEEX_MODEID_UWB)
555          {
556             fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try ultra-wideband instead\n", mode->modeName , rate);
557          }
558       } else if (rate>12500)
559       {
560          if (modeID != SPEEX_MODEID_WB)
561          {
562             fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try wideband instead\n", mode->modeName , rate);
563          }
564       } else if (rate>=6000)
565       {
566          if (modeID != SPEEX_MODEID_NB)
567          {
568             fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try narrowband instead\n", mode->modeName , rate);
569          }
570       } else {
571          fprintf (stderr, "Error: sampling rate too low: %d Hz\n", rate);
572          exit(1);
573       }
574    } else if (modeID==-1)
575    {
576       if (rate>48000)
577       {
578          fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate);
579          exit(1);
580       } else if (rate>25000)
581       {
582          modeID = SPEEX_MODEID_UWB;
583       } else if (rate>12500)
584       {
585          modeID = SPEEX_MODEID_WB;
586       } else if (rate>=6000)
587       {
588          modeID = SPEEX_MODEID_NB;
589       } else {
590          fprintf (stderr, "Error: Sampling rate too low: %d Hz\n", rate);
591          exit(1);
592       }
593    } else if (!rate)
594    {
595       if (modeID == SPEEX_MODEID_NB)
596          rate=8000;
597       else if (modeID == SPEEX_MODEID_WB)
598          rate=16000;
599       else if (modeID == SPEEX_MODEID_UWB)
600          rate=32000;
601    }
602
603    if (!quiet)
604       if (rate!=8000 && rate!=16000 && rate!=32000)
605          fprintf (stderr, "Warning: Speex is only optimized for 8, 16 and 32 kHz. It will still work at %d Hz but your mileage may vary\n", rate); 
606
607    if (!mode)
608       mode = speex_lib_get_mode (modeID);
609
610    speex_init_header(&header, rate, 1, mode);
611    header.frames_per_packet=nframes;
612    header.vbr=vbr_enabled;
613    header.nb_channels = chan;
614
615    {
616       char *st_string="mono";
617       if (chan==2)
618          st_string="stereo";
619       if (!quiet)
620          fprintf (stderr, "Encoding %d Hz audio using %s mode (%s)\n", 
621                header.rate, mode->modeName, st_string);
622    }
623    /*fprintf (stderr, "Encoding %d Hz audio at %d bps using %s mode\n", 
624      header.rate, mode->bitrate, mode->modeName);*/
625
626    /*Initialize Speex encoder*/
627    st = speex_encoder_init(mode);
628
629    if (strcmp(outFile,"-")==0)
630    {
631 #if defined WIN32 || defined _WIN32
632       _setmode(_fileno(stdout), _O_BINARY);
633 #endif
634       fout=stdout;
635    }
636    else 
637    {
638       fout = fopen(outFile, "wb");
639       if (!fout)
640       {
641          perror(outFile);
642          exit(1);
643       }
644       close_out=1;
645    }
646
647    speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size);
648    speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &complexity);
649    speex_encoder_ctl(st, SPEEX_SET_SAMPLING_RATE, &rate);
650
651    if (quality >= 0)
652    {
653       if (vbr_enabled)
654       {
655          if (vbr_max>0)
656             speex_encoder_ctl(st, SPEEX_SET_VBR_MAX_BITRATE, &vbr_max);
657          speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_quality);
658       }
659       else
660          speex_encoder_ctl(st, SPEEX_SET_QUALITY, &quality);
661    }
662    if (bitrate)
663    {
664       if (quality >= 0 && vbr_enabled)
665          fprintf (stderr, "Warning: --bitrate option is overriding --quality\n");
666       speex_encoder_ctl(st, SPEEX_SET_BITRATE, &bitrate);
667    }
668    if (vbr_enabled)
669    {
670       tmp=1;
671       speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
672    } else if (vad_enabled)
673    {
674       tmp=1;
675       speex_encoder_ctl(st, SPEEX_SET_VAD, &tmp);
676    }
677    if (dtx_enabled)
678       speex_encoder_ctl(st, SPEEX_SET_DTX, &tmp);
679    if (dtx_enabled && !(vbr_enabled || abr_enabled || vad_enabled))
680    {
681       fprintf (stderr, "Warning: --dtx is useless without --vad, --vbr or --abr\n");
682    } else if ((vbr_enabled || abr_enabled) && (vad_enabled))
683    {
684       fprintf (stderr, "Warning: --vad is already implied by --vbr or --abr\n");
685    }
686    if (with_skeleton) {
687       fprintf (stderr, "Warning: Enabling skeleton output may cause some decoders to fail.\n");
688    }
689
690    if (abr_enabled)
691    {
692       speex_encoder_ctl(st, SPEEX_SET_ABR, &abr_enabled);
693    }
694
695    speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
696    
697    if (denoise_enabled || agc_enabled)
698    {
699       preprocess = speex_preprocess_state_init(frame_size, rate);
700       speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &denoise_enabled);
701       speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC, &agc_enabled);
702       lookahead += frame_size;
703    }
704
705    /* first packet should be the skeleton header. */
706
707    if (with_skeleton) {
708       add_fishead_packet(&so);
709       if ((ret = flush_ogg_stream_to_file(&so, fout))) {
710          fprintf (stderr,"Error: failed skeleton (fishead) header to output stream\n");
711          exit(1);
712       } else
713          bytes_written += ret;
714    }
715
716    /*Write header*/
717    {
718       int packet_size;
719       op.packet = (unsigned char *)speex_header_to_packet(&header, &packet_size);
720       op.bytes = packet_size;
721       op.b_o_s = 1;
722       op.e_o_s = 0;
723       op.granulepos = 0;
724       op.packetno = 0;
725       ogg_stream_packetin(&os, &op);
726       free(op.packet);
727
728       while((result = ogg_stream_flush(&os, &og)))
729       {
730          if(!result) break;
731          ret = oe_write_page(&og, fout);
732          if(ret != og.header_len + og.body_len)
733          {
734             fprintf (stderr,"Error: failed writing header to output stream\n");
735             exit(1);
736          }
737          else
738             bytes_written += ret;
739       }
740
741       op.packet = (unsigned char *)comments;
742       op.bytes = comments_length;
743       op.b_o_s = 0;
744       op.e_o_s = 0;
745       op.granulepos = 0;
746       op.packetno = 1;
747       ogg_stream_packetin(&os, &op);
748    }
749
750    /* fisbone packet should be write after all bos pages */
751    if (with_skeleton) {
752       add_fisbone_packet(&so, os.serialno, &header);
753       if ((ret = flush_ogg_stream_to_file(&so, fout))) {
754          fprintf (stderr,"Error: failed writing skeleton (fisbone )header to output stream\n");
755          exit(1);
756       } else
757          bytes_written += ret;
758    }
759
760    /* writing the rest of the speex header packets */
761    while((result = ogg_stream_flush(&os, &og)))
762    {
763       if(!result) break;
764       ret = oe_write_page(&og, fout);
765       if(ret != og.header_len + og.body_len)
766       {
767          fprintf (stderr,"Error: failed writing header to output stream\n");
768          exit(1);
769       }
770       else
771          bytes_written += ret;
772    }
773
774    free(comments);
775
776    /* write the skeleton eos packet */
777    if (with_skeleton) {
778       add_eos_packet_to_stream(&so);
779       if ((ret = flush_ogg_stream_to_file(&so, fout))) {
780          fprintf (stderr,"Error: failed writing skeleton header to output stream\n");
781          exit(1);
782       } else
783          bytes_written += ret;
784    }
785
786
787    speex_bits_init(&bits);
788
789    if (!wave_input)
790    {
791       nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL);
792    } else {
793       nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
794    }
795    if (nb_samples==0)
796       eos=1;
797    total_samples += nb_samples;
798    nb_encoded = -lookahead;
799    /*Main encoding loop (one frame per iteration)*/
800    while (!eos || total_samples>nb_encoded)
801    {
802       id++;
803       /*Encode current frame*/
804       if (chan==2)
805          speex_encode_stereo_int(input, frame_size, &bits);
806
807       if (preprocess)
808          speex_preprocess(preprocess, input, NULL);
809
810       speex_encode_int(st, input, &bits);
811       
812       nb_encoded += frame_size;
813       if (print_bitrate) {
814          int tmp;
815          char ch=13;
816          speex_encoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
817          fputc (ch, stderr);
818          cumul_bits += tmp;
819          enc_frames += 1;
820          if (!quiet)
821          {
822             if (vad_enabled || vbr_enabled || abr_enabled)
823                fprintf (stderr, "Bitrate is use: %d bps  (average %d bps)   ", tmp, (int)(cumul_bits/enc_frames));
824             else
825                fprintf (stderr, "Bitrate is use: %d bps     ", tmp);
826          }
827          
828       }
829
830       if (wave_input)
831       {
832          nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
833       } else {
834          nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL);
835       }
836       if (nb_samples==0)
837       {
838          eos=1;
839       }
840       if (eos && total_samples<=nb_encoded)
841          op.e_o_s = 1;
842       else
843          op.e_o_s = 0;
844       total_samples += nb_samples;
845
846       if ((id+1)%nframes!=0)
847          continue;
848       speex_bits_insert_terminator(&bits);
849       nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES);
850       speex_bits_reset(&bits);
851       op.packet = (unsigned char *)cbits;
852       op.bytes = nbBytes;
853       op.b_o_s = 0;
854       /*Is this redundent?*/
855       if (eos && total_samples<=nb_encoded)
856          op.e_o_s = 1;
857       else
858          op.e_o_s = 0;
859       op.granulepos = (id+1)*frame_size-lookahead;
860       if (op.granulepos>total_samples)
861          op.granulepos = total_samples;
862       /*printf ("granulepos: %d %d %d %d %d %d\n", (int)op.granulepos, id, nframes, lookahead, 5, 6);*/
863       op.packetno = 2+id/nframes;
864       ogg_stream_packetin(&os, &op);
865
866       /*Write all new pages (most likely 0 or 1)*/
867       while (ogg_stream_pageout(&os,&og))
868       {
869          ret = oe_write_page(&og, fout);
870          if(ret != og.header_len + og.body_len)
871          {
872             fprintf (stderr,"Error: failed writing header to output stream\n");
873             exit(1);
874          }
875          else
876             bytes_written += ret;
877       }
878    }
879    if ((id+1)%nframes!=0)
880    {
881       while ((id+1)%nframes!=0)
882       {
883          id++;
884          speex_bits_pack(&bits, 15, 5);
885       }
886       nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES);
887       op.packet = (unsigned char *)cbits;
888       op.bytes = nbBytes;
889       op.b_o_s = 0;
890       op.e_o_s = 1;
891       op.granulepos = (id+1)*frame_size-lookahead;
892       if (op.granulepos>total_samples)
893          op.granulepos = total_samples;
894
895       op.packetno = 2+id/nframes;
896       ogg_stream_packetin(&os, &op);
897    }
898    /*Flush all pages left to be written*/
899    while (ogg_stream_flush(&os, &og))
900    {
901       ret = oe_write_page(&og, fout);
902       if(ret != og.header_len + og.body_len)
903       {
904          fprintf (stderr,"Error: failed writing header to output stream\n");
905          exit(1);
906       }
907       else
908          bytes_written += ret;
909    }
910
911    speex_encoder_destroy(st);
912    speex_bits_destroy(&bits);
913    ogg_stream_clear(&os);
914
915    if (close_in)
916       fclose(fin);
917    if (close_out)
918       fclose(fout);
919    return 0;
920 }
921
922 /*                 
923  Comments will be stored in the Vorbis style.            
924  It is describled in the "Structure" section of
925     http://www.xiph.org/ogg/vorbis/doc/v-comment.html
926
927 The comment header is decoded as follows:
928   1) [vendor_length] = read an unsigned integer of 32 bits
929   2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
930   3) [user_comment_list_length] = read an unsigned integer of 32 bits
931   4) iterate [user_comment_list_length] times {
932      5) [length] = read an unsigned integer of 32 bits
933      6) this iteration's user comment = read a UTF-8 vector as [length] octets
934      }
935   7) [framing_bit] = read a single bit as boolean
936   8) if ( [framing_bit]  unset or end of packet ) then ERROR
937   9) done.
938
939   If you have troubles, please write to ymnk@jcraft.com.
940  */
941
942 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
943                            ((buf[base+2]<<16)&0xff0000)| \
944                            ((buf[base+1]<<8)&0xff00)| \
945                             (buf[base]&0xff))
946 #define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \
947                                      buf[base+2]=((val)>>16)&0xff; \
948                                      buf[base+1]=((val)>>8)&0xff; \
949                                      buf[base]=(val)&0xff; \
950                                  }while(0)
951
952 void comment_init(char **comments, int* length, char *vendor_string)
953 {
954   int vendor_length=strlen(vendor_string);
955   int user_comment_list_length=0;
956   int len=4+vendor_length+4;
957   char *p=(char*)malloc(len);
958   if(p==NULL){
959      fprintf (stderr, "malloc failed in comment_init()\n");
960      exit(1);
961   }
962   writeint(p, 0, vendor_length);
963   memcpy(p+4, vendor_string, vendor_length);
964   writeint(p, 4+vendor_length, user_comment_list_length);
965   *length=len;
966   *comments=p;
967 }
968 void comment_add(char **comments, int* length, char *tag, char *val)
969 {
970   char* p=*comments;
971   int vendor_length=readint(p, 0);
972   int user_comment_list_length=readint(p, 4+vendor_length);
973   int tag_len=(tag?strlen(tag):0);
974   int val_len=strlen(val);
975   int len=(*length)+4+tag_len+val_len;
976
977   p=(char*)realloc(p, len);
978   if(p==NULL){
979      fprintf (stderr, "realloc failed in comment_add()\n");
980      exit(1);
981   }
982
983   writeint(p, *length, tag_len+val_len);      /* length of comment */
984   if(tag) memcpy(p+*length+4, tag, tag_len);  /* comment */
985   memcpy(p+*length+4+tag_len, val, val_len);  /* comment */
986   writeint(p, 4+vendor_length, user_comment_list_length+1);
987
988   *comments=p;
989   *length=len;
990 }
991 #undef readint
992 #undef writeint