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 }