xref: /plan9/sys/src/games/mp3enc/vorbis_interface.c (revision 8f5875f3e9b20916b4c52ad4336922bc8653eb7b)
1*8f5875f3SDavid du Colombier /* $Id: vorbis_interface.c,v 1.16 2001/03/18 14:31:29 aleidinger Exp $ */
2*8f5875f3SDavid du Colombier 
3*8f5875f3SDavid du Colombier 
4*8f5875f3SDavid du Colombier /* Compile lame with
5*8f5875f3SDavid du Colombier 
6*8f5875f3SDavid du Colombier #! /bin/bash
7*8f5875f3SDavid du Colombier 
8*8f5875f3SDavid du Colombier OGGVORBIS_ROOT=/home/cvs/vorbis
9*8f5875f3SDavid du Colombier 
10*8f5875f3SDavid du Colombier export CPPFLAGS="-I${OGGVORBIS_ROOT}/ogg/include -I${OGGVORBIS_ROOT}/vorbis/lib"
11*8f5875f3SDavid du Colombier export CONFIG_DEFS="-DUSE_FFT3DN"
12*8f5875f3SDavid du Colombier 
13*8f5875f3SDavid du Colombier make clean
14*8f5875f3SDavid du Colombier ../configure
15*8f5875f3SDavid du Colombier make
16*8f5875f3SDavid du Colombier 
17*8f5875f3SDavid du Colombier You can also do this with the "--with-vorbis" options in configure.
18*8f5875f3SDavid du Colombier 
19*8f5875f3SDavid du Colombier  */
20*8f5875f3SDavid du Colombier 
21*8f5875f3SDavid du Colombier #ifdef HAVE_CONFIG_H
22*8f5875f3SDavid du Colombier # include <config.h>
23*8f5875f3SDavid du Colombier #endif
24*8f5875f3SDavid du Colombier 
25*8f5875f3SDavid du Colombier /* LAME interface to libvorbis */
26*8f5875f3SDavid du Colombier 
27*8f5875f3SDavid du Colombier #ifdef HAVE_VORBIS
28*8f5875f3SDavid du Colombier #include <stdlib.h>
29*8f5875f3SDavid du Colombier #include <limits.h>
30*8f5875f3SDavid du Colombier #include <time.h>
31*8f5875f3SDavid du Colombier #include "vorbis/codec.h"
32*8f5875f3SDavid du Colombier #include "modes/modes.h"
33*8f5875f3SDavid du Colombier #include "lame.h"
34*8f5875f3SDavid du Colombier #include "util.h"
35*8f5875f3SDavid du Colombier 
36*8f5875f3SDavid du Colombier #ifdef WITH_DMALLOC
37*8f5875f3SDavid du Colombier #include <dmalloc.h>
38*8f5875f3SDavid du Colombier #endif
39*8f5875f3SDavid du Colombier 
40*8f5875f3SDavid du Colombier short int  convbuffer [4096];  /* take 8 KByte out of the data segment, not the stack */
41*8f5875f3SDavid du Colombier int        convsize;
42*8f5875f3SDavid du Colombier 
43*8f5875f3SDavid du Colombier ogg_sync_state    oy;  // sync and verify incoming physical bitstream
44*8f5875f3SDavid du Colombier ogg_stream_state  os;  // take physical pages, weld into a logical stream of packets
45*8f5875f3SDavid du Colombier ogg_page          og;  // one Ogg bitstream page. Vorbis packets are inside
46*8f5875f3SDavid du Colombier ogg_packet        op;  // one raw packet of data for decode
47*8f5875f3SDavid du Colombier vorbis_info       vi;  // struct that stores all the static vorbis bitstream settings
48*8f5875f3SDavid du Colombier vorbis_comment    vc;  // struct that stores all the bitstream user comments
49*8f5875f3SDavid du Colombier vorbis_dsp_state  vd;  // central working state for the packet->PCM decoder
50*8f5875f3SDavid du Colombier vorbis_block      vb;  // local working space for packet->PCM decode
51*8f5875f3SDavid du Colombier 
52*8f5875f3SDavid du Colombier 
53*8f5875f3SDavid du Colombier 
lame_decode_ogg_initfile(lame_global_flags * gfp,FILE * fd,mp3data_struct * mp3data)54*8f5875f3SDavid du Colombier int lame_decode_ogg_initfile( lame_global_flags*  gfp,
55*8f5875f3SDavid du Colombier                               FILE*               fd,
56*8f5875f3SDavid du Colombier                               mp3data_struct*     mp3data )
57*8f5875f3SDavid du Colombier {
58*8f5875f3SDavid du Colombier 
59*8f5875f3SDavid du Colombier   lame_internal_flags *gfc = gfp->internal_flags;
60*8f5875f3SDavid du Colombier   char *buffer;
61*8f5875f3SDavid du Colombier   int  bytes;
62*8f5875f3SDavid du Colombier   int i;
63*8f5875f3SDavid du Colombier 
64*8f5875f3SDavid du Colombier 
65*8f5875f3SDavid du Colombier   /********** Decode setup ************/
66*8f5875f3SDavid du Colombier 
67*8f5875f3SDavid du Colombier   ogg_sync_init(&oy); /* Now we can read pages */
68*8f5875f3SDavid du Colombier 
69*8f5875f3SDavid du Colombier 
70*8f5875f3SDavid du Colombier   /* grab some data at the head of the stream.  We want the first page
71*8f5875f3SDavid du Colombier      (which is guaranteed to be small and only contain the Vorbis
72*8f5875f3SDavid du Colombier      stream initial header) We need the first page to get the stream
73*8f5875f3SDavid du Colombier      serialno. */
74*8f5875f3SDavid du Colombier 
75*8f5875f3SDavid du Colombier   /* submit a 4k block to libvorbis' Ogg layer */
76*8f5875f3SDavid du Colombier   buffer=ogg_sync_buffer(&oy,4096);
77*8f5875f3SDavid du Colombier   bytes=fread(buffer,1,4096,fd);
78*8f5875f3SDavid du Colombier   ogg_sync_wrote(&oy,bytes);
79*8f5875f3SDavid du Colombier 
80*8f5875f3SDavid du Colombier   /* Get the first page. */
81*8f5875f3SDavid du Colombier   if(ogg_sync_pageout(&oy,&og)!=1){
82*8f5875f3SDavid du Colombier     /* error case.  Must not be Vorbis data */
83*8f5875f3SDavid du Colombier     ERRORF( gfc, "Error initializing Ogg bitstream data.\n" );
84*8f5875f3SDavid du Colombier     return -1;
85*8f5875f3SDavid du Colombier   }
86*8f5875f3SDavid du Colombier 
87*8f5875f3SDavid du Colombier   /* Get the serial number and set up the rest of decode. */
88*8f5875f3SDavid du Colombier   /* serialno first; use it to set up a logical stream */
89*8f5875f3SDavid du Colombier   ogg_stream_init(&os,ogg_page_serialno(&og));
90*8f5875f3SDavid du Colombier 
91*8f5875f3SDavid du Colombier   /* extract the initial header from the first page and verify that the
92*8f5875f3SDavid du Colombier      Ogg bitstream is in fact Vorbis data */
93*8f5875f3SDavid du Colombier 
94*8f5875f3SDavid du Colombier   /* I handle the initial header first instead of just having the code
95*8f5875f3SDavid du Colombier      read all three Vorbis headers at once because reading the initial
96*8f5875f3SDavid du Colombier      header is an easy way to identify a Vorbis bitstream and it's
97*8f5875f3SDavid du Colombier      useful to see that functionality seperated out. */
98*8f5875f3SDavid du Colombier 
99*8f5875f3SDavid du Colombier   vorbis_info_init(&vi);
100*8f5875f3SDavid du Colombier   vorbis_comment_init(&vc);
101*8f5875f3SDavid du Colombier   if(ogg_stream_pagein(&os,&og)<0){
102*8f5875f3SDavid du Colombier     /* error; stream version mismatch perhaps */
103*8f5875f3SDavid du Colombier     ERRORF( gfc, "Error reading first page of Ogg bitstream data.\n" );
104*8f5875f3SDavid du Colombier     return -1;
105*8f5875f3SDavid du Colombier   }
106*8f5875f3SDavid du Colombier 
107*8f5875f3SDavid du Colombier   if(ogg_stream_packetout(&os,&op)!=1){
108*8f5875f3SDavid du Colombier     /* no page? must not be vorbis */
109*8f5875f3SDavid du Colombier     ERRORF( gfc, "Error reading initial header packet.\n" );
110*8f5875f3SDavid du Colombier     return -1;
111*8f5875f3SDavid du Colombier   }
112*8f5875f3SDavid du Colombier 
113*8f5875f3SDavid du Colombier   if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){
114*8f5875f3SDavid du Colombier     /* error case; not a vorbis header */
115*8f5875f3SDavid du Colombier     ERRORF( gfc, "This Ogg bitstream does not contain Vorbis "
116*8f5875f3SDavid du Colombier 	    "audio data.\n");
117*8f5875f3SDavid du Colombier     return -1;
118*8f5875f3SDavid du Colombier   }
119*8f5875f3SDavid du Colombier 
120*8f5875f3SDavid du Colombier   /* At this point, we're sure we're Vorbis.  We've set up the logical
121*8f5875f3SDavid du Colombier      (Ogg) bitstream decoder.  Get the comment and codebook headers and
122*8f5875f3SDavid du Colombier      set up the Vorbis decoder */
123*8f5875f3SDavid du Colombier 
124*8f5875f3SDavid du Colombier   /* The next two packets in order are the comment and codebook headers.
125*8f5875f3SDavid du Colombier      They're likely large and may span multiple pages.  Thus we reead
126*8f5875f3SDavid du Colombier      and submit data until we get our two pacakets, watching that no
127*8f5875f3SDavid du Colombier      pages are missing.  If a page is missing, error out; losing a
128*8f5875f3SDavid du Colombier      header page is the only place where missing data is fatal. */
129*8f5875f3SDavid du Colombier 
130*8f5875f3SDavid du Colombier   i=0;
131*8f5875f3SDavid du Colombier   while(i<2){
132*8f5875f3SDavid du Colombier     while(i<2){
133*8f5875f3SDavid du Colombier       int result=ogg_sync_pageout(&oy,&og);
134*8f5875f3SDavid du Colombier       if(result==0)break; /* Need more data */
135*8f5875f3SDavid du Colombier       /* Don't complain about missing or corrupt data yet.  We'll
136*8f5875f3SDavid du Colombier 	 catch it at the packet output phase */
137*8f5875f3SDavid du Colombier       if(result==1){
138*8f5875f3SDavid du Colombier 	ogg_stream_pagein(&os,&og); /* we can ignore any errors here
139*8f5875f3SDavid du Colombier 				       as they'll also become apparent
140*8f5875f3SDavid du Colombier 				       at packetout */
141*8f5875f3SDavid du Colombier 	while(i<2){
142*8f5875f3SDavid du Colombier 	  result=ogg_stream_packetout(&os,&op);
143*8f5875f3SDavid du Colombier 	  if(result==0)break;
144*8f5875f3SDavid du Colombier 	  if(result==-1){
145*8f5875f3SDavid du Colombier 	    /* Uh oh; data at some point was corrupted or missing!
146*8f5875f3SDavid du Colombier 	       We can't tolerate that in a header.  Die. */
147*8f5875f3SDavid du Colombier 	    ERRORF( gfc, "Corrupt secondary header.  Exiting.\n" );
148*8f5875f3SDavid du Colombier 	    return -1;
149*8f5875f3SDavid du Colombier 	  }
150*8f5875f3SDavid du Colombier 	  vorbis_synthesis_headerin(&vi,&vc,&op);
151*8f5875f3SDavid du Colombier 	  i++;
152*8f5875f3SDavid du Colombier 	}
153*8f5875f3SDavid du Colombier       }
154*8f5875f3SDavid du Colombier     }
155*8f5875f3SDavid du Colombier     /* no harm in not checking before adding more */
156*8f5875f3SDavid du Colombier     buffer=ogg_sync_buffer(&oy,4096);
157*8f5875f3SDavid du Colombier     bytes=fread(buffer,1,4096,fd);
158*8f5875f3SDavid du Colombier     if(bytes==0 && i<2){
159*8f5875f3SDavid du Colombier       ERRORF( gfc, "End of file before finding all Vorbis headers!\n" );
160*8f5875f3SDavid du Colombier       return -1;
161*8f5875f3SDavid du Colombier     }
162*8f5875f3SDavid du Colombier     ogg_sync_wrote(&oy,bytes);
163*8f5875f3SDavid du Colombier   }
164*8f5875f3SDavid du Colombier 
165*8f5875f3SDavid du Colombier   /* Throw the comments plus a few lines about the bitstream we're
166*8f5875f3SDavid du Colombier      decoding */
167*8f5875f3SDavid du Colombier   {
168*8f5875f3SDavid du Colombier     /*
169*8f5875f3SDavid du Colombier     char **ptr=vc.user_comments;
170*8f5875f3SDavid du Colombier     while(*ptr){
171*8f5875f3SDavid du Colombier       MSGF( gfc, "%s\n", *ptr );
172*8f5875f3SDavid du Colombier       ++ptr;
173*8f5875f3SDavid du Colombier     }
174*8f5875f3SDavid du Colombier     MSGF( gfc, "\nBitstream is %d channel, %ldHz\n", vi.channels, vi.rate );
175*8f5875f3SDavid du Colombier     MSGF( gfc, "Encoded by: %s\n\n", vc.vendor );
176*8f5875f3SDavid du Colombier     */
177*8f5875f3SDavid du Colombier   }
178*8f5875f3SDavid du Colombier 
179*8f5875f3SDavid du Colombier 
180*8f5875f3SDavid du Colombier   /* OK, got and parsed all three headers. Initialize the Vorbis
181*8f5875f3SDavid du Colombier      packet->PCM decoder. */
182*8f5875f3SDavid du Colombier   vorbis_synthesis_init(&vd,&vi); /* central decode state */
183*8f5875f3SDavid du Colombier   vorbis_block_init(&vd,&vb);     /* local state for most of the decode
184*8f5875f3SDavid du Colombier 				     so multiple block decodes can
185*8f5875f3SDavid du Colombier 				     proceed in parallel.  We could init
186*8f5875f3SDavid du Colombier 				     multiple vorbis_block structures
187*8f5875f3SDavid du Colombier 				     for vd here */
188*8f5875f3SDavid du Colombier 
189*8f5875f3SDavid du Colombier   mp3data->stereo = vi.channels;
190*8f5875f3SDavid du Colombier   mp3data->samplerate = vi.rate;
191*8f5875f3SDavid du Colombier   mp3data->bitrate = 0; //ov_bitrate_instant(&vf);
192*8f5875f3SDavid du Colombier   mp3data->nsamp=MAX_U_32_NUM;
193*8f5875f3SDavid du Colombier 
194*8f5875f3SDavid du Colombier   return 0;
195*8f5875f3SDavid du Colombier }
196*8f5875f3SDavid du Colombier 
197*8f5875f3SDavid du Colombier 
198*8f5875f3SDavid du Colombier 
199*8f5875f3SDavid du Colombier /*
200*8f5875f3SDavid du Colombier   For lame_decode_fromfile:  return code
201*8f5875f3SDavid du Colombier   -1     error, or eof
202*8f5875f3SDavid du Colombier   0     ok, but need more data before outputing any samples
203*8f5875f3SDavid du Colombier   n     number of samples output.
204*8f5875f3SDavid du Colombier */
lame_decode_ogg_fromfile(lame_global_flags * gfp,FILE * fd,short int pcm_l[],short int pcm_r[],mp3data_struct * mp3data)205*8f5875f3SDavid du Colombier int lame_decode_ogg_fromfile( lame_global_flags*  gfp,
206*8f5875f3SDavid du Colombier                               FILE*               fd,
207*8f5875f3SDavid du Colombier                               short int           pcm_l[],
208*8f5875f3SDavid du Colombier                               short int           pcm_r[],
209*8f5875f3SDavid du Colombier                               mp3data_struct*     mp3data )
210*8f5875f3SDavid du Colombier {
211*8f5875f3SDavid du Colombier   lame_internal_flags *gfc = gfp->internal_flags;
212*8f5875f3SDavid du Colombier   int samples,result,i,j,eof=0,eos=0,bout=0;
213*8f5875f3SDavid du Colombier   double **pcm;
214*8f5875f3SDavid du Colombier 
215*8f5875f3SDavid du Colombier   while(1){
216*8f5875f3SDavid du Colombier 
217*8f5875f3SDavid du Colombier     /*
218*8f5875f3SDavid du Colombier     **pcm is a multichannel double vector.  In stereo, for
219*8f5875f3SDavid du Colombier     example, pcm[0] is left, and pcm[1] is right.  samples is
220*8f5875f3SDavid du Colombier     the size of each channel.  Convert the float values
221*8f5875f3SDavid du Colombier     (-1.<=range<=1.) to whatever PCM format and write it out */
222*8f5875f3SDavid du Colombier     /* unpack the buffer, if it has at least 1024 samples */
223*8f5875f3SDavid du Colombier     convsize=1024;
224*8f5875f3SDavid du Colombier     samples=vorbis_synthesis_pcmout(&vd,&pcm);
225*8f5875f3SDavid du Colombier     if (samples >= convsize || eos || eof) {
226*8f5875f3SDavid du Colombier       /* read 1024 samples, or if eos, read what ever is in buffer */
227*8f5875f3SDavid du Colombier       int clipflag=0;
228*8f5875f3SDavid du Colombier       bout=(samples<convsize?samples:convsize);
229*8f5875f3SDavid du Colombier 
230*8f5875f3SDavid du Colombier       /* convert doubles to 16 bit signed ints (host order) and
231*8f5875f3SDavid du Colombier 	 interleave */
232*8f5875f3SDavid du Colombier       for(i=0;i<vi.channels;i++){
233*8f5875f3SDavid du Colombier 	double  *mono=pcm[i];
234*8f5875f3SDavid du Colombier 	for(j=0;j<bout;j++){
235*8f5875f3SDavid du Colombier 	  int val=mono[j]*32767.;
236*8f5875f3SDavid du Colombier 	  /* might as well guard against clipping */
237*8f5875f3SDavid du Colombier 	  if(val>32767){
238*8f5875f3SDavid du Colombier 	    val=32767;
239*8f5875f3SDavid du Colombier 	    clipflag=1;
240*8f5875f3SDavid du Colombier 	  }
241*8f5875f3SDavid du Colombier 	  if(val<-32768){
242*8f5875f3SDavid du Colombier 	    val=-32768;
243*8f5875f3SDavid du Colombier 	    clipflag=1;
244*8f5875f3SDavid du Colombier 	  }
245*8f5875f3SDavid du Colombier 	  if (i==0) pcm_l[j]=val;
246*8f5875f3SDavid du Colombier 	  if (i==1) pcm_r[j]=val;
247*8f5875f3SDavid du Colombier 	}
248*8f5875f3SDavid du Colombier       }
249*8f5875f3SDavid du Colombier 
250*8f5875f3SDavid du Colombier       /*
251*8f5875f3SDavid du Colombier       if(clipflag)
252*8f5875f3SDavid du Colombier 	MSGF( gfc, "Clipping in frame %ld\n", vd.sequence );
253*8f5875f3SDavid du Colombier       */
254*8f5875f3SDavid du Colombier 
255*8f5875f3SDavid du Colombier       /* tell libvorbis how many samples we actually consumed */
256*8f5875f3SDavid du Colombier       vorbis_synthesis_read(&vd,bout);
257*8f5875f3SDavid du Colombier 
258*8f5875f3SDavid du Colombier       break;
259*8f5875f3SDavid du Colombier     }
260*8f5875f3SDavid du Colombier 
261*8f5875f3SDavid du Colombier     result=ogg_sync_pageout(&oy,&og);
262*8f5875f3SDavid du Colombier 
263*8f5875f3SDavid du Colombier     if(result==0) {
264*8f5875f3SDavid du Colombier       /* need more data */
265*8f5875f3SDavid du Colombier     }else if (result==-1){ /* missing or corrupt data at this page position */
266*8f5875f3SDavid du Colombier       ERRORF( gfc, "Corrupt or missing data in bitstream; "
267*8f5875f3SDavid du Colombier 	      "continuing...\n");
268*8f5875f3SDavid du Colombier     }else{
269*8f5875f3SDavid du Colombier       /* decode this page */
270*8f5875f3SDavid du Colombier       ogg_stream_pagein(&os,&og); /* can safely ignore errors at
271*8f5875f3SDavid du Colombier 				       this point */
272*8f5875f3SDavid du Colombier       do {
273*8f5875f3SDavid du Colombier 	result=ogg_stream_packetout(&os,&op);
274*8f5875f3SDavid du Colombier 	if(result==0) {
275*8f5875f3SDavid du Colombier 	  /* need more data */
276*8f5875f3SDavid du Colombier 	} else if(result==-1){ /* missing or corrupt data at this page position */
277*8f5875f3SDavid du Colombier 	  /* no reason to complain; already complained above */
278*8f5875f3SDavid du Colombier 	}else{
279*8f5875f3SDavid du Colombier 	  /* we have a packet.  Decode it */
280*8f5875f3SDavid du Colombier 	  vorbis_synthesis(&vb,&op);
281*8f5875f3SDavid du Colombier 	  vorbis_synthesis_blockin(&vd,&vb);
282*8f5875f3SDavid du Colombier 	}
283*8f5875f3SDavid du Colombier       } while (result!=0);
284*8f5875f3SDavid du Colombier     }
285*8f5875f3SDavid du Colombier 
286*8f5875f3SDavid du Colombier     /* is this the last page? */
287*8f5875f3SDavid du Colombier     if(ogg_page_eos(&og))eos=1;
288*8f5875f3SDavid du Colombier 
289*8f5875f3SDavid du Colombier     if(!eos){
290*8f5875f3SDavid du Colombier       char *buffer;
291*8f5875f3SDavid du Colombier       int bytes;
292*8f5875f3SDavid du Colombier       buffer=ogg_sync_buffer(&oy,4096);
293*8f5875f3SDavid du Colombier       bytes=fread(buffer,1,4096,fd);
294*8f5875f3SDavid du Colombier       ogg_sync_wrote(&oy,bytes);
295*8f5875f3SDavid du Colombier       if(bytes==0)eof=1;
296*8f5875f3SDavid du Colombier     }
297*8f5875f3SDavid du Colombier   }
298*8f5875f3SDavid du Colombier 
299*8f5875f3SDavid du Colombier   mp3data->stereo = vi.channels;
300*8f5875f3SDavid du Colombier   mp3data->samplerate = vi.rate;
301*8f5875f3SDavid du Colombier   mp3data->bitrate = 0; //ov_bitrate_instant(&vf);
302*8f5875f3SDavid du Colombier   /*  mp3data->nsamp=MAX_U_32_NUM;*/
303*8f5875f3SDavid du Colombier 
304*8f5875f3SDavid du Colombier 
305*8f5875f3SDavid du Colombier   if (bout==0) {
306*8f5875f3SDavid du Colombier     /* clean up this logical bitstream; before exit we see if we're
307*8f5875f3SDavid du Colombier        followed by another [chained] */
308*8f5875f3SDavid du Colombier     ogg_stream_clear(&os);
309*8f5875f3SDavid du Colombier 
310*8f5875f3SDavid du Colombier     /* ogg_page and ogg_packet structs always point to storage in
311*8f5875f3SDavid du Colombier        libvorbis.  They're never freed or manipulated directly */
312*8f5875f3SDavid du Colombier 
313*8f5875f3SDavid du Colombier     vorbis_block_clear(&vb);
314*8f5875f3SDavid du Colombier     vorbis_dsp_clear(&vd);
315*8f5875f3SDavid du Colombier     vorbis_info_clear(&vi);  /* must be called last */
316*8f5875f3SDavid du Colombier 
317*8f5875f3SDavid du Colombier     /* OK, clean up the framer */
318*8f5875f3SDavid du Colombier     ogg_sync_clear(&oy);
319*8f5875f3SDavid du Colombier     return -1;
320*8f5875f3SDavid du Colombier   }
321*8f5875f3SDavid du Colombier   return bout;
322*8f5875f3SDavid du Colombier }
323*8f5875f3SDavid du Colombier 
324*8f5875f3SDavid du Colombier 
325*8f5875f3SDavid du Colombier 
326*8f5875f3SDavid du Colombier 
327*8f5875f3SDavid du Colombier 
328*8f5875f3SDavid du Colombier 
329*8f5875f3SDavid du Colombier 
330*8f5875f3SDavid du Colombier 
331*8f5875f3SDavid du Colombier 
332*8f5875f3SDavid du Colombier 
333*8f5875f3SDavid du Colombier 
334*8f5875f3SDavid du Colombier 
335*8f5875f3SDavid du Colombier 
336*8f5875f3SDavid du Colombier ogg_stream_state  os2;  // take physical pages, weld into a logical stream of packets
337*8f5875f3SDavid du Colombier ogg_page          og2;  // one Ogg bitstream page. Vorbis packets are inside
338*8f5875f3SDavid du Colombier ogg_packet        op2;  // one raw packet of data for decode
339*8f5875f3SDavid du Colombier 
340*8f5875f3SDavid du Colombier vorbis_info       vi2;  // struct that stores all the static vorbis bitstream settings
341*8f5875f3SDavid du Colombier vorbis_comment    vc2;  // struct that stores all the bitstream user comments
342*8f5875f3SDavid du Colombier vorbis_dsp_state  vd2;  // central working state for the packet->PCM decoder
343*8f5875f3SDavid du Colombier vorbis_block      vb2;  // local working space for packet->PCM decode
344*8f5875f3SDavid du Colombier 
345*8f5875f3SDavid du Colombier 
346*8f5875f3SDavid du Colombier 
347*8f5875f3SDavid du Colombier 
348*8f5875f3SDavid du Colombier #define MAX_COMMENT_LENGTH 255
349*8f5875f3SDavid du Colombier 
lame_encode_ogg_init(lame_global_flags * gfp)350*8f5875f3SDavid du Colombier int lame_encode_ogg_init(lame_global_flags *gfp)
351*8f5875f3SDavid du Colombier {
352*8f5875f3SDavid du Colombier   lame_internal_flags *gfc=gfp->internal_flags;
353*8f5875f3SDavid du Colombier   char comment[MAX_COMMENT_LENGTH+1];
354*8f5875f3SDavid du Colombier 
355*8f5875f3SDavid du Colombier 
356*8f5875f3SDavid du Colombier   /********** Encode setup ************/
357*8f5875f3SDavid du Colombier 
358*8f5875f3SDavid du Colombier   /* choose an encoding mode */
359*8f5875f3SDavid du Colombier   /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
360*8f5875f3SDavid du Colombier   if (gfp->compression_ratio < 5.01) {
361*8f5875f3SDavid du Colombier     memcpy(&vi2,&info_E,sizeof(vi2));
362*8f5875f3SDavid du Colombier     MSGF( gfc, "Encoding with Vorbis mode info_E \n" );
363*8f5875f3SDavid du Colombier   } else if (gfp->compression_ratio < 6) {
364*8f5875f3SDavid du Colombier     memcpy(&vi2,&info_D,sizeof(vi2));
365*8f5875f3SDavid du Colombier     MSGF( gfc, "Encoding with Vorbis mode info_D \n" );
366*8f5875f3SDavid du Colombier   } else if (gfp->compression_ratio < 8) {
367*8f5875f3SDavid du Colombier     memcpy(&vi2,&info_C,sizeof(vi2));
368*8f5875f3SDavid du Colombier     MSGF( gfc, "Encoding with Vorbis mode info_C \n" );
369*8f5875f3SDavid du Colombier   } else if (gfp->compression_ratio < 10) {
370*8f5875f3SDavid du Colombier     memcpy(&vi2,&info_B,sizeof(vi2));
371*8f5875f3SDavid du Colombier     MSGF( gfc, "Encoding with Vorbis mode info_B \n" );
372*8f5875f3SDavid du Colombier   } else if (gfp->compression_ratio < 12) {
373*8f5875f3SDavid du Colombier     memcpy(&vi2,&info_A,sizeof(vi2));
374*8f5875f3SDavid du Colombier     MSGF( gfc, "Encoding with Vorbis mode info_A \n" );
375*8f5875f3SDavid du Colombier   } else {
376*8f5875f3SDavid du Colombier     memcpy(&vi2,&info_A,sizeof(vi2));
377*8f5875f3SDavid du Colombier     MSGF( gfc, "Encoding with Vorbis mode info_A \n" );
378*8f5875f3SDavid du Colombier   }
379*8f5875f3SDavid du Colombier 
380*8f5875f3SDavid du Colombier   vi2.channels = gfc->channels_out;
381*8f5875f3SDavid du Colombier   vi2.rate = gfp->out_samplerate;
382*8f5875f3SDavid du Colombier 
383*8f5875f3SDavid du Colombier 
384*8f5875f3SDavid du Colombier   /* add a comment */
385*8f5875f3SDavid du Colombier   vorbis_comment_init(&vc2);
386*8f5875f3SDavid du Colombier   vorbis_comment_add(&vc2,"Track encoded using L.A.M.E. libvorbis interface.");
387*8f5875f3SDavid du Colombier 
388*8f5875f3SDavid du Colombier   /* Add ID3-style comments to the output using (for the time being) the
389*8f5875f3SDavid du Colombier      "private data members" in the "id3tag_spec" data structure. This was
390*8f5875f3SDavid du Colombier      from a patch by Ralph Giles <giles@a3a32260.sympatico.bconnected.net> */
391*8f5875f3SDavid du Colombier 
392*8f5875f3SDavid du Colombier #ifdef THIS_CODE_IS_NOT_BROKEN_ANYMORE
393*8f5875f3SDavid du Colombier   if(gfp->tag_spec.title) {
394*8f5875f3SDavid du Colombier     strcpy(comment,"TITLE=");
395*8f5875f3SDavid du Colombier     strncat(comment,gfp->tag_spec.title,MAX_COMMENT_LENGTH-strlen(comment));
396*8f5875f3SDavid du Colombier     vorbis_comment_add(&vc2,comment);
397*8f5875f3SDavid du Colombier   }
398*8f5875f3SDavid du Colombier   if(gfp->tag_spec.artist) {
399*8f5875f3SDavid du Colombier     strcpy(comment,"ARTIST=");
400*8f5875f3SDavid du Colombier     strncat(comment,gfp->tag_spec.artist,MAX_COMMENT_LENGTH-strlen(comment));
401*8f5875f3SDavid du Colombier     vorbis_comment_add(&vc2,comment);
402*8f5875f3SDavid du Colombier   }
403*8f5875f3SDavid du Colombier   if(gfp->tag_spec.album) {
404*8f5875f3SDavid du Colombier     strcpy(comment,"ALBUM=");
405*8f5875f3SDavid du Colombier     strncat(comment,gfp->tag_spec.album,MAX_COMMENT_LENGTH-strlen(comment));
406*8f5875f3SDavid du Colombier     vorbis_comment_add(&vc2,comment);
407*8f5875f3SDavid du Colombier   }
408*8f5875f3SDavid du Colombier   /* pretend that the ID3 fields are equivalent to the Vorbis fields */
409*8f5875f3SDavid du Colombier   if(gfp->tag_spec.year) {
410*8f5875f3SDavid du Colombier     sprintf(comment, "DATE=%d", gfp->tag_spec.year);
411*8f5875f3SDavid du Colombier     vorbis_comment_add(&vc2,comment);
412*8f5875f3SDavid du Colombier   }
413*8f5875f3SDavid du Colombier   if(gfp->tag_spec.comment) {
414*8f5875f3SDavid du Colombier     strcpy(comment,"DESCRIPTION=");
415*8f5875f3SDavid du Colombier     strncat(comment,gfp->tag_spec.comment,MAX_COMMENT_LENGTH-strlen(comment));
416*8f5875f3SDavid du Colombier     vorbis_comment_add(&vc2,comment);
417*8f5875f3SDavid du Colombier   }
418*8f5875f3SDavid du Colombier   /* TODO -- support for track and genre */
419*8f5875f3SDavid du Colombier #endif
420*8f5875f3SDavid du Colombier 
421*8f5875f3SDavid du Colombier   /* set up the analysis state and auxiliary encoding storage */
422*8f5875f3SDavid du Colombier   vorbis_analysis_init(&vd2,&vi2);
423*8f5875f3SDavid du Colombier   vorbis_block_init(&vd2,&vb2);
424*8f5875f3SDavid du Colombier 
425*8f5875f3SDavid du Colombier   /* set up our packet->stream encoder */
426*8f5875f3SDavid du Colombier   /* pick a random serial number; that way we can more likely build
427*8f5875f3SDavid du Colombier      chained streams just by concatenation */
428*8f5875f3SDavid du Colombier   srand(time(NULL));
429*8f5875f3SDavid du Colombier   ogg_stream_init(&os2,rand());
430*8f5875f3SDavid du Colombier 
431*8f5875f3SDavid du Colombier   /* Vorbis streams begin with three headers; the initial header (with
432*8f5875f3SDavid du Colombier      most of the codec setup parameters) which is mandated by the Ogg
433*8f5875f3SDavid du Colombier      bitstream spec.  The second header holds any comment fields.  The
434*8f5875f3SDavid du Colombier      third header holds the bitstream codebook.  We merely need to
435*8f5875f3SDavid du Colombier      make the headers, then pass them to libvorbis one at a time;
436*8f5875f3SDavid du Colombier      libvorbis handles the additional Ogg bitstream constraints */
437*8f5875f3SDavid du Colombier 
438*8f5875f3SDavid du Colombier   {
439*8f5875f3SDavid du Colombier     ogg_packet header;
440*8f5875f3SDavid du Colombier     ogg_packet header_comm;
441*8f5875f3SDavid du Colombier     ogg_packet header_code;
442*8f5875f3SDavid du Colombier 
443*8f5875f3SDavid du Colombier     vorbis_analysis_headerout(&vd2,&vc2,&header,&header_comm,&header_code);
444*8f5875f3SDavid du Colombier     ogg_stream_packetin(&os2,&header); /* automatically placed in its own
445*8f5875f3SDavid du Colombier 					 page */
446*8f5875f3SDavid du Colombier     ogg_stream_packetin(&os2,&header_comm);
447*8f5875f3SDavid du Colombier     ogg_stream_packetin(&os2,&header_code);
448*8f5875f3SDavid du Colombier 
449*8f5875f3SDavid du Colombier     /* no need to write out here.  We'll get to that in the main loop */
450*8f5875f3SDavid du Colombier   }
451*8f5875f3SDavid du Colombier 
452*8f5875f3SDavid du Colombier   return 0;
453*8f5875f3SDavid du Colombier }
454*8f5875f3SDavid du Colombier 
455*8f5875f3SDavid du Colombier 
456*8f5875f3SDavid du Colombier 
lame_encode_ogg_finish(lame_global_flags * gfp,char * mp3buf,int mp3buf_size)457*8f5875f3SDavid du Colombier int lame_encode_ogg_finish(lame_global_flags *gfp,
458*8f5875f3SDavid du Colombier 			  char *mp3buf, int mp3buf_size)
459*8f5875f3SDavid du Colombier {
460*8f5875f3SDavid du Colombier   int eos=0,bytes=0;
461*8f5875f3SDavid du Colombier 
462*8f5875f3SDavid du Colombier   vorbis_analysis_wrote(&vd2,0);
463*8f5875f3SDavid du Colombier 
464*8f5875f3SDavid du Colombier   while(vorbis_analysis_blockout(&vd2,&vb2)==1){
465*8f5875f3SDavid du Colombier 
466*8f5875f3SDavid du Colombier     /* analysis */
467*8f5875f3SDavid du Colombier     vorbis_analysis(&vb2,&op2);
468*8f5875f3SDavid du Colombier 
469*8f5875f3SDavid du Colombier       /* weld the packet into the bitstream */
470*8f5875f3SDavid du Colombier       ogg_stream_packetin(&os2,&op2);
471*8f5875f3SDavid du Colombier 
472*8f5875f3SDavid du Colombier       /* write out pages (if any) */
473*8f5875f3SDavid du Colombier       while(!eos){
474*8f5875f3SDavid du Colombier 	int result=ogg_stream_pageout(&os2,&og2);
475*8f5875f3SDavid du Colombier 	if(result==0)break;
476*8f5875f3SDavid du Colombier 
477*8f5875f3SDavid du Colombier 
478*8f5875f3SDavid du Colombier 	/* check if mp3buffer is big enough for the output */
479*8f5875f3SDavid du Colombier 	bytes += og2.header_len + og2.body_len;
480*8f5875f3SDavid du Colombier 	if (bytes > mp3buf_size && mp3buf_size>0)
481*8f5875f3SDavid du Colombier 	  return -5;
482*8f5875f3SDavid du Colombier 
483*8f5875f3SDavid du Colombier 	memcpy(mp3buf,og2.header,og2.header_len);
484*8f5875f3SDavid du Colombier 	memcpy(mp3buf+og2.header_len,og2.body,og2.body_len);
485*8f5875f3SDavid du Colombier 
486*8f5875f3SDavid du Colombier 	/* this could be set above, but for illustrative purposes, I do
487*8f5875f3SDavid du Colombier 	   it here (to show that vorbis does know where the stream ends) */
488*8f5875f3SDavid du Colombier 	if(ogg_page_eos(&og2))eos=1;
489*8f5875f3SDavid du Colombier 
490*8f5875f3SDavid du Colombier       }
491*8f5875f3SDavid du Colombier     }
492*8f5875f3SDavid du Colombier 
493*8f5875f3SDavid du Colombier 
494*8f5875f3SDavid du Colombier   /* clean up and exit.  vorbis_info_clear() must be called last */
495*8f5875f3SDavid du Colombier   ogg_stream_clear(&os2);
496*8f5875f3SDavid du Colombier   vorbis_block_clear(&vb2);
497*8f5875f3SDavid du Colombier   vorbis_dsp_clear(&vd2);
498*8f5875f3SDavid du Colombier 
499*8f5875f3SDavid du Colombier 
500*8f5875f3SDavid du Colombier   /* ogg_page and ogg_packet structs always point to storage in
501*8f5875f3SDavid du Colombier      libvorbis.  They're never freed or manipulated directly */
502*8f5875f3SDavid du Colombier   return bytes;
503*8f5875f3SDavid du Colombier 
504*8f5875f3SDavid du Colombier }
505*8f5875f3SDavid du Colombier 
506*8f5875f3SDavid du Colombier 
507*8f5875f3SDavid du Colombier 
lame_encode_ogg_frame(lame_global_flags * gfp,const sample_t * inbuf_l,const sample_t * inbuf_r,unsigned char * mp3buf,size_t mp3buf_size)508*8f5875f3SDavid du Colombier int  lame_encode_ogg_frame (
509*8f5875f3SDavid du Colombier 	lame_global_flags*  gfp,
510*8f5875f3SDavid du Colombier 	const sample_t*     inbuf_l,
511*8f5875f3SDavid du Colombier 	const sample_t*     inbuf_r,
512*8f5875f3SDavid du Colombier 	unsigned char*      mp3buf,
513*8f5875f3SDavid du Colombier 	size_t              mp3buf_size )
514*8f5875f3SDavid du Colombier {
515*8f5875f3SDavid du Colombier     lame_internal_flags *gfc = gfp->internal_flags;
516*8f5875f3SDavid du Colombier     int  i;
517*8f5875f3SDavid du Colombier     int  eos   = 0;
518*8f5875f3SDavid du Colombier     int  bytes = 0;
519*8f5875f3SDavid du Colombier 
520*8f5875f3SDavid du Colombier     /* expose the buffer to submit data */
521*8f5875f3SDavid du Colombier     double **buffer = vorbis_analysis_buffer(&vd2,gfp->framesize);
522*8f5875f3SDavid du Colombier 
523*8f5875f3SDavid du Colombier     /* change level of input by -90 dB (no de-interleaving!) */
524*8f5875f3SDavid du Colombier     for ( i = 0; i < gfp->framesize; i++ )
525*8f5875f3SDavid du Colombier         buffer [0] [i] = (1/32768.) * inbuf_l [i];
526*8f5875f3SDavid du Colombier     if ( gfc->channels_out == 2 )
527*8f5875f3SDavid du Colombier         for ( i = 0; i < gfp->framesize; i++ )
528*8f5875f3SDavid du Colombier             buffer [1] [i] = (1/32768.) * inbuf_r [i];
529*8f5875f3SDavid du Colombier 
530*8f5875f3SDavid du Colombier   /* tell the library how much we actually submitted */
531*8f5875f3SDavid du Colombier   vorbis_analysis_wrote(&vd2,i);
532*8f5875f3SDavid du Colombier 
533*8f5875f3SDavid du Colombier   /* vorbis does some data preanalysis, then divvies up blocks for
534*8f5875f3SDavid du Colombier      more involved (potentially parallel) processing.  Get a single
535*8f5875f3SDavid du Colombier      block for encoding now */
536*8f5875f3SDavid du Colombier   while(vorbis_analysis_blockout(&vd2,&vb2)==1){
537*8f5875f3SDavid du Colombier     int result;
538*8f5875f3SDavid du Colombier     /* analysis */
539*8f5875f3SDavid du Colombier     vorbis_analysis(&vb2,&op2);
540*8f5875f3SDavid du Colombier 
541*8f5875f3SDavid du Colombier     /* weld the packet into the bitstream */
542*8f5875f3SDavid du Colombier     ogg_stream_packetin(&os2,&op2);
543*8f5875f3SDavid du Colombier 
544*8f5875f3SDavid du Colombier     /* write out pages (if any) */
545*8f5875f3SDavid du Colombier     do {
546*8f5875f3SDavid du Colombier       result=ogg_stream_pageout(&os2,&og2);
547*8f5875f3SDavid du Colombier       if (result==0) break;
548*8f5875f3SDavid du Colombier 
549*8f5875f3SDavid du Colombier       /* check if mp3buffer is big enough for the output */
550*8f5875f3SDavid du Colombier       bytes += og2.header_len + og2.body_len;
551*8f5875f3SDavid du Colombier       /*
552*8f5875f3SDavid du Colombier       DEBUGF("\n\n*********\ndecoded bytes=%i  %i \n",bytes,mp3buf_size);
553*8f5875f3SDavid du Colombier       */
554*8f5875f3SDavid du Colombier       if (bytes > mp3buf_size && mp3buf_size>0)
555*8f5875f3SDavid du Colombier 	return -6;
556*8f5875f3SDavid du Colombier 
557*8f5875f3SDavid du Colombier       memcpy(mp3buf,og2.header,og2.header_len);
558*8f5875f3SDavid du Colombier       memcpy(mp3buf+og2.header_len,og2.body,og2.body_len);
559*8f5875f3SDavid du Colombier       mp3buf += og2.header_len + og2.body_len;
560*8f5875f3SDavid du Colombier 
561*8f5875f3SDavid du Colombier       if(ogg_page_eos(&og2))eos=1;
562*8f5875f3SDavid du Colombier     } while (1);
563*8f5875f3SDavid du Colombier   }
564*8f5875f3SDavid du Colombier   (gfp -> frameNum)++;
565*8f5875f3SDavid du Colombier   return bytes;
566*8f5875f3SDavid du Colombier }
567*8f5875f3SDavid du Colombier 
568*8f5875f3SDavid du Colombier #endif
569*8f5875f3SDavid du Colombier 
570*8f5875f3SDavid du Colombier /* end of vorbis_interface.c */
571*8f5875f3SDavid du Colombier 
572