Make duplicate script compatible with Python 3
[wdl/wdl-ol.git] / WDL / vorbisencdec.h
blobfa935f2f09afdcf5e6bf60ba34784d7853ad80d9
1 /*
2 WDL - vorbisencdec.h
3 Copyright (C) 2005 and later, Cockos Incorporated
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
26 This file provides simple interfaces for encoding and decoding of OGG Vorbis data.
27 It is a wrapper around what their SDKs expose, which is not too easy to use.
29 This stuff is pretty limited and simple, but works, usually.
31 For full control you probably want to #define VORBISENC_WANT_FULLCONFIG
32 but for compatibility with some older code, it's left disabled here.
36 #ifndef _VORBISENCDEC_H_
37 #define _VORBISENCDEC_H_
39 #ifndef OV_EXCLUDE_STATIC_CALLBACKS
40 #define OV_EXCLUDE_STATIC_CALLBACKS
41 #endif
42 #include "vorbis/vorbisenc.h"
43 #include "vorbis/codec.h"
45 class VorbisDecoderInterface
47 public:
48 virtual ~VorbisDecoderInterface(){}
49 virtual int GetSampleRate()=0;
50 virtual int GetNumChannels()=0;
51 virtual void *DecodeGetSrcBuffer(int srclen)=0;
52 virtual void DecodeWrote(int srclen)=0;
53 virtual void Reset()=0;
54 virtual int Available()=0;
55 virtual float *Get()=0;
56 virtual void Skip(int amt)=0;
59 class VorbisEncoderInterface
61 public:
62 virtual ~VorbisEncoderInterface(){}
63 virtual void Encode(float *in, int inlen, int advance=1, int spacing=1)=0; // length in sample (PAIRS)
64 virtual int isError()=0;
65 virtual int Available()=0;
66 virtual void *Get()=0;
67 virtual void Advance(int)=0;
68 virtual void Compact()=0;
69 virtual void reinit(int bla=0)=0;
73 #ifndef WDL_VORBIS_INTERFACE_ONLY
75 #include "../WDL/queue.h"
77 class VorbisDecoder : public VorbisDecoderInterface
79 public:
80 VorbisDecoder()
82 m_samples_used=0;
83 packets=0;
84 memset(&oy,0,sizeof(oy));
85 memset(&os,0,sizeof(os));
86 memset(&og,0,sizeof(og));
87 memset(&op,0,sizeof(op));
88 memset(&vi,0,sizeof(vi));
89 memset(&vc,0,sizeof(vc));
90 memset(&vd,0,sizeof(vd));
91 memset(&vb,0,sizeof(vb));
94 ogg_sync_init(&oy); /* Now we can read pages */
95 m_err=0;
97 ~VorbisDecoder()
99 ogg_stream_clear(&os);
100 vorbis_block_clear(&vb);
101 vorbis_dsp_clear(&vd);
102 vorbis_comment_clear(&vc);
103 vorbis_info_clear(&vi);
105 ogg_sync_clear(&oy);
108 int GetSampleRate() { return vi.rate; }
109 int GetNumChannels() { return vi.channels?vi.channels:1; }
111 void *DecodeGetSrcBuffer(int srclen)
113 return ogg_sync_buffer(&oy,srclen);
116 void DecodeWrote(int srclen)
118 ogg_sync_wrote(&oy,srclen);
120 while(ogg_sync_pageout(&oy,&og)>0)
122 int serial=ogg_page_serialno(&og);
123 if (!packets) ogg_stream_init(&os,serial);
124 else if (serial!=os.serialno)
126 vorbis_block_clear(&vb);
127 vorbis_dsp_clear(&vd);
128 vorbis_comment_clear(&vc);
129 vorbis_info_clear(&vi);
131 ogg_stream_clear(&os);
132 ogg_stream_init(&os,serial);
133 packets=0;
135 if (!packets)
137 vorbis_info_init(&vi);
138 vorbis_comment_init(&vc);
140 ogg_stream_pagein(&os,&og);
141 while(ogg_stream_packetout(&os,&op)>0)
143 if (packets<3)
145 if(vorbis_synthesis_headerin(&vi,&vc,&op)<0) return;
147 else
149 float ** pcm;
150 int samples;
151 if(vorbis_synthesis(&vb,&op)==0) vorbis_synthesis_blockin(&vd,&vb);
152 while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0)
154 int n,c;
156 int newsize=(m_samples_used+(samples+4096)*vi.channels)*sizeof(float);
158 if (m_samples.GetSize() < newsize) m_samples.Resize(newsize+32768);
160 float *bufmem = (float *)m_samples.Get();
162 for(n=0;n<samples;n++)
164 for(c=0;c<vi.channels;c++)
166 bufmem[m_samples_used++]=pcm[c][n];
169 vorbis_synthesis_read(&vd,samples);
172 packets++;
173 if (packets==3)
175 vorbis_synthesis_init(&vd,&vi);
176 vorbis_block_init(&vd,&vb);
181 int Available()
183 return m_samples_used;
185 float *Get()
187 return (float *)m_samples.Get();
189 void Skip(int amt)
191 float *sptr=(float *)m_samples.Get();
192 m_samples_used-=amt;
193 if (m_samples_used>0)
194 memcpy(sptr,sptr+amt,m_samples_used*sizeof(float));
195 else m_samples_used=0;
198 void Reset()
200 m_samples_used=0;
202 vorbis_block_clear(&vb);
203 vorbis_dsp_clear(&vd);
204 vorbis_comment_clear(&vc);
205 vorbis_info_clear(&vi);
207 ogg_stream_clear(&os);
208 packets=0;
211 private:
213 WDL_HeapBuf m_samples; // we let the size get as big as it needs to, so we don't worry about tons of mallocs/etc
215 int m_err;
216 int packets;
217 int m_samples_used;
219 ogg_sync_state oy; /* sync and verify incoming physical bitstream */
220 ogg_stream_state os; /* take physical pages, weld into a logical
221 stream of packets */
222 ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
223 ogg_packet op; /* one raw packet of data for decode */
225 vorbis_info vi; /* struct that stores all the static vorbis bitstream
226 settings */
227 vorbis_comment vc; /* struct that stores all the bitstream user comments */
228 vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
229 vorbis_block vb; /* local working space for packet->PCM decode */
232 } WDL_FIXALIGN;
235 class VorbisEncoder : public VorbisEncoderInterface
237 public:
238 #ifdef VORBISENC_WANT_FULLCONFIG
239 VorbisEncoder(int srate, int nch, int serno, float qv, int cbr=-1, int minbr=-1, int maxbr=-1, const char *encname=NULL)
240 #elif defined(VORBISENC_WANT_QVAL)
241 VorbisEncoder(int srate, int nch, float qv, int serno, const char *encname=NULL)
242 #else
243 VorbisEncoder(int srate, int nch, int bitrate, int serno, const char *encname=NULL)
244 #endif
246 m_flushmode=false;
247 m_ds=0;
249 memset(&vi,0,sizeof(vi));
250 memset(&vc,0,sizeof(vc));
251 memset(&vd,0,sizeof(vd));
252 memset(&vb,0,sizeof(vb));
254 m_nch=nch;
255 vorbis_info_init(&vi);
257 #ifdef VORBISENC_WANT_FULLCONFIG
259 if (cbr > 0)
261 m_err=vorbis_encode_init(&vi,nch,srate,maxbr*1000,cbr*1000,minbr*1000);
263 else
264 m_err=vorbis_encode_init_vbr(&vi,nch,srate,qv);
266 #else
268 #ifndef VORBISENC_WANT_QVAL
269 float qv=0.0;
270 if (nch == 2) bitrate= (bitrate*5)/8;
271 // at least for mono 44khz
272 //-0.1 = ~40kbps
273 //0.0 == ~64kbps
274 //0.1 == 75
275 //0.3 == 95
276 //0.5 == 110
277 //0.75== 140
278 //1.0 == 240
279 if (bitrate <= 32)
281 m_ds=1;
282 bitrate*=2;
285 if (bitrate < 40) qv=-0.1f;
286 else if (bitrate < 64) qv=-0.10f + (bitrate-40)*(0.10f/24.0f);
287 else if (bitrate < 75) qv=(bitrate-64)*(0.1f/9.0f);
288 else if (bitrate < 95) qv=0.1f+(bitrate-75)*(0.2f/20.0f);
289 else if (bitrate < 110) qv=0.3f+(bitrate-95)*(0.2f/15.0f);
290 else if (bitrate < 140) qv=0.5f+(bitrate-110)*(0.25f/30.0f);
291 else qv=0.75f+(bitrate-140)*(0.25f/100.0f);
293 if (qv<-0.10f)qv=-0.10f;
294 if (qv>1.0f)qv=1.0f;
295 #endif
297 m_err=vorbis_encode_init_vbr(&vi,nch,srate>>m_ds,qv);
298 #endif
300 vorbis_comment_init(&vc);
301 if (encname) vorbis_comment_add_tag(&vc,"ENCODER",(char *)encname);
302 vorbis_analysis_init(&vd,&vi);
303 vorbis_block_init(&vd,&vb);
304 ogg_stream_init(&os,m_ser=serno);
306 if (m_err) return;
309 reinit(1);
312 void reinit(int bla=0)
314 if (!bla)
316 ogg_stream_clear(&os);
317 vorbis_block_clear(&vb);
318 vorbis_dsp_clear(&vd);
320 vorbis_analysis_init(&vd,&vi);
321 vorbis_block_init(&vd,&vb);
322 ogg_stream_init(&os,m_ser++); //++?
324 outqueue.Advance(outqueue.Available());
325 outqueue.Compact();
329 ogg_packet header;
330 ogg_packet header_comm;
331 ogg_packet header_code;
332 vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
333 ogg_stream_packetin(&os,&header); /* automatically placed in its own page */
334 ogg_stream_packetin(&os,&header_comm);
335 ogg_stream_packetin(&os,&header_code);
337 for (;;)
339 ogg_page og;
340 int result=ogg_stream_flush(&os,&og);
341 if(result==0)break;
342 outqueue.Add(og.header,og.header_len);
343 outqueue.Add(og.body,og.body_len);
347 void Encode(float *in, int inlen, int advance=1, int spacing=1) // length in sample (PAIRS)
349 if (m_err) return;
351 if (inlen == 0)
353 // disable this for now, it fucks us sometimes
354 // maybe we should throw some silence in instead?
355 vorbis_analysis_wrote(&vd,0);
357 else
359 inlen >>= m_ds;
360 float **buffer=vorbis_analysis_buffer(&vd,inlen);
361 int i,i2=0;
363 if (m_nch==1)
365 for (i = 0; i < inlen; i ++)
367 buffer[0][i]=in[i2];
368 i2+=advance<<m_ds;
371 else if (m_nch==2)
373 for (i = 0; i < inlen; i ++)
375 buffer[0][i]=in[i2];
376 buffer[1][i]=in[i2+spacing];
377 i2+=advance<<m_ds;
380 else if (m_nch>2)
382 int n=m_nch;
383 for (i = 0; i < inlen; i ++)
385 int a;
386 int i3=i2;
387 for(a=0;a<n;a++,i3+=spacing)
388 buffer[a][i]=in[i3];
389 i2+=advance<<m_ds;
392 vorbis_analysis_wrote(&vd,i);
395 int eos=0;
396 while(vorbis_analysis_blockout(&vd,&vb)==1)
398 vorbis_analysis(&vb,NULL);
399 vorbis_bitrate_addblock(&vb);
400 ogg_packet op;
402 while(vorbis_bitrate_flushpacket(&vd,&op))
405 ogg_stream_packetin(&os,&op);
407 while (!eos)
409 ogg_page og;
410 int result=m_flushmode ? ogg_stream_flush(&os,&og) : ogg_stream_pageout(&os,&og);
411 if(result==0)break;
412 outqueue.Add(og.header,og.header_len);
413 outqueue.Add(og.body,og.body_len);
414 if(ogg_page_eos(&og)) eos=1;
420 int isError() { return m_err; }
422 int Available()
424 return outqueue.Available();
426 void *Get()
428 return outqueue.Get();
430 void Advance(int amt)
432 outqueue.Advance(amt);
435 void Compact()
437 outqueue.Compact();
440 ~VorbisEncoder()
442 ogg_stream_clear(&os);
443 vorbis_block_clear(&vb);
444 vorbis_dsp_clear(&vd);
445 vorbis_comment_clear(&vc);
446 if (!m_err) vorbis_info_clear(&vi);
449 WDL_Queue outqueue;
451 private:
452 int m_err,m_nch;
454 ogg_stream_state os;
455 vorbis_info vi;
456 vorbis_comment vc;
457 vorbis_dsp_state vd;
458 vorbis_block vb;
459 int m_ser;
460 int m_ds;
462 public:
463 bool m_flushmode;
464 } WDL_FIXALIGN;
466 #endif//WDL_VORBIS_INTERFACE_ONLY
468 #endif//_VORBISENCDEC_H_