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