langpackedit: sorting fixes, 0.015 -- from 8f06f769
[wdl.git] / WDL / vorbisencdec.h
blob302711426e3c22250eced935d0d348abea2691d4
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 #include "assocarray.h"
46 #include "lice/lice.h"
48 bool ParseUserDefMetadata(const char *id, const char *val,
49 const char **k, const char **v, int *klen, int *vlen);
50 bool HasScheme(const char *scheme, WDL_StringKeyedArray<char*> *metadata);
51 bool PackFlacPicBase64(WDL_StringKeyedArray<char*> *metadata,
52 int img_w, int img_h, int bpp, WDL_HeapBuf *hb);
54 extern LICE_IBitmap* (*_LICE_LoadImage)(const char* filename, LICE_IBitmap* bmp, bool tryIgnoreExtension);
57 class VorbisDecoderInterface
59 public:
60 virtual ~VorbisDecoderInterface(){}
61 virtual int GetSampleRate()=0;
62 virtual int GetNumChannels()=0;
63 virtual void *DecodeGetSrcBuffer(int srclen)=0;
64 virtual void DecodeWrote(int srclen)=0;
65 virtual void Reset()=0;
66 virtual int Available()=0;
67 virtual float *Get()=0;
68 virtual void Skip(int amt)=0;
69 virtual int GenerateLappingSamples()=0;
72 class VorbisEncoderInterface
74 public:
75 virtual ~VorbisEncoderInterface(){}
76 virtual void Encode(float *in, int inlen, int advance=1, int spacing=1)=0; // length in sample (PAIRS)
77 virtual int isError()=0;
78 virtual int Available()=0;
79 virtual void *Get()=0;
80 virtual void Advance(int)=0;
81 virtual void Compact()=0;
82 virtual void reinit(int bla=0)=0;
86 #ifndef WDL_VORBIS_INTERFACE_ONLY
88 #include "../WDL/queue.h"
89 #include "../WDL/assocarray.h"
91 class VorbisDecoder : public VorbisDecoderInterface
93 public:
94 VorbisDecoder()
96 packets=0;
97 memset(&oy,0,sizeof(oy));
98 memset(&os,0,sizeof(os));
99 memset(&og,0,sizeof(og));
100 memset(&op,0,sizeof(op));
101 memset(&vi,0,sizeof(vi));
102 memset(&vc,0,sizeof(vc));
103 memset(&vd,0,sizeof(vd));
104 memset(&vb,0,sizeof(vb));
107 ogg_sync_init(&oy); /* Now we can read pages */
108 m_err=0;
110 ~VorbisDecoder()
112 ogg_stream_clear(&os);
113 vorbis_block_clear(&vb);
114 vorbis_dsp_clear(&vd);
115 vorbis_comment_clear(&vc);
116 vorbis_info_clear(&vi);
118 ogg_sync_clear(&oy);
121 int GetSampleRate() { return vi.rate; }
122 int GetNumChannels() { return vi.channels?vi.channels:1; }
124 void *DecodeGetSrcBuffer(int srclen)
126 return ogg_sync_buffer(&oy,srclen);
129 void DecodeWrote(int srclen)
131 ogg_sync_wrote(&oy,srclen);
133 while(ogg_sync_pageout(&oy,&og)>0)
135 int serial=ogg_page_serialno(&og);
136 if (!packets) ogg_stream_init(&os,serial);
137 else if (serial!=os.serialno)
139 vorbis_block_clear(&vb);
140 vorbis_dsp_clear(&vd);
141 vorbis_comment_clear(&vc);
142 vorbis_info_clear(&vi);
144 ogg_stream_clear(&os);
145 ogg_stream_init(&os,serial);
146 packets=0;
148 if (!packets)
150 vorbis_info_init(&vi);
151 vorbis_comment_init(&vc);
153 ogg_stream_pagein(&os,&og);
154 while(ogg_stream_packetout(&os,&op)>0)
156 if (packets<3)
158 if(vorbis_synthesis_headerin(&vi,&vc,&op)<0) return;
160 else
162 float ** pcm;
163 int samples;
164 if(vorbis_synthesis(&vb,&op)==0) vorbis_synthesis_blockin(&vd,&vb);
165 while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0)
167 int n,c;
170 float *bufmem = m_buf.Add(NULL,samples*vi.channels);
172 if (bufmem) for(n=0;n<samples;n++)
174 for(c=0;c<vi.channels;c++) *bufmem++=pcm[c][n];
176 vorbis_synthesis_read(&vd,samples);
179 packets++;
180 if (packets==3)
182 vorbis_synthesis_init(&vd,&vi);
183 vorbis_block_init(&vd,&vb);
188 int Available() { return m_buf.Available(); }
189 float *Get() { return m_buf.Get(); }
191 void Skip(int amt)
193 m_buf.Advance(amt);
194 m_buf.Compact();
196 int GenerateLappingSamples()
198 if (vd.pcm_returned<0 ||
199 !vd.vi ||
200 !vd.vi->codec_setup)
202 return 0;
204 float ** pcm;
205 int samples = vorbis_synthesis_lapout(&vd,&pcm);
206 if (samples <= 0) return 0;
207 float *bufmem = m_buf.Add(NULL,samples*vi.channels);
208 if (bufmem) for(int n=0;n<samples;n++)
210 for (int c=0;c<vi.channels;c++) *bufmem++=pcm[c][n];
212 return samples;
215 void Reset()
217 m_buf.Clear();
219 vorbis_block_clear(&vb);
220 vorbis_dsp_clear(&vd);
221 vorbis_comment_clear(&vc);
222 vorbis_info_clear(&vi);
224 ogg_stream_clear(&os);
225 packets=0;
228 private:
230 WDL_TypedQueue<float> m_buf;
232 int m_err;
233 int packets;
235 ogg_sync_state oy; /* sync and verify incoming physical bitstream */
236 ogg_stream_state os; /* take physical pages, weld into a logical
237 stream of packets */
238 ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
239 ogg_packet op; /* one raw packet of data for decode */
241 vorbis_info vi; /* struct that stores all the static vorbis bitstream
242 settings */
243 vorbis_comment vc; /* struct that stores all the bitstream user comments */
244 vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
245 vorbis_block vb; /* local working space for packet->PCM decode */
248 } WDL_FIXALIGN;
251 class VorbisEncoder : public VorbisEncoderInterface
253 public:
254 #ifdef VORBISENC_WANT_FULLCONFIG
255 VorbisEncoder(int srate, int nch, int serno, float qv, int cbr=-1, int minbr=-1, int maxbr=-1,
256 const char *encname=NULL, WDL_StringKeyedArray<char*> *metadata=NULL)
257 #elif defined(VORBISENC_WANT_QVAL)
258 VorbisEncoder(int srate, int nch, float qv, int serno, const char *encname=NULL)
259 #else
260 VorbisEncoder(int srate, int nch, int bitrate, int serno, const char *encname=NULL)
261 #endif
263 m_flushmode=false;
264 m_ds=0;
266 memset(&vi,0,sizeof(vi));
267 memset(&vc,0,sizeof(vc));
268 memset(&vd,0,sizeof(vd));
269 memset(&vb,0,sizeof(vb));
271 m_nch=nch;
272 vorbis_info_init(&vi);
274 #ifdef VORBISENC_WANT_FULLCONFIG
276 if (cbr > 0)
278 const int brlimit = (srate < 11025 ? 32 :
279 srate < 16000 ? 44 :
280 srate < 32000 ? 86 :
281 srate < 44100 ? 190:
282 240) * nch;
283 for (;;)
285 m_err=vorbis_encode_init(&vi,nch,srate,maxbr*1000,cbr*1000,minbr*1000);
286 if (!m_err) break;
288 if (minbr > brlimit) minbr = brlimit;
289 else if (cbr > brlimit) cbr = brlimit;
290 else if (maxbr > brlimit) maxbr = brlimit;
291 else break;
293 // try again with reduced rate
294 vorbis_info_init(&vi);
297 else
298 m_err=vorbis_encode_init_vbr(&vi,nch,srate,qv);
300 #else // VORBISENC_WANT_FULLCONFIG
302 #ifndef VORBISENC_WANT_QVAL
303 float qv=0.0;
304 if (nch == 2) bitrate= (bitrate*5)/8;
305 // at least for mono 44khz
306 //-0.1 = ~40kbps
307 //0.0 == ~64kbps
308 //0.1 == 75
309 //0.3 == 95
310 //0.5 == 110
311 //0.75== 140
312 //1.0 == 240
313 if (bitrate <= 32)
315 m_ds=1;
316 bitrate*=2;
319 if (bitrate < 40) qv=-0.1f;
320 else if (bitrate < 64) qv=-0.10f + (bitrate-40)*(0.10f/24.0f);
321 else if (bitrate < 75) qv=(bitrate-64)*(0.1f/9.0f);
322 else if (bitrate < 95) qv=0.1f+(bitrate-75)*(0.2f/20.0f);
323 else if (bitrate < 110) qv=0.3f+(bitrate-95)*(0.2f/15.0f);
324 else if (bitrate < 140) qv=0.5f+(bitrate-110)*(0.25f/30.0f);
325 else qv=0.75f+(bitrate-140)*(0.25f/100.0f);
327 if (qv<-0.10f)qv=-0.10f;
328 if (qv>1.0f)qv=1.0f;
329 #endif // !VORBISENC_WANT_QVAL
331 m_err=vorbis_encode_init_vbr(&vi,nch,srate>>m_ds,qv);
332 #endif // !VORBISENC_WANT_FULLCONFIG
334 vorbis_comment_init(&vc);
335 if (encname) vorbis_comment_add_tag(&vc,"ENCODER",(char *)encname);
337 #ifdef VORBISENC_WANT_FULLCONFIG
338 if (metadata)
340 char buf[512];
341 for (int i=0; i < metadata->GetSize(); ++i)
343 const char *key;
344 const char *val=metadata->Enumerate(i, &key);
345 if (key && val && key[0] && val[0])
347 if (strncmp(key, "VORBIS:", 7)) continue;
348 key += 7;
350 if (!strncmp(key, "USER", 4))
352 const char *k, *v;
353 int klen, vlen;
354 ParseUserDefMetadata(key, val, &k, &v, &klen, &vlen);
355 lstrcpyn(buf, k, sizeof(buf));
356 for (char *p=buf; *p; ++p) // make vorbis-compliant
358 if (*p < ' ' || *p > '}' || *p == '=' || *p == '~') *p=' ';
360 vorbis_comment_add_tag(&vc, buf, val);
362 else
364 vorbis_comment_add_tag(&vc, key, val);
369 if (HasScheme("FLACPIC", metadata) && _LICE_LoadImage)
371 const char *picfn=metadata->Get("FLACPIC:APIC_FILE");
372 LICE_IBitmap *bmp = picfn && picfn[0] ? _LICE_LoadImage(picfn, NULL, false) : NULL;
373 int img_w = bmp ? bmp->getWidth() : 0, img_h = bmp ? bmp->getHeight() : 0;
374 if (bmp) delete bmp;
375 if (img_w > 0 && img_h > 0)
377 WDL_HeapBuf hb;
378 if (PackFlacPicBase64(metadata, img_w, img_h, 32, &hb) && hb.GetSize())
380 vorbis_comment_add_tag(&vc, "METADATA_BLOCK_PICTURE", (const char*)hb.Get());
386 #endif // VORBISENC_WANT_FULLCONFIG
388 vorbis_analysis_init(&vd,&vi);
389 vorbis_block_init(&vd,&vb);
390 ogg_stream_init(&os,m_ser=serno);
392 if (m_err) return;
395 reinit(1);
398 void reinit(int bla=0)
400 if (!bla)
402 ogg_stream_clear(&os);
403 vorbis_block_clear(&vb);
404 vorbis_dsp_clear(&vd);
406 vorbis_analysis_init(&vd,&vi);
407 vorbis_block_init(&vd,&vb);
408 ogg_stream_init(&os,m_ser++); //++?
410 outqueue.Advance(outqueue.Available());
411 outqueue.Compact();
415 ogg_packet header;
416 ogg_packet header_comm;
417 ogg_packet header_code;
418 vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
419 ogg_stream_packetin(&os,&header); /* automatically placed in its own page */
420 ogg_stream_packetin(&os,&header_comm);
421 ogg_stream_packetin(&os,&header_code);
423 for (;;)
425 ogg_page og;
426 int result=ogg_stream_flush(&os,&og);
427 if(result==0)break;
428 outqueue.Add(og.header,og.header_len);
429 outqueue.Add(og.body,og.body_len);
433 void Encode(float *in, int inlen, int advance=1, int spacing=1) // length in sample (PAIRS)
435 if (m_err) return;
437 if (inlen == 0)
439 // disable this for now, it fucks us sometimes
440 // maybe we should throw some silence in instead?
441 vorbis_analysis_wrote(&vd,0);
443 else
445 inlen >>= m_ds;
446 float **buffer=vorbis_analysis_buffer(&vd,inlen);
447 int i=0,i2=0;
449 if (m_nch==1)
451 for (i = 0; i < inlen; i ++)
453 buffer[0][i]=in[i2];
454 i2+=advance<<m_ds;
457 else if (m_nch==2)
459 for (i = 0; i < inlen; i ++)
461 buffer[0][i]=in[i2];
462 buffer[1][i]=in[i2+spacing];
463 i2+=advance<<m_ds;
466 else if (m_nch>2)
468 int n=m_nch;
469 for (i = 0; i < inlen; i ++)
471 int a;
472 int i3=i2;
473 for(a=0;a<n;a++,i3+=spacing)
474 buffer[a][i]=in[i3];
475 i2+=advance<<m_ds;
478 vorbis_analysis_wrote(&vd,i);
481 int eos=0;
482 while(vorbis_analysis_blockout(&vd,&vb)==1)
484 vorbis_analysis(&vb,NULL);
485 vorbis_bitrate_addblock(&vb);
486 ogg_packet op;
488 while(vorbis_bitrate_flushpacket(&vd,&op))
491 ogg_stream_packetin(&os,&op);
493 while (!eos)
495 ogg_page og;
496 int result=m_flushmode ? ogg_stream_flush(&os,&og) : ogg_stream_pageout(&os,&og);
497 if(result==0)break;
498 outqueue.Add(og.header,og.header_len);
499 outqueue.Add(og.body,og.body_len);
500 if(ogg_page_eos(&og)) eos=1;
506 int isError() { return m_err; }
508 int Available()
510 return outqueue.Available();
512 void *Get()
514 return outqueue.Get();
516 void Advance(int amt)
518 outqueue.Advance(amt);
521 void Compact()
523 outqueue.Compact();
526 ~VorbisEncoder()
528 ogg_stream_clear(&os);
529 vorbis_block_clear(&vb);
530 vorbis_dsp_clear(&vd);
531 vorbis_comment_clear(&vc);
532 if (!m_err) vorbis_info_clear(&vi);
535 WDL_Queue outqueue;
537 private:
538 int m_err,m_nch;
540 ogg_stream_state os;
541 vorbis_info vi;
542 vorbis_comment vc;
543 vorbis_dsp_state vd;
544 vorbis_block vb;
545 int m_ser;
546 int m_ds;
548 public:
549 bool m_flushmode;
551 } WDL_FIXALIGN;
554 #endif//!WDL_VORBIS_INTERFACE_ONLY
556 #endif//_VORBISENCDEC_H_