Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / adpcm_decode.h
blobf97195c9dd8783c483f2d3275720c929879e021b
1 #ifndef _WDL_ADPCM_DECODE_H_
2 #define _WDL_ADPCM_DECODE_H_
4 #include "queue.h"
6 #define MSADPCM_TYPE 2
7 #define IMAADPCM_TYPE 0x11
8 #define CADPCM2_TYPE 0xac0c
10 class WDL_adpcm_decoder
12 typedef struct
14 int cf1,cf2,deltas,spl1,spl2;
15 } WDL_adpcm_decode_chanctx;
17 public:
18 enum { MSADPCM_PREAMBLELEN=7, IMA_PREAMBLELEN=4 };
19 static INT64 sampleLengthFromBytes(INT64 nbytes, int blockalign, int nch, int type, int bps)
21 if (!bps||type!=CADPCM2_TYPE) bps=4;
22 // remove overhead of headers
23 INT64 nblocks=((nbytes+blockalign-1)/blockalign);
25 // remove preambles
26 if (type==IMAADPCM_TYPE||type==CADPCM2_TYPE) nbytes -= nblocks*IMA_PREAMBLELEN*nch;
27 else nbytes -= nblocks*MSADPCM_PREAMBLELEN*nch;
29 // scale from bytes to samples
30 nbytes = (nbytes*8)/(nch*bps);
32 if (type==IMAADPCM_TYPE||type==CADPCM2_TYPE) nbytes++; // IMA has just one initial sample
33 else nbytes+=2; // msadpcm has 2 initial sample values
35 return nbytes;
38 WDL_adpcm_decoder(int blockalign,int nch, int type, int bps)
40 m_bps=0;
41 m_type=0;
42 m_nch=0;
43 m_blockalign=0;
44 m_srcbuf=0;
45 m_chans=0;
46 setParameters(blockalign,nch,type,bps);
48 ~WDL_adpcm_decoder()
50 free(m_srcbuf);
51 free(m_chans);
55 void resetState()
57 if (m_chans) memset(m_chans,0,m_nch*sizeof(WDL_adpcm_decode_chanctx));
58 m_srcbuf_valid=0;
59 samplesOut.Clear();
60 samplesOut.Compact();
63 void setParameters(int ba, int nch, int type, int bps)
65 if (m_blockalign != ba||nch != m_nch||type!=m_type||bps != m_bps)
67 free(m_srcbuf);
68 free(m_chans);
69 m_bps=bps;
70 m_blockalign=ba;
71 m_nch=nch;
72 m_srcbuf_valid=0;
73 m_srcbuf=(unsigned char*)malloc(ba);
74 m_chans=(WDL_adpcm_decode_chanctx*)malloc(sizeof(WDL_adpcm_decode_chanctx)*nch);
75 m_type=type;
76 resetState();
80 int blockAlign() { return m_blockalign; }
82 int samplesPerBlock()
84 if (m_type==IMAADPCM_TYPE||m_type==CADPCM2_TYPE)
86 if (m_bps == 2) return (m_blockalign/m_nch - IMA_PREAMBLELEN)*4 + 1;
87 return (m_blockalign/m_nch - IMA_PREAMBLELEN)*2 + 1; //4 bit
89 return (m_blockalign/m_nch - MSADPCM_PREAMBLELEN)*2 + 2; // 4 bit
92 INT64 samplesToSourceBytes(INT64 outlen_samples) // length in samplepairs
94 outlen_samples -= samplesOut.Available()/m_nch;
95 if (outlen_samples<1) return 0; // no data required
97 int spls_block = samplesPerBlock();
98 if (spls_block<1) return 0;
99 INT64 nblocks = (outlen_samples+spls_block-1)/spls_block;
100 INT64 v=nblocks * m_blockalign;
102 v -= m_srcbuf_valid;
104 return wdl_max(v,0);
107 void AddInput(void *buf, int len, short *parm_cotab=NULL)
109 unsigned char *rdbuf = (unsigned char *)buf;
110 if (m_srcbuf_valid)
112 int v=m_blockalign-m_srcbuf_valid;
113 if (v>len) v=len;
115 memcpy(m_srcbuf+m_srcbuf_valid,rdbuf,v);
116 len-=v;
117 rdbuf+=v;
118 if ((m_srcbuf_valid+=v)>=m_blockalign)
120 DecodeBlock(m_srcbuf,parm_cotab);
121 m_srcbuf_valid=0;
125 while (len >= m_blockalign)
127 DecodeBlock(rdbuf,parm_cotab);
128 rdbuf+=m_blockalign;
129 len-=m_blockalign;
131 if (len>0) memcpy(m_srcbuf,rdbuf,m_srcbuf_valid=len);
135 int sourceBytesQueued() { return m_srcbuf_valid; }
136 WDL_TypedQueue<short> samplesOut;
138 private:
139 static int getwordsigned(unsigned char **rdptr)
141 int s = (*rdptr)[0] + ((*rdptr)[1]<<8);
142 (*rdptr)+=2;
143 if (s & 0x8000) s -= 0x10000;
144 return s;
147 bool DecodeBlockIMA(unsigned char *buf)
149 int samples_block = samplesPerBlock();
151 int nch=m_nch;
152 int ch;
153 short *outptr = samplesOut.Add(NULL,samples_block * nch);
155 for (ch=0;ch<nch;ch++)
157 m_chans[ch].spl1 = getwordsigned(&buf);
158 m_chans[ch].cf1 = buf[0] | (buf[1]<<8);
159 buf+=2;
162 for (ch=0;ch<nch;ch++) *outptr++ = m_chans[ch].spl1;
164 char bstate=0;
165 unsigned char lastbyte=0;
166 int x;
168 static signed char index_table[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
169 static short step_table[89] = {
170 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
171 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
172 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
173 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
174 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
175 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
176 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
177 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
178 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
182 int splcnt = (samples_block-1)*nch;
183 int cnt=0;
184 ch=0;
185 int wrpos = 0;
187 int bps=m_bps;
188 const int chunksize = bps == 2 ? 16 : 8;
190 for (x=0; x < splcnt; x++)
192 int nib;
194 if (bps==2)
196 switch (bstate++)
198 case 0: nib=(lastbyte=*buf++)<<2; break;
199 case 1: nib=lastbyte; break;
200 case 2: nib=lastbyte>>2; break;
201 default: nib=lastbyte>>4; bstate=0; break;
203 nib &= 8|4;
205 else
207 if ((bstate^=1)) nib=(lastbyte=*buf++)&0xf;
208 else nib=lastbyte>>4;
211 int step_index=m_chans[ch].cf1;
212 if (step_index<0)step_index=0;
213 else if (step_index>88)step_index=88;
215 int step=step_table[step_index];
217 int diff = ((nib&7)*step)/4 + step/8;
219 int v=m_chans[ch].spl1 + ((nib&8) ? -diff : diff);
221 if (v<-32768)v=-32768;
222 else if (v>32767)v=32767;
224 outptr[wrpos]=(short)v;
225 wrpos+=nch;
227 m_chans[ch].spl1=v;
229 m_chans[ch].cf1=step_index + index_table[nib&7];
232 // advance channelcounts
233 if (++cnt==chunksize)
235 if (++ch>=nch)
237 ch=0;
238 outptr += chunksize*nch;
240 wrpos = ch;
241 cnt=0;
245 return true;
248 bool DecodeBlock(unsigned char *buf, short *parm_cotab=NULL)
250 if (m_type==IMAADPCM_TYPE||m_type==CADPCM2_TYPE) return DecodeBlockIMA(buf);
251 static short cotab[14] = { 256,0, 512,-256, 0,0, 192,64, 240, 0,460, -208, 392, -232 };
252 static short adtab[16] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 };
254 short *use_cotab = parm_cotab ? parm_cotab : cotab;
255 int nch = m_nch;
256 int ch;
257 for(ch=0;ch<nch;ch++)
259 unsigned char c=*buf++;
260 if (c > 6) return false;
261 c*=2;
262 m_chans[ch].cf1 = use_cotab[c];
263 m_chans[ch].cf2 = use_cotab[c+1];
265 for(ch=0;ch<nch;ch++) m_chans[ch].deltas = getwordsigned(&buf);
266 for(ch=0;ch<nch;ch++) m_chans[ch].spl1 = getwordsigned(&buf);
267 for(ch=0;ch<nch;ch++) m_chans[ch].spl2 = getwordsigned(&buf);
269 int samples_block = samplesPerBlock();
271 short *outptr = samplesOut.Add(NULL,samples_block * nch);
273 for(ch=0;ch<nch;ch++) *outptr++ = m_chans[ch].spl2;
274 for(ch=0;ch<nch;ch++) *outptr++ = m_chans[ch].spl1;
276 int x;
277 char bstate=0;
278 unsigned char lastbyte;
279 for (x=2; x < samples_block; x++)
281 for(ch=0;ch<nch;ch++)
283 int nib;
284 if ((bstate^=1)) nib=(lastbyte=*buf++)>>4;
285 else nib=lastbyte&0xf;
287 int sn=nib;
288 if (sn & 8) sn -= 16;
290 int pred = ( ((m_chans[ch].spl1 * m_chans[ch].cf1) +
291 (m_chans[ch].spl2 * m_chans[ch].cf2)) / 256) +
292 (sn * m_chans[ch].deltas);
294 m_chans[ch].spl2 = m_chans[ch].spl1;
296 if (pred < -32768) pred=-32768;
297 else if (pred > 32767) pred=32767;
299 *outptr++ = m_chans[ch].spl1 = pred;
301 int i= (adtab[nib] * m_chans[ch].deltas) / 256;
302 if (i <= 16) m_chans[ch].deltas=16;
303 else m_chans[ch].deltas = i;
306 return true;
309 WDL_adpcm_decode_chanctx *m_chans;
310 unsigned char *m_srcbuf;
311 int m_srcbuf_valid;
313 int m_blockalign,m_nch,m_type,m_bps;
319 #endif