Create FUNDING.yml
[wdl/wdl-ol.git] / WDL / vorbisencdec.h
blob771d7cca2c4970c24ef9d84c8a90ecfac5e26ad5
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"
78 class VorbisDecoder : public VorbisDecoderInterface
80 public:
81 VorbisDecoder()
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;
157 float *bufmem = m_buf.Add(NULL,samples*vi.channels);
159 if (bufmem) for(n=0;n<samples;n++)
161 for(c=0;c<vi.channels;c++) *bufmem++=pcm[c][n];
163 vorbis_synthesis_read(&vd,samples);
166 packets++;
167 if (packets==3)
169 vorbis_synthesis_init(&vd,&vi);
170 vorbis_block_init(&vd,&vb);
175 int Available() { return m_buf.Available(); }
176 float *Get() { return m_buf.Get(); }
178 void Skip(int amt)
180 m_buf.Advance(amt);
181 m_buf.Compact();
184 void Reset()
186 m_buf.Clear();
188 vorbis_block_clear(&vb);
189 vorbis_dsp_clear(&vd);
190 vorbis_comment_clear(&vc);
191 vorbis_info_clear(&vi);
193 ogg_stream_clear(&os);
194 packets=0;
197 private:
199 WDL_TypedQueue<float> m_buf;
201 int m_err;
202 int packets;
204 ogg_sync_state oy; /* sync and verify incoming physical bitstream */
205 ogg_stream_state os; /* take physical pages, weld into a logical
206 stream of packets */
207 ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
208 ogg_packet op; /* one raw packet of data for decode */
210 vorbis_info vi; /* struct that stores all the static vorbis bitstream
211 settings */
212 vorbis_comment vc; /* struct that stores all the bitstream user comments */
213 vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
214 vorbis_block vb; /* local working space for packet->PCM decode */
217 } WDL_FIXALIGN;
220 class VorbisEncoder : public VorbisEncoderInterface
222 public:
223 #ifdef VORBISENC_WANT_FULLCONFIG
224 VorbisEncoder(int srate, int nch, int serno, float qv, int cbr=-1, int minbr=-1, int maxbr=-1, const char *encname=NULL)
225 #elif defined(VORBISENC_WANT_QVAL)
226 VorbisEncoder(int srate, int nch, float qv, int serno, const char *encname=NULL)
227 #else
228 VorbisEncoder(int srate, int nch, int bitrate, int serno, const char *encname=NULL)
229 #endif
231 m_flushmode=false;
232 m_ds=0;
234 memset(&vi,0,sizeof(vi));
235 memset(&vc,0,sizeof(vc));
236 memset(&vd,0,sizeof(vd));
237 memset(&vb,0,sizeof(vb));
239 m_nch=nch;
240 vorbis_info_init(&vi);
242 #ifdef VORBISENC_WANT_FULLCONFIG
244 if (cbr > 0)
246 m_err=vorbis_encode_init(&vi,nch,srate,maxbr*1000,cbr*1000,minbr*1000);
248 else
249 m_err=vorbis_encode_init_vbr(&vi,nch,srate,qv);
251 #else
253 #ifndef VORBISENC_WANT_QVAL
254 float qv=0.0;
255 if (nch == 2) bitrate= (bitrate*5)/8;
256 // at least for mono 44khz
257 //-0.1 = ~40kbps
258 //0.0 == ~64kbps
259 //0.1 == 75
260 //0.3 == 95
261 //0.5 == 110
262 //0.75== 140
263 //1.0 == 240
264 if (bitrate <= 32)
266 m_ds=1;
267 bitrate*=2;
270 if (bitrate < 40) qv=-0.1f;
271 else if (bitrate < 64) qv=-0.10f + (bitrate-40)*(0.10f/24.0f);
272 else if (bitrate < 75) qv=(bitrate-64)*(0.1f/9.0f);
273 else if (bitrate < 95) qv=0.1f+(bitrate-75)*(0.2f/20.0f);
274 else if (bitrate < 110) qv=0.3f+(bitrate-95)*(0.2f/15.0f);
275 else if (bitrate < 140) qv=0.5f+(bitrate-110)*(0.25f/30.0f);
276 else qv=0.75f+(bitrate-140)*(0.25f/100.0f);
278 if (qv<-0.10f)qv=-0.10f;
279 if (qv>1.0f)qv=1.0f;
280 #endif
282 m_err=vorbis_encode_init_vbr(&vi,nch,srate>>m_ds,qv);
283 #endif
285 vorbis_comment_init(&vc);
286 if (encname) vorbis_comment_add_tag(&vc,"ENCODER",(char *)encname);
287 vorbis_analysis_init(&vd,&vi);
288 vorbis_block_init(&vd,&vb);
289 ogg_stream_init(&os,m_ser=serno);
291 if (m_err) return;
294 reinit(1);
297 void reinit(int bla=0)
299 if (!bla)
301 ogg_stream_clear(&os);
302 vorbis_block_clear(&vb);
303 vorbis_dsp_clear(&vd);
305 vorbis_analysis_init(&vd,&vi);
306 vorbis_block_init(&vd,&vb);
307 ogg_stream_init(&os,m_ser++); //++?
309 outqueue.Advance(outqueue.Available());
310 outqueue.Compact();
314 ogg_packet header;
315 ogg_packet header_comm;
316 ogg_packet header_code;
317 vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
318 ogg_stream_packetin(&os,&header); /* automatically placed in its own page */
319 ogg_stream_packetin(&os,&header_comm);
320 ogg_stream_packetin(&os,&header_code);
322 for (;;)
324 ogg_page og;
325 int result=ogg_stream_flush(&os,&og);
326 if(result==0)break;
327 outqueue.Add(og.header,og.header_len);
328 outqueue.Add(og.body,og.body_len);
332 void Encode(float *in, int inlen, int advance=1, int spacing=1) // length in sample (PAIRS)
334 if (m_err) return;
336 if (inlen == 0)
338 // disable this for now, it fucks us sometimes
339 // maybe we should throw some silence in instead?
340 vorbis_analysis_wrote(&vd,0);
342 else
344 inlen >>= m_ds;
345 float **buffer=vorbis_analysis_buffer(&vd,inlen);
346 int i=0,i2=0;
348 if (m_nch==1)
350 for (i = 0; i < inlen; i ++)
352 buffer[0][i]=in[i2];
353 i2+=advance<<m_ds;
356 else if (m_nch==2)
358 for (i = 0; i < inlen; i ++)
360 buffer[0][i]=in[i2];
361 buffer[1][i]=in[i2+spacing];
362 i2+=advance<<m_ds;
365 else if (m_nch>2)
367 int n=m_nch;
368 for (i = 0; i < inlen; i ++)
370 int a;
371 int i3=i2;
372 for(a=0;a<n;a++,i3+=spacing)
373 buffer[a][i]=in[i3];
374 i2+=advance<<m_ds;
377 vorbis_analysis_wrote(&vd,i);
380 int eos=0;
381 while(vorbis_analysis_blockout(&vd,&vb)==1)
383 vorbis_analysis(&vb,NULL);
384 vorbis_bitrate_addblock(&vb);
385 ogg_packet op;
387 while(vorbis_bitrate_flushpacket(&vd,&op))
390 ogg_stream_packetin(&os,&op);
392 while (!eos)
394 ogg_page og;
395 int result=m_flushmode ? ogg_stream_flush(&os,&og) : ogg_stream_pageout(&os,&og);
396 if(result==0)break;
397 outqueue.Add(og.header,og.header_len);
398 outqueue.Add(og.body,og.body_len);
399 if(ogg_page_eos(&og)) eos=1;
405 int isError() { return m_err; }
407 int Available()
409 return outqueue.Available();
411 void *Get()
413 return outqueue.Get();
415 void Advance(int amt)
417 outqueue.Advance(amt);
420 void Compact()
422 outqueue.Compact();
425 ~VorbisEncoder()
427 ogg_stream_clear(&os);
428 vorbis_block_clear(&vb);
429 vorbis_dsp_clear(&vd);
430 vorbis_comment_clear(&vc);
431 if (!m_err) vorbis_info_clear(&vi);
434 WDL_Queue outqueue;
436 private:
437 int m_err,m_nch;
439 ogg_stream_state os;
440 vorbis_info vi;
441 vorbis_comment vc;
442 vorbis_dsp_state vd;
443 vorbis_block vb;
444 int m_ser;
445 int m_ds;
447 public:
448 bool m_flushmode;
449 } WDL_FIXALIGN;
451 #endif//WDL_VORBIS_INTERFACE_ONLY
453 #endif//_VORBISENCDEC_H_