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