1 /*
2  * libPCM by László Szerémi.
3  * Copyright under Boost License.
4  */
5 
6 module libPCM.codecs;
7 
8 import std.stdio;
9 
10 import core.stdc.math;
11 import libPCM.utility;
12 
13 package static immutable byte[16] ADPCM_IndexTable = 
14 			[-1, -1, -1, -1, 2, 4, 6, 8, 
15 			 -1, -1, -1, -1, 2, 4, 6, 8];	///For IMA and Dialogic ADPCM
16 package static immutable byte[16] Yamaha_ADPCM_A_IndexTable =
17 			[-1, -1, -1, -1, 2, 5, 7, 9, 
18 			 -1, -1, -1, -1, 2, 5, 7, 9];	///For the Yamaha ADPCM A found in YM2610 and probably other chips
19 package static immutable byte[16] Yamaha_ADPCM_DiffLookup =
20 			[1,  3,  5,  7,  9,  11,  13,  15,
21 			-1, -3, -5, -7, -9, -11, -13, -15];
22 package static immutable byte[4] ADPCM_IndexTable_2Bit = 
23 			[-1, 2,
24 			 -1, 2];
25 package static immutable byte[8] ADPCM_IndexTable_3Bit = 
26 			[-1, -1, 2, 4,
27 			 -1, -1, 2, 4,];
28 package static immutable byte[32] ADPCM_IndexTable_5Bit = 
29 			[-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16
30 			 -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16];
31 package static immutable byte[2][5] XA_ADPCM_Table =
32 			[[0,0],
33 			[60,0],
34 			[115,-52],
35 			[98,-55],
36 			[112,-60]];
37 package static immutable ushort[49] DIALOGIC_ADPCM_StepTable = 
38 			[16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
39 			60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190,	
40 			209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598,
41 			658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552];		///Most OKI and Yamaha chips seems to use this step-table
42 package static immutable ushort[89] IMA_ADPCM_StepTable = 
43 			[7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 
44 			19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 
45 			50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 
46 			130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
47 			337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
48 			876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 
49 			2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
50 			5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 
51 			15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767];
52 package static immutable ushort[16] Yamaha_ADPCM_IndexScale =
53 			[230, 230, 230, 230, 307, 409, 512, 614,
54 			 230, 230, 230, 230, 307, 409, 512, 614];
55 
56 
57 /*
58  * A note on workpads:
59  * Dynamic decode functions use 16 bytes of workpad, consisting of 4 32 bit integers, which is the recommended initialization method to avoid misaligned
60  * integers. For looping an audio sample, you need to back up the workpad at the start of the loop, monitor the third integer (which is the position), then
61  * replace the current workpad's data with the backed up one. This is extremly important with ADPCM as they depend on many local values.
62  * Dynamic encode functions use 32 bytes. In these cases, the 3rd and 6th integers need to be set to zero if working on a fixed length buffer.
63  * Functions meant to be used on a fixed length buffer coming soon.
64  *
65  * None of the functions depend on external libraries or functions, and require no garbage collection.
66  */
67 public @nogc struct DecoderWorkpad{
68 	uint position;
69 	int stepIndex;
70 	int x_nMinusOne;
71 	int predictor;
72 	public @nogc this(uint position, int stepIndex, int x_nMinusOne){
73 		this.position = position;
74 		this.stepIndex = stepIndex;
75 		this.x_nMinusOne = x_nMinusOne;
76 	}
77 }
78 public @nogc struct EncoderWorkpad{
79 	uint position;
80 	uint stepSize;
81 	int stepIndex;
82 	int d_nMinusOne;
83 	DecoderWorkpad dW;
84 	public @nogc this(uint position, uint stepSize, int stepIndex, int d_nMinusOne, DecoderWorkpad dW){
85 		this.position = position;
86 		this.stepIndex = stepIndex;
87 		this.stepSize = stepSize;
88 		this.d_nMinusOne = d_nMinusOne;
89 		this.dW = dW;
90 	}
91 }
92 /**
93  * Dinamically decodes an IMA ADPCM stream.
94  */
95 public @nogc short dynamicDecodeIMAADPCM(ubyte* inputStream, DecoderWorkpad* workpad){
96 	uint stepSize;
97 	int d_n;
98 	ubyte index;
99 	//get the next index
100 	if(workpad.position & 1)
101 		index = *(inputStream) & 0x0F;
102 	else
103 		index = (*(inputStream))>>4;
104 	//calculate the next step size
105 	workpad.stepIndex += ADPCM_IndexTable[index];
106 	//clamp the index data within the steptable's range
107 	if(workpad.stepIndex < 0)
108 		workpad.stepIndex = 0;
109 	else if(workpad.stepIndex > 88)
110 		workpad.stepIndex = 88;
111 	stepSize = IMA_ADPCM_StepTable[workpad.stepIndex];
112 	d_n = ((stepSize) * (index & 0b0100)>>2) + ((stepSize>>1) * (index & 0b0010)>>1) + ((stepSize>>2) * index & 0b0001) + (stepSize>>3);
113 
114 	if(index & 0b1000)
115 		d_n *= -1;
116 	//adding positive feedback value
117 	d_n += workpad.x_nMinusOne;
118 
119 	
120 	workpad.position++;
121 	workpad.x_nMinusOne = d_n;
122 	return cast(short)d_n;
123 }
124 /**
125  * Dinamically decodes an Dialogic ADPCM stream.
126  */
127 public @nogc short dynamicDecodeDialogicADPCM(ubyte* inputStream, DecoderWorkpad* workpad){
128 	uint stepSize;
129 	int d_n;
130 	ubyte index;
131 	//get the next index
132 	if(workpad.position & 1)
133 		index = *(inputStream) & 0x0F;
134 	else
135 		index = (*(inputStream))>>4;
136 	//calculate the next step size
137 	workpad.stepIndex += ADPCM_IndexTable[index];
138 	//clamp the index data within the steptable's range
139 	if(workpad.stepIndex < 0)
140 		workpad.stepIndex = 0;
141 	else if(workpad.stepIndex > 48)
142 		workpad.stepIndex = 48;
143 	stepSize = DIALOGIC_ADPCM_StepTable[workpad.stepIndex];
144 	
145 	d_n = ((stepSize) * (index & 0b0100)>>2) + ((stepSize>>1) * (index & 0b0010)>>1) + ((stepSize>>2) * index & 0b0001) + (stepSize>>3);
146 
147 	if(index & 0b1000)
148 		d_n *= -1;
149 	//adding positive feedback value
150 	d_n += workpad.x_nMinusOne;
151 
152 	workpad.position++;
153 	workpad.x_nMinusOne = d_n;
154 	return cast(short)d_n;
155 }
156 /**
157  * Initializes the index at 16 for Dialogic ADPCM codecs.
158  */
159 public @nogc DecoderWorkpad initializeDialogicADPCMDecoderWorkpad(){
160 	return DecoderWorkpad(0,16,0);
161 }
162 /**
163  * Dynamically decodes a Yamaha ADPCM A stream. Workpad is 16 bytes long, inputStream always points to the first byte.
164  */
165 public @nogc short dynamicDecodeYamahaADPCMA(ubyte* inputStream, DecoderWorkpad* workpad){
166 	uint stepSize;
167 	int d_n;
168 	ubyte index;
169 	//get the next index
170 	if(workpad.position & 1)
171 		index = *(inputStream) & 0x0F;
172 	else
173 		index = (*(inputStream))>>4;
174 	//calculate the next step size
175 	workpad.stepIndex += Yamaha_ADPCM_A_IndexTable[index];
176 	//clamp the index data within the steptable's range
177 	if(workpad.stepIndex < 0)
178 		workpad.stepIndex = 0;
179 	else if(workpad.stepIndex > 48)
180 		workpad.stepIndex = 48;
181 	stepSize = DIALOGIC_ADPCM_StepTable[workpad.stepIndex];
182 	
183 	d_n = ((stepSize) * (index & 0b0100)>>2) + ((stepSize>>1) * (index & 0b0010)>>1) + ((stepSize>>2) * index & 0b0001) + (stepSize>>3);
184 
185 	if(index & 0b1000)
186 		d_n *= -1;
187 	//adding positive feedback value
188 	d_n += workpad.x_nMinusOne;
189 
190 	workpad.position++;
191 	workpad.x_nMinusOne = d_n;
192 	return cast(short)d_n;
193 }
194 /**
195  * Appends 8 bit unsigned PCM to 16 bit signed PCM. Workpad is 16 bytes long, inputStream always points to the first byte.
196  */
197 public @nogc short dynamicDecode8BitPCMUnsigned(ubyte* inputStream, DecoderWorkpad* workpad){
198 	int output = *(inputStream + workpad.position);
199 	output += byte.min;
200 	output *= 256;
201 
202 	workpad.position++;
203 	return cast(short)(output);
204 }
205 /**
206  * Workpad for XA ADPCM decoders
207  */
208 public @nogc struct XAADPCMDecoderWorkpad{
209 	int[8] sample_minusOne;
210 	int[8] sample_minusTwo;
211 	//uint inputOffset;
212 	//uint outputOffset;
213 }
214 /**
215  * Decodes a single unit of XA ADPCM.
216  */
217 public @nogc void unitDecodeXAADPCM(ubyte* inputStream, short* outputStream, int channels, XAADPCMDecoderWorkpad* workpad, int filter, int shift, int unit){
218 	int difference, sample, currentCh = unit & (channels - 1);
219 	
220 	for(int i ; i < 28 ; i++){
221 		difference = inputStream[(unit>>1) + (i * 4)];
222 		difference = unit & 1 ? signExtend(difference>>4, 4) : signExtend(difference, 4);
223 		sample = (difference << shift) + ((workpad.sample_minusOne[currentCh] * XA_ADPCM_Table[filter][0] + workpad.sample_minusTwo[currentCh] * XA_ADPCM_Table[filter][1]) >> 6);
224 		if(sample >= short.max)
225 			sample = short.max;
226 		else if(sample < short.min)
227 			sample = short.min;
228 		workpad.sample_minusTwo[currentCh] = workpad.sample_minusOne[currentCh];
229 		workpad.sample_minusOne[currentCh] = sample;
230 		outputStream[(i * channels) + currentCh + (unit * 28)] = cast(short)sample;
231 	}
232 }
233 /**
234  * Decodes a whole block of XA ADPCM, which outputs (8-channels)*28 samples for each channel.
235  */
236 public @nogc void blockDecodeXAADPCM(ubyte* inputStream, short* outputStream, int channels, XAADPCMDecoderWorkpad* workpad){
237 	int shift, filter, f0, f1;
238 	//inputStream += workpad.inputOffset;
239 	//outputStream += workpad.outputOffset;
240 	for(int unit; unit < 8; unit ++){
241 		//int currentChannel = unit & (channels - 1);
242 		shift = 12 - (inputStream[4 + unit] & 0x0F);
243 		filter = (inputStream[4 + unit])>>4;
244 		if(filter >= XA_ADPCM_Table.length)
245 			filter = 0;
246 		unitDecodeXAADPCM(inputStream + 16, outputStream, channels, workpad, filter, shift, unit);
247 	}
248 }
249 /**
250  * Dinamically encodes a stream with IMA ADPCM. Workpad is 32 bytes long, inputStream and outputStream always points to the first byte.
251  */
252 public @nogc void dynamicEncodeIMAADPCM(short* inputStream, ubyte* outputStream, EncoderWorkpad* workpad){
253 	//int x_nMinusOne = *cast(int*)(workpad + 4);
254 	//uint position = *cast(uint*)(workpad + 8);
255 	//uint stepSize = *cast(uint*)(workpad + 12);
256 	ubyte index;
257 
258 	int d_n = *(inputStream) - workpad.d_nMinusOne; //applying negative feedback to x_n
259 	if(d_n < 0){ 
260 		d_n *=-1; //get the absolute value of d_n
261 		index = 0b1000;	//set the sign if d_n is negative
262 	}
263 	if(d_n >= workpad.stepSize){
264 		index |= 0b0100;
265 		d_n -= workpad.stepSize;
266 	}
267 	workpad.stepSize >>= 1;
268 	if(d_n >= workpad.stepSize){
269 		index |= 0b0010;
270 		d_n -= workpad.stepSize;
271 	}
272 	workpad.stepSize >>= 1;
273 	if(d_n >= workpad.stepSize)
274 		index |= 0b0001;
275 	
276 	//calculate next step size
277 	//int stepIndex = *cast(int*)(workpad);
278 	workpad.stepIndex += ADPCM_IndexTable[index];
279 	//clamp the index data within the steptable's range
280 	if(workpad.stepIndex <= 0)
281 		workpad.stepIndex = 0;
282 	else if(workpad.stepIndex > 88)
283 		workpad.stepIndex = 88;
284 	workpad.stepSize = IMA_ADPCM_StepTable[workpad.stepIndex];
285 	//*cast(int*)(workpad) = stepIndex;
286 
287 	//write the new index into the outputStream
288 	if(workpad.position & 1)
289 		*(outputStream) |= index;
290 	else
291 		*(outputStream) = cast(ubyte)(index<<4);
292 	
293 	//calculate new x_nMinusOne
294 	workpad.d_nMinusOne = dynamicDecodeIMAADPCM(outputStream, &workpad.dW);
295 
296 	workpad.position++;
297 	//*cast(int*)(workpad + 8) = position;
298 }
299 /**
300  * Dinamically encodes a stream with Dialogic ADPCM. Workpad is 32 bytes long, inputStream and outputStream always points to the first byte.
301  */
302 public @nogc void dynamicEncodeDialogicADPCM(short* inputStream, ubyte* outputStream, EncoderWorkpad* workpad){
303 	//int x_nMinusOne = *cast(int*)(workpad + 4);
304 	//uint position = *cast(uint*)(workpad + 8);
305 	//uint stepSize = *cast(uint*)(workpad + 12);
306 	ubyte index;
307 
308 	int d_n = *(inputStream) - workpad.d_nMinusOne; //applying negative feedback to x_n
309 	d_n /= 16;
310 	if(d_n < 0){ 
311 		d_n *=-1; //get the absolute value of d_n
312 		index = 0b1000;	//set the sign if d_n is negative
313 	}
314 	if(d_n >= workpad.stepSize){
315 		index |= 0b0100;
316 		d_n -= workpad.stepSize;
317 	}
318 	workpad.stepSize >>= 1;
319 	if(d_n >= workpad.stepSize){
320 		index |= 0b0010;
321 		d_n -= workpad.stepSize;
322 	}
323 	workpad.stepSize >>= 1;
324 	if(d_n >= workpad.stepSize)
325 		index |= 0b0001;
326 	
327 	//calculate next step size
328 	//int stepIndex = *cast(int*)(workpad);
329 	workpad.stepIndex += ADPCM_IndexTable[index];
330 	//clamp the index data within the steptable's range
331 	if(workpad.stepIndex < 0)
332 		workpad.stepIndex = 0;
333 	else if(workpad.stepIndex > 48)
334 		workpad.stepIndex = 48;
335 	workpad.stepSize = DIALOGIC_ADPCM_StepTable[workpad.stepIndex];
336 	//*cast(int*)(workpad) = stepIndex;
337 
338 	//write the new index into the outputStream
339 	if(workpad.position & 1)
340 		*(outputStream) |= index;
341 	else
342 		*(outputStream) = cast(ubyte)(index<<4);
343 	
344 	//calculate new d_nMinusOne
345 	workpad.d_nMinusOne = dynamicDecodeDialogicADPCM(outputStream, &workpad.dW);
346 
347 	workpad.position++;
348 	//position++;
349 	//*cast(int*)(workpad + 8) = position;
350 }
351 /**
352  * Initializes the index at 16 for Dialogic ADPCM codecs.
353  */
354 public @nogc EncoderWorkpad initializeDialogicADPCMEncoderWorkpad(){
355 	//return [16,0,0,0,16,0,0,0];
356 	return EncoderWorkpad(0, 0, 16, 0 , initializeDialogicADPCMDecoderWorkpad());
357 }
358 /**
359  * Dinamically encodes a stream with Yamaha ADPCM A. Workpad is 32 bytes long, inputStream and outputStream always points to the first byte.
360  */
361 public @nogc void dynamicEncodeYamahaADPCMA(short* inputStream, ubyte* outputStream, EncoderWorkpad* workpad){
362 	//int x_nMinusOne = *cast(int*)(workpad + 4);
363 	//uint position = *cast(uint*)(workpad + 8);
364 	//uint stepSize = *cast(uint*)(workpad + 12);
365 	ubyte index;
366 
367 	int d_n = *(inputStream) - workpad.d_nMinusOne; //applying negative feedback to x_n
368 	d_n /= 16;
369 	if(d_n < 0){ 
370 		d_n *=-1; //get the absolute value of d_n
371 		index = 0b1000;	//set the sign if d_n is negative
372 	}
373 	if(d_n >= workpad.stepSize){
374 		index |= 0b0100;
375 		d_n -= workpad.stepSize;
376 	}
377 	workpad.stepSize >>= 1;
378 	if(d_n >= workpad.stepSize){
379 		index |= 0b0010;
380 		d_n -= workpad.stepSize;
381 	}
382 	workpad.stepSize >>= 1;
383 	if(d_n >= workpad.stepSize)
384 		index |= 0b0001;
385 	
386 	//calculate next step size
387 	//int stepIndex = *cast(int*)(workpad);
388 	workpad.stepIndex += Yamaha_ADPCM_A_IndexTable[index];
389 	//clamp the index data within the steptable's range
390 	if(workpad.stepIndex < 0)
391 		workpad.stepIndex = 0;
392 	else if(workpad.stepIndex > 48)
393 		workpad.stepIndex = 48;
394 	workpad.stepSize = DIALOGIC_ADPCM_StepTable[workpad.stepIndex];
395 	//*cast(int*)(workpad) = stepIndex;
396 
397 	//write the new index into the outputStream
398 	if(workpad.position & 1)
399 		*(outputStream) |= index;
400 	else
401 		*(outputStream) = cast(ubyte)(index<<4);
402 	
403 	//calculate new x_nMinusOne
404 	workpad.d_nMinusOne = dynamicDecodeYamahaADPCMA(outputStream, &workpad.dW);
405 
406 	workpad.position++;
407 	//*cast(int*)(workpad + 8) = position;
408 }
409 /**
410  * Keeper values fo XAADPCM encoding.
411  */
412 public @nogc struct XAADPCMEncoderWorkpad{
413 	int[2][8] sample_MinusOne;
414 	int[2][8] vl;
415 	/*uint inputOffset, outputOffset;
416 	public @nogc void blockIncrement(){
417 		outputOffset += 16 + (28 * 4);
418 		inputOffset += (28 * 8);
419 	}*/
420 }
421 /**
422  * Encodes a unit of XA ADPCM
423  */
424 public @nogc double encodeXAADPCM(int unit, XAADPCMEncoderWorkpad* workpad, byte[2] inputCoEff, 
425 							short* inputStream, ubyte* outputStream, int iostep, int channels, bool vl = false){
426 	int curc = (unit & (channels - 1)) + ((unit >> (channels-1) ) * 28 * channels);
427 	short* ip = inputStream + curc, itop = ip + (channels * 28);
428 	ubyte* op;
429 	int ox = unit;
430 	int d, v; // v0 = workpad.sample_MinusOne[0], v1 = workpad.sample_MinusTwo[1];
431 	double d2 = 0;
432 	int step = 1 << (12 - iostep);
433 	op = outputStream;
434 	for(; ip < itop; ip += channels){
435 		int vlin = (workpad.sample_MinusOne[unit][0] * inputCoEff[0] + workpad.sample_MinusOne[unit][1] * inputCoEff[1]) >> 6, dp, c;
436 		d = *ip - vlin;
437 		dp = d + (step << 3) + (step >> 1);
438 		if(dp > 0){
439 			c = dp / step;
440 			if(c > 15)
441 				c = 15;
442 		}
443 		c -= 8;
444 		dp = c * step;
445 		c &= 0x0F;
446 		v = vlin + dp;
447 		if(v >= short.max)
448 			v = short.max;
449 		else if(v < short.min)
450 			v = short.min;
451 		workpad.sample_MinusOne[unit][1] = workpad.sample_MinusOne[unit][0];
452 		workpad.sample_MinusOne[unit][0] = v;
453 
454 		d = *ip - workpad.sample_MinusOne[unit][0];
455 		d2 += d * d;
456 
457 		if(op){
458 			op[ox >> 1] |= (ox & 1) ? (c << 4) : c;
459 			ox += 8;
460 		}
461 	}
462 	if(vl){
463 		d = workpad.sample_MinusOne[unit][0] - workpad.vl[unit][0];
464 		d2 += d*d;
465 		d = workpad.sample_MinusOne[unit][1] - workpad.vl[unit][1];
466 		d2 += d*d;
467 		d2 /= 30;
468 	}else{
469 		d2 /= 28;
470 	}
471 	return sqrt(d2);
472 }
473 /**
474  * Encodes a block of 16 bit PCM stream into XA ADPCM.
475  */
476 public @nogc void blockEncodeXAADPCM(short* inputStream, ubyte* outputStream, int channels, XAADPCMEncoderWorkpad* workpad, bool vl = false){
477 	int s, smin, k, kmin, unit, c;
478 	double dmin;
479 	/*inputStream += workpad.inputOffset;
480 	outputStream += workpad.outputOffset;*/
481 	for(; unit < 8 ; unit++){
482 		c = unit & (channels - 1);
483 		//set work values to zero
484 		dmin = 0;
485 		kmin = 0;
486 		smin = 0;
487 		for(s = 0 ; s < 13 ; s++){
488 			for(k = 0 ; k < 4 ; k++){
489 				double d = encodeXAADPCM(unit, workpad, XA_ADPCM_Table[k], inputStream + (c << 2), null, s, channels, vl);
490 				if((!s && !k) || d < dmin){
491 					dmin = d;
492 					kmin = k;
493 					smin = s;
494 				}
495 			}
496 		}
497 		outputStream[4+unit] = cast(ubyte)(smin | (kmin<<4));
498 		encodeXAADPCM(unit, workpad, XA_ADPCM_Table[kmin], inputStream, outputStream + 16, smin, channels);
499 	}
500 	*cast(int*)outputStream = (cast(int*)outputStream)[1];
501 	(cast(int*)outputStream)[3] = (cast(int*)outputStream)[2];
502 	//workpad.outputOffset += 16 + (28 * 4);
503 	//workpad.inputOffset += (28 * 8);
504 }
505 /**
506  * Dinamically encodes 16 bit stream into 8 bit. Workpad is 32 bytes long, inputStream and outputStream always points to the first byte.
507  */
508 public @nogc void dynamicEncode8BitPCMUnsigned(short* inputStream, ubyte* outputStream, void* workpad){
509 	uint position = *cast(uint*)(workpad + 8);
510 	int outputValue = *(inputStream + position);
511 	outputValue += short.max;
512 	outputValue /= 256;
513 	*(outputStream + position) = cast(ubyte)outputValue;
514 	position++;
515 	*cast(uint*)(workpad + 8) = position;
516 }
517 /**
518  * Decodes a preexisting stream automatically.
519  */
520 public @nogc void decodeStreamIMAADPCM(ubyte* inputStream, short* outputStream, uint length){
521 	DecoderWorkpad workpad = DecoderWorkpad();
522 	for(uint i ; i < length ; i++){
523 		*(outputStream + i) = dynamicDecodeIMAADPCM(inputStream + (i>>1), &workpad);
524 		//writeln(inputStream,',',outputStream,',',workpad.position,',',workpad.predictor,',',workpad.stepIndex,',',workpad.x_nMinusOne);
525 		
526 		}
527 }
528 /**
529  * Decodes a preexisting stream automatically.
530  */
531 public @nogc void decodeStreamDialogicADPCM(ubyte* inputStream, short* outputStream, uint length){
532 	DecoderWorkpad workpad = initializeDialogicADPCMDecoderWorkpad();
533 	for(uint i ; i < length ; i++){
534 		*(outputStream + i) = dynamicDecodeDialogicADPCM(inputStream + (i>>1), &workpad);
535 		
536 		}
537 }
538 /**
539  * Decodes a preexisting stream automatically.
540  */
541 public @nogc void decodeStreamYamahaADPCMA(ubyte* inputStream, short* outputStream, uint length){
542 	DecoderWorkpad workpad = initializeDialogicADPCMDecoderWorkpad;
543 	for(uint i ; i < length ; i++){
544 		*(outputStream + i) = dynamicDecodeYamahaADPCMA(inputStream + (i>>1), &workpad);
545 		}
546 }
547 /**
548  * Decodes a preexisting stream automatically.
549  */
550 public @nogc void decodeStream8BitPCMUnsigned(ubyte* inputStream, short* outputStream, uint length){
551 	DecoderWorkpad workpad = DecoderWorkpad();
552 	for(uint i ; i < length ; i++){
553 		*(outputStream + i) = dynamicDecode8BitPCMUnsigned(inputStream + i, &workpad);
554 		}
555 }
556 /**
557  * Decodes a preexisting stream automatically.
558  */
559 public @nogc void decodeStreamXAADPCM(ubyte* inputStream, short* outputStream, uint length, int channels){
560 	XAADPCMDecoderWorkpad workpad = XAADPCMDecoderWorkpad();
561 	for(uint i ; i < length ; i+= 28 * 8){
562 		blockDecodeXAADPCM(inputStream, outputStream, channels, &workpad);
563 		inputStream += 16 + (28 * 8);
564 		outputStream += 28 * 8;
565 	}
566 }
567 /**
568  * Encodes a preexisting stream automatically.
569  */
570 public @nogc void encodeStreamIMAADPCM(short* inputStream, ubyte* outputStream, uint length){
571 	EncoderWorkpad workpad = EncoderWorkpad();
572 	for(uint i ; i < length ; i++){
573 		dynamicEncodeIMAADPCM(inputStream, outputStream, &workpad);
574 		//writeln(*inputStream,',',*outputStream,',',workpad.position,',',workpad.d_nMinusOne,',',workpad.stepIndex,',',workpad.stepSize,',',workpad.dW.position,',',workpad.dW.predictor,',',workpad.dW.x_nMinusOne,',',workpad.dW.stepIndex);
575 		inputStream++;
576 		outputStream += i&1;
577 		}
578 }
579 /**
580  * Encodes a preexisting stream automatically.
581  */
582 public @nogc void encodeStreamDialogicADPCM(short* inputStream, ubyte* outputStream, uint length){
583 	EncoderWorkpad workpad = initializeDialogicADPCMEncoderWorkpad();
584 	for(uint i ; i < length ; i++){
585 		dynamicEncodeDialogicADPCM(inputStream, outputStream, &workpad);
586 		inputStream++;
587 		outputStream += i&1;
588 		}
589 	
590 }
591 /**
592  * Encodes a preexisting stream automatically.
593  */
594 public @nogc void encodeStreamYamahaADPCMA(short* inputStream, ubyte* outputStream, uint length){
595 	EncoderWorkpad workpad = initializeDialogicADPCMEncoderWorkpad();
596 	for(uint i ; i < length ; i++){
597 		dynamicEncodeYamahaADPCMA(inputStream, outputStream, &workpad);
598 		inputStream++;
599 		outputStream += i&1;
600 		}
601 	
602 }
603 /**
604  * Encodes a preexisting stream automatically.
605  */
606 public @nogc void encodeStream8BitPCMUnsigned(short* inputStream, ubyte* outputStream, uint length){
607 	EncoderWorkpad workpad = EncoderWorkpad();
608 	for(uint i ; i < length ; i++){
609 		dynamicEncode8BitPCMUnsigned(inputStream, outputStream, &workpad);
610 		inputStream++;
611 		outputStream++;
612 		}
613 }
614 /**
615  * Encodes a stream of XA ADPCM automatically with multi-channel support
616  */
617 public @nogc void encodeStreamXAADPCM(short* inputStream, ubyte* outputStream, uint length, int channels){
618 	XAADPCMEncoderWorkpad workpad = XAADPCMEncoderWorkpad();
619 	uint blockLength = length / channels;
620 	for(uint i ; i < blockLength ; i++){
621 		blockEncodeXAADPCM(inputStream,outputStream,channels,&workpad,true);
622 		//workpad.blockIncrement();
623 		workpad.vl = workpad.sample_MinusOne;
624 		outputStream += 16 + (28 * 8);
625 		inputStream += 28 * 8;
626 	}
627 }