hostile-takeover/SpiffLib/AudioFormats.cs
2014-07-06 17:47:28 -07:00

1476 lines
56 KiB
C#

using System;
using System.IO;
using System.Collections;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace SpiffLib
{
/// <summary>
/// Summary description for AudioFormats.
/// </summary>
public class AudioFormats
{
// Fibonacci
static int[] s_anFibonacci = { -34, -21, -13, -8, -5, -3, -2, -1, 0, 1, 2, 3, 5, 8, 13, 21 };
public static byte[] EncodeFibonacciDelta(byte[] abPcm) {
return Encode8BitDelta(abPcm, s_anFibonacci);
}
public static byte[] DecodeFibonacciDelta(byte[] abEncoded) {
return Decode8BitDelta(abEncoded, s_anFibonacci);
}
// Exponential
static int[] s_anExponential = { -128, -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 };
public static byte[] EncodeExponentialDelta(byte[] abPcm) {
return Encode8BitDelta(abPcm, s_anExponential);
}
public static byte[] DecodeExponentialDelta(byte[] abEncoded) {
return Decode8BitDelta(abEncoded, s_anExponential);
}
static byte[] Encode8BitDelta(byte[] abPcm, int[] anDelta) {
byte[] abEncoded = new byte[1 + (abPcm.Length + 1) / 2];
int nLast = (int)abPcm[0];
abEncoded[0] = abPcm[0];
for (int i = 1; i < abPcm.Length; i++) {
// Important - the shortest path to the next sample may be by overflowing or underflowing.
// If this isn't done, the results will be poor.
sbyte sbDelta = (sbyte)(abPcm[i] - nLast);
int iEntry = -1;
int nDiffSmallest = Int32.MaxValue;
for (int j = 0; j < anDelta.Length; j++) {
int nDiff = (anDelta[j] - sbDelta);
if (nDiff < 0)
nDiff = -nDiff;
if (nDiff < nDiffSmallest) {
nDiffSmallest = nDiff;
iEntry = j;
}
}
Debug.Assert(iEntry >= 0 && iEntry <= 15);
if ((i & 1) != 0) {
abEncoded[(i - 1) / 2 + 1] = (byte)((iEntry << 4) + 8);
} else {
abEncoded[(i - 1) / 2 + 1] = (byte)((byte)(abEncoded[(i - 1) / 2 + 1] & 0xf0) | (byte)iEntry);
}
nLast += anDelta[iEntry];
}
return abEncoded;
}
static byte[] Decode8BitDelta(byte[] abEncoded, int[] anDelta) {
byte[] abPcm = new byte[(abEncoded.Length - 1) * 2 + 1];
byte bSample = abEncoded[0];
abPcm[0] = bSample;
for (int i = 1; i < abEncoded.Length; i++) {
bSample += (byte)anDelta[abEncoded[i] >> 4];
abPcm[(i - 1) * 2 + 1] = bSample;
bSample += (byte)anDelta[abEncoded[i] & 0x0f];
abPcm[(i - 1) * 2 + 2] = bSample;
}
return abPcm;
}
// Wrappers
public unsafe static byte[] EncodeImaAdpcm(short[] ashPcm, int cBits, bool fPreClamp) {
byte[] abEncoded = new byte[ashPcm.Length / 2];
short *pshPcm = (short *)Marshal.UnsafeAddrOfPinnedArrayElement(ashPcm, 0);
byte *pbOut = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(abEncoded, 0);
adpcm_state state;
state.valprev = 0;
state.index = 0;
adpcm_coder(pshPcm, pbOut, ashPcm.Length, &state, cBits, fPreClamp);
return abEncoded;
}
public unsafe static short[] DecodeImaAdpcm(byte[] abEncoded, bool fPreClamp) {
short[] ashOut = new short[abEncoded.Length * 2];
byte *pbEncoded = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(abEncoded, 0);
short *pshOut = (short *)Marshal.UnsafeAddrOfPinnedArrayElement(ashOut, 0);
adpcm_state state;
state.valprev = 0;
state.index = 0;
adpcm_decoder(pbEncoded, pshOut, abEncoded.Length * 2, &state, fPreClamp);
return ashOut;
}
// IMD ADPCM
// This implementation Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
// Netherlands.
/* Intel ADPCM step variation table */
static int[] indexTable = new int[16] {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8,
};
static int[] stepsizeTable = new int[89] {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
struct adpcm_state {
public int valprev;
public int index;
};
unsafe static void adpcm_coder(short *indata, byte *outdata, int len, adpcm_state *state, int cBits, bool fPreClamp)
{
short *inp; /* Input buffer pointer */
byte *outp; /* output buffer pointer */
int val; /* Current input sample value */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int diff; /* Difference between val and valprev */
int step; /* Stepsize */
int valpred; /* Predicted output value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int outputbuffer; /* place to keep previous 4-bit value */
int bufferstep; /* toggle between outputbuffer/output */
outp = outdata;
inp = indata;
valpred = state->valprev;
index = state->index;
step = stepsizeTable[index];
outputbuffer = 0;
bufferstep = 1;
for ( ; len > 0 ; len-- ) {
val = *inp++;
/* Step 1 - compute difference with previous value */
diff = val - valpred;
sign = (diff < 0) ? 8 : 0;
if (sign != 0) diff = (-diff);
// If we preclamp, then at decode time we don't need to clamp
// at all. It results in some quantization error however, but
// it is so slight it fails the blind test.
int vpdiffMax = int.MaxValue;
if (fPreClamp) {
if (sign != 0) {
vpdiffMax = valpred - -32768;
} else {
vpdiffMax = 32767 - valpred;
}
}
/* Step 2 - Divide and clamp */
/* Note:
** This code *approximately* computes:
** delta = diff*4/step;
** vpdiff = (delta+0.5)*step/4;
** but in shift step bits are dropped. The net result of this is
** that even if you have fast mul/div hardware you cannot put it to
** good use since the fixup would be too expensive.
*/
delta = 0;
if (fPreClamp) {
vpdiff = 0;
} else {
vpdiff = (step >> 3);
}
if ( diff >= step ) {
delta = 4;
diff -= step;
vpdiff += step;
if (vpdiff > vpdiffMax) {
vpdiff -= step;
delta &= ~4;
}
}
if (cBits > 2) {
step >>= 1;
if ( diff >= step ) {
delta |= 2;
diff -= step;
vpdiff += step;
if (vpdiff > vpdiffMax) {
vpdiff -= step;
delta &= ~2;
}
}
}
if (cBits > 3) {
step >>= 1;
if ( diff >= step ) {
delta |= 1;
vpdiff += step;
if (vpdiff > vpdiffMax) {
vpdiff -= step;
delta &= ~1;
}
}
}
/* Step 3 - Update previous value */
if (sign != 0)
valpred -= vpdiff;
else
valpred += vpdiff;
/* Step 4 - Clamp previous value to 16 bits */
if ( valpred > 32767 ) {
valpred = 32767;
Debug.Assert(!fPreClamp);
} else if ( valpred < -32768 ) {
valpred = -32768;
Debug.Assert(!fPreClamp);
}
/* Step 5 - Assemble value, update index and step values */
delta |= sign;
index += indexTable[delta];
if ( index < 0 ) index = 0;
if ( index > 88 ) index = 88;
step = stepsizeTable[index];
/* Step 6 - Output value */
if (bufferstep != 0 ) {
outputbuffer = (delta << 4) & 0xf0;
} else {
*outp++ = (byte)((delta & 0x0f) | outputbuffer);
}
bufferstep ^= 1;
}
/* Output last step, if needed */
if (bufferstep == 0)
*outp++ = (byte)outputbuffer;
state->valprev = valpred;
state->index = index;
}
unsafe static void adpcm_decoder(byte *indata, short *outdata, int len, adpcm_state *state, bool fPreClamp)
{
byte *inp; /* Input buffer pointer */
short *outp; /* output buffer pointer */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int step; /* Stepsize */
int valpred; /* Predicted value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int inputbuffer; /* place to keep next 4-bit value */
int bufferstep; /* toggle between inputbuffer/input */
outp = outdata;
inp = indata;
valpred = state->valprev;
index = state->index;
step = stepsizeTable[index];
inputbuffer = 0;
bufferstep = 0;
for ( ; len > 0 ; len-- ) {
/* Step 1 - get the delta value */
if (bufferstep != 0) {
delta = inputbuffer & 0xf;
} else {
inputbuffer = *inp++;
delta = (inputbuffer >> 4) & 0xf;
}
bufferstep ^= 1;
/* Step 2 - Find new index value (for later) */
index += indexTable[delta];
if ( index < 0 ) index = 0;
if ( index > 88 ) index = 88;
/* Step 3 - Separate sign and magnitude */
sign = delta & 8;
delta = delta & 7;
/* Step 4 - Compute difference and new predicted value */
/*
** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
** in adpcm_coder.
*/
if (fPreClamp) {
vpdiff = 0;
} else {
vpdiff = step >> 3;
}
if ((delta & 4) != 0) vpdiff += step;
if ((delta & 2) != 0) vpdiff += step>>1;
if ((delta & 1) != 0) vpdiff += step>>2;
if (sign != 0)
valpred -= vpdiff;
else
valpred += vpdiff;
/* Step 5 - clamp output value */
if (!fPreClamp) {
if ( valpred > 32767 )
valpred = 32767;
else if ( valpred < -32768 )
valpred = -32768;
}
/* Step 6 - Update step value */
step = stepsizeTable[index];
/* Step 7 - Output value */
*outp++ = (short)valpred;
}
state->valprev = valpred;
state->index = index;
}
static int[] s_anStepFractions = new int[] {
1,1,1,1,1,2,2,2,2,2,2,3,3,3,4,4,4,5,5,6,6,7,8,8,9,10,11,12,13,15,16,18,20,22,24,26,29,32,35,38,42,46,51,56,62,68,75,82,91,100,110,120,133,146,160,176,194,213,235,258,284,312,344,378,416,458,503,554,609,670,737,811,892,981,1079,1187,1305,1436,1579,1737,1911,2102,2313,2544,2798,3078,3386,3724,4096,
2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,9,9,10,11,13,14,15,17,18,20,22,24,27,30,33,36,39,43,48,52,58,63,70,77,84,93,102,112,124,136,150,165,181,199,219,241,265,292,321,353,388,427,470,517,568,625,687,756,832,915,1007,1107,1218,1340,1474,1621,1783,1961,2158,2373,2611,2872,3159,3475,3822,4205,4625,5088,5596,6156,6772,7449,8192,
4,4,5,5,6,6,7,7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,30,33,37,40,44,49,54,59,65,72,79,87,95,105,115,127,140,154,169,186,204,225,247,272,299,329,362,398,438,482,530,583,641,706,776,854,939,1033,1136,1250,1375,1512,1664,1830,2013,2214,2436,2679,2947,3242,3566,3923,4315,4747,5221,5744,6318,6950,7645,8409,9250,10175,11193,12312,13543,14897,16384,
5,6,7,8,8,9,10,11,12,13,14,16,17,19,21,23,26,28,31,34,38,41,45,50,55,60,66,73,80,89,98,107,118,130,143,157,173,190,209,230,253,278,306,337,371,408,449,494,543,597,657,722,795,875,962,1058,1164,1280,1409,1550,1704,1874,2062,2268,2495,2745,3020,3321,3653,4019,4421,4863,5349,5884,6473,7120,7832,8615,9476,10424,11467,12614,13875,15263,16789,18467,20315,22346,24575,
7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,50,55,60,66,73,80,88,97,107,118,130,143,157,173,190,209,230,253,279,307,337,371,408,449,494,544,598,658,724,796,876,963,1060,1166,1282,1411,1552,1707,1878,2066,2272,2499,2749,3024,3327,3660,4026,4428,4871,5358,5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,15289,16818,18500,20350,22385,24623,27086,29794,32767,
9,10,11,13,14,15,16,18,20,21,24,26,29,31,35,39,43,46,51,56,63,69,75,83,91,100,110,121,134,148,163,179,196,216,238,261,288,316,349,384,421,464,510,561,618,680,748,823,905,995,1095,1204,1325,1458,1603,1764,1940,2134,2348,2583,2840,3124,3436,3780,4159,4575,5033,5535,6089,6698,7368,8105,8915,9806,10788,11866,13053,14359,15794,17374,19111,21023,23125,25438,27981,30779,33858,37243,40959,
11,12,14,15,17,18,20,21,24,26,29,32,35,38,42,47,51,56,62,68,75,83,90,99,110,120,132,146,161,177,195,215,236,260,285,314,345,380,419,461,506,557,612,674,741,816,897,987,1086,1194,1314,1445,1590,1749,1923,2117,2328,2561,2817,3099,3408,3749,4124,4536,4991,5490,6039,6642,7307,8037,8841,9726,10698,11768,12945,14240,15663,17231,18953,20849,22934,25227,27750,30525,33578,36935,40629,44691,49151,
12,14,16,18,19,21,23,25,28,30,33,37,40,44,49,54,60,65,72,79,88,96,105,116,128,140,154,170,187,207,228,250,275,303,333,366,403,443,488,537,590,649,714,786,865,952,1047,1152,1267,1393,1533,1685,1855,2041,2244,2469,2716,2987,3287,3616,3976,4373,4811,5292,5822,6405,7046,7749,8524,9377,10315,11347,12481,13729,15103,16613,18274,20102,22111,24323,26756,29432,32375,35613,39174,43090,47401,52140,57342,
-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-3,-3,-3,-4,-4,-4,-5,-5,-6,-6,-7,-8,-8,-9,-10,-11,-12,-13,-15,-16,-18,-20,-22,-24,-26,-29,-32,-35,-38,-42,-46,-51,-56,-62,-68,-75,-82,-91,-100,-110,-120,-133,-146,-160,-176,-194,-213,-235,-258,-284,-312,-344,-378,-416,-458,-503,-554,-609,-670,-737,-811,-892,-981,-1079,-1187,-1305,-1436,-1579,-1737,-1911,-2102,-2313,-2544,-2798,-3078,-3386,-3724,-4096,
-2,-2,-2,-3,-3,-3,-3,-4,-4,-4,-5,-5,-6,-6,-7,-8,-9,-9,-10,-11,-13,-14,-15,-17,-18,-20,-22,-24,-27,-30,-33,-36,-39,-43,-48,-52,-58,-63,-70,-77,-84,-93,-102,-112,-124,-136,-150,-165,-181,-199,-219,-241,-265,-292,-321,-353,-388,-427,-470,-517,-568,-625,-687,-756,-832,-915,-1007,-1107,-1218,-1340,-1474,-1621,-1783,-1961,-2158,-2373,-2611,-2872,-3159,-3475,-3822,-4205,-4625,-5088,-5596,-6156,-6772,-7449,-8192,
-4,-4,-5,-5,-6,-6,-7,-7,-8,-9,-10,-11,-12,-13,-14,-16,-17,-19,-21,-23,-25,-28,-30,-33,-37,-40,-44,-49,-54,-59,-65,-72,-79,-87,-95,-105,-115,-127,-140,-154,-169,-186,-204,-225,-247,-272,-299,-329,-362,-398,-438,-482,-530,-583,-641,-706,-776,-854,-939,-1033,-1136,-1250,-1375,-1512,-1664,-1830,-2013,-2214,-2436,-2679,-2947,-3242,-3566,-3923,-4315,-4747,-5221,-5744,-6318,-6950,-7645,-8409,-9250,-10175,-11193,-12312,-13543,-14897,-16384,
-5,-6,-7,-8,-8,-9,-10,-11,-12,-13,-14,-16,-17,-19,-21,-23,-26,-28,-31,-34,-38,-41,-45,-50,-55,-60,-66,-73,-80,-89,-98,-107,-118,-130,-143,-157,-173,-190,-209,-230,-253,-278,-306,-337,-371,-408,-449,-494,-543,-597,-657,-722,-795,-875,-962,-1058,-1164,-1280,-1409,-1550,-1704,-1874,-2062,-2268,-2495,-2745,-3020,-3321,-3653,-4019,-4421,-4863,-5349,-5884,-6473,-7120,-7832,-8615,-9476,-10424,-11467,-12614,-13875,-15263,-16789,-18467,-20315,-22346,-24575,
-7,-8,-9,-10,-11,-12,-13,-14,-16,-17,-19,-21,-23,-25,-28,-31,-34,-37,-41,-45,-50,-55,-60,-66,-73,-80,-88,-97,-107,-118,-130,-143,-157,-173,-190,-209,-230,-253,-279,-307,-337,-371,-408,-449,-494,-544,-598,-658,-724,-796,-876,-963,-1060,-1166,-1282,-1411,-1552,-1707,-1878,-2066,-2272,-2499,-2749,-3024,-3327,-3660,-4026,-4428,-4871,-5358,-5894,-6484,-7132,-7845,-8630,-9493,-10442,-11487,-12635,-13899,-15289,-16818,-18500,-20350,-22385,-24623,-27086,-29794,-32767,
-9,-10,-11,-13,-14,-15,-16,-18,-20,-21,-24,-26,-29,-31,-35,-39,-43,-46,-51,-56,-63,-69,-75,-83,-91,-100,-110,-121,-134,-148,-163,-179,-196,-216,-238,-261,-288,-316,-349,-384,-421,-464,-510,-561,-618,-680,-748,-823,-905,-995,-1095,-1204,-1325,-1458,-1603,-1764,-1940,-2134,-2348,-2583,-2840,-3124,-3436,-3780,-4159,-4575,-5033,-5535,-6089,-6698,-7368,-8105,-8915,-9806,-10788,-11866,-13053,-14359,-15794,-17374,-19111,-21023,-23125,-25438,-27981,-30779,-33858,-37243,-40959,
-11,-12,-14,-15,-17,-18,-20,-21,-24,-26,-29,-32,-35,-38,-42,-47,-51,-56,-62,-68,-75,-83,-90,-99,-110,-120,-132,-146,-161,-177,-195,-215,-236,-260,-285,-314,-345,-380,-419,-461,-506,-557,-612,-674,-741,-816,-897,-987,-1086,-1194,-1314,-1445,-1590,-1749,-1923,-2117,-2328,-2561,-2817,-3099,-3408,-3749,-4124,-4536,-4991,-5490,-6039,-6642,-7307,-8037,-8841,-9726,-10698,-11768,-12945,-14240,-15663,-17231,-18953,-20849,-22934,-25227,-27750,-30525,-33578,-36935,-40629,-44691,-49151,
-12,-14,-16,-18,-19,-21,-23,-25,-28,-30,-33,-37,-40,-44,-49,-54,-60,-65,-72,-79,-88,-96,-105,-116,-128,-140,-154,-170,-187,-207,-228,-250,-275,-303,-333,-366,-403,-443,-488,-537,-590,-649,-714,-786,-865,-952,-1047,-1152,-1267,-1393,-1533,-1685,-1855,-2041,-2244,-2469,-2716,-2987,-3287,-3616,-3976,-4373,-4811,-5292,-5822,-6405,-7046,-7749,-8524,-9377,-10315,-11347,-12481,-13729,-15103,-16613,-18274,-20102,-22111,-24323,-26756,-29432,-32375,-35613,-39174,-43090,-47401,-52140,-57342
};
static int[] s_anStepIndexMap = new int[] {
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,
4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,88,88,
6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,88,88,88,88,
8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,88,88,88,88,88,88,
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,
4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,88,88,
6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,88,88,88,88,
8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,88,88,88,88,88,88,88,88
};
public static byte[] EncodeImaAdpcmTableDriven(short[] ashPcm) {
ArrayList alsEncoded = new ArrayList();
short shPredicted = 0;
int nStepIndex = 0;
int[] anStep = new int[2];
for (int i = 0; i < ashPcm.Length; i += 2) {
// Encoded size is a nibble, so 2 per byte
for (int k = 0; k < 2; k++) {
anStep[k] = 0;
if (i + k == ashPcm.Length)
break;
int nDelta = ashPcm[i + k] - shPredicted;
int iStepSmallest = -1;
int nDiffSmallest = int.MaxValue;
for (int j = 0; j < 16; j++) {
int nStepFraction = s_anStepFractions[j * 89 + nStepIndex];
if (shPredicted + nStepFraction < -32768 || shPredicted + nStepFraction > 32767)
continue;
int nDiff = Math.Abs(nStepFraction - nDelta);
if (nDiff < nDiffSmallest) {
nDiffSmallest = nDiff;
iStepSmallest = j;
}
}
anStep[k] = iStepSmallest;
shPredicted += (short)s_anStepFractions[iStepSmallest * 89 + nStepIndex];
nStepIndex = s_anStepIndexMap[iStepSmallest * 89 + nStepIndex];
}
// Add 1 byte to output
alsEncoded.Add((byte)((anStep[0] << 4) | anStep[1]));
}
return (byte[])alsEncoded.ToArray(typeof(byte));
}
public static short[] DecodeImaAdpcmTableDriven(byte[] abIn) {
ArrayList alsPcm = new ArrayList();
short shPredicted = 0;
int nStepIndex = 0;
foreach (byte bT in abIn) {
int nDelta = bT >> 4;
shPredicted += (short)s_anStepFractions[nDelta * 89 + nStepIndex];
alsPcm.Add(shPredicted);
nStepIndex = s_anStepIndexMap[nDelta * 89 + nStepIndex];
nDelta = bT & 0xf;
shPredicted += (short)s_anStepFractions[nDelta * 89 + nStepIndex];
alsPcm.Add(shPredicted);
nStepIndex = s_anStepIndexMap[nDelta * 89 + nStepIndex];
}
return (short[])alsPcm.ToArray(typeof(short));
}
static int[] s_anStepFractions8BitEncode = new int[] {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,4,4,4,5,5,6,6,7,8,8,9,10,11,12,14,15,16,18,20,22,24,26,29,32,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,4,4,5,5,5,6,7,7,8,9,10,11,12,13,14,15,17,19,20,22,25,27,30,33,36,40,44,48,53,58,64,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,49,54,60,66,72,79,87,96,106,116,128,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,4,4,5,5,5,5,6,7,8,8,9,10,11,12,14,14,16,18,20,21,23,26,29,32,35,38,42,46,50,56,61,67,74,81,89,98,108,119,131,144,158,174,191,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,5,5,6,6,7,7,8,9,10,11,12,13,15,16,18,19,21,24,26,28,31,34,38,42,46,50,56,61,67,74,81,89,98,108,119,131,144,158,174,192,211,232,255,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,4,4,4,4,5,5,6,6,8,8,9,9,10,11,13,14,15,16,19,20,23,24,26,30,33,35,39,43,48,53,58,63,70,76,84,93,101,111,123,135,149,164,180,198,218,240,264,290,319,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,5,5,5,5,6,6,8,8,9,9,11,11,12,14,15,17,18,20,23,24,27,29,32,36,39,42,47,51,57,63,69,75,84,92,101,111,122,134,147,162,179,197,216,237,261,288,317,348,383,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,5,5,5,5,7,7,9,9,11,11,12,12,14,16,18,19,21,23,26,28,32,33,37,42,46,49,54,60,67,74,81,88,98,107,117,130,142,156,172,189,208,229,252,277,305,336,369,406,446,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-3,-3,-3,-4,-4,-4,-5,-5,-6,-6,-7,-8,-8,-9,-10,-11,-12,-14,-15,-16,-18,-20,-22,-24,-26,-29,-32,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-3,-3,-3,-3,-4,-4,-5,-5,-5,-6,-7,-7,-8,-9,-10,-11,-12,-13,-14,-15,-17,-19,-20,-22,-25,-27,-30,-33,-36,-40,-44,-48,-53,-58,-64,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-3,-3,-3,-3,-4,-4,-4,-5,-5,-6,-6,-7,-8,-8,-9,-10,-11,-12,-13,-14,-16,-17,-19,-21,-23,-25,-28,-31,-34,-37,-41,-45,-49,-54,-60,-66,-72,-79,-87,-96,-106,-116,-128,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-3,-3,-4,-4,-5,-5,-5,-5,-6,-7,-8,-8,-9,-10,-11,-12,-14,-14,-16,-18,-20,-21,-23,-26,-29,-32,-35,-38,-42,-46,-50,-56,-61,-67,-74,-81,-89,-98,-108,-119,-131,-144,-158,-174,-191,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-3,-3,-3,-3,-4,-4,-5,-5,-6,-6,-7,-7,-8,-9,-10,-11,-12,-13,-15,-16,-18,-19,-21,-24,-26,-28,-31,-34,-38,-42,-46,-50,-56,-61,-67,-74,-81,-89,-98,-108,-119,-131,-144,-158,-174,-192,-211,-232,-255,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-3,-3,-3,-3,-3,-4,-4,-4,-4,-5,-5,-6,-6,-8,-8,-9,-9,-10,-11,-13,-14,-15,-16,-19,-20,-23,-24,-26,-30,-33,-35,-39,-43,-48,-53,-58,-63,-70,-76,-84,-93,-101,-111,-123,-135,-149,-164,-180,-198,-218,-240,-264,-290,-319,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-3,-3,-3,-3,-3,-5,-5,-5,-5,-6,-6,-8,-8,-9,-9,-11,-11,-12,-14,-15,-17,-18,-20,-23,-24,-27,-29,-32,-36,-39,-42,-47,-51,-57,-63,-69,-75,-84,-92,-101,-111,-122,-134,-147,-162,-179,-197,-216,-237,-261,-288,-317,-348,-383,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-4,-4,-4,-4,-4,-5,-5,-5,-5,-7,-7,-9,-9,-11,-11,-12,-12,-14,-16,-18,-19,-21,-23,-26,-28,-32,-33,-37,-42,-46,-49,-54,-60,-67,-74,-81,-88,-98,-107,-117,-130,-142,-156,-172,-189,-208,-229,-252,-277,-305,-336,-369,-406,-446
};
public static byte[] EncodeImaAdpcmTableDriven8Bit(byte[] abPcm) {
ArrayList alsEncoded = new ArrayList();
byte bPredicted = 128;
int nStepIndex = 0;
int[] anStep = new int[2];
for (int i = 0; i < abPcm.Length; i += 2) {
// Encoded size is a nibble, so 2 per byte
for (int k = 0; k < 2; k++) {
anStep[k] = 0;
if (i + k == abPcm.Length)
break;
int nDelta = abPcm[i + k] - bPredicted;
int iStepSmallest = -1;
int nDiffSmallest = int.MaxValue;
for (int j = 0; j < 16; j++) {
int nStepFraction = s_anStepFractions8BitEncode[j * 89 + nStepIndex];
if (bPredicted + nStepFraction < 0 || bPredicted + nStepFraction > 255)
continue;
int nDiff = Math.Abs(nStepFraction - nDelta);
if (nDiff <= nDiffSmallest) {
nDiffSmallest = nDiff;
iStepSmallest = j;
}
}
anStep[k] = iStepSmallest;
bPredicted += (byte)s_anStepFractions8BitEncode[iStepSmallest * 89 + nStepIndex];
nStepIndex = s_anStepIndexMap[iStepSmallest * 89 + nStepIndex];
}
// Add 1 byte to output
alsEncoded.Add((byte)((anStep[0] << 4) | anStep[1]));
}
return (byte[])alsEncoded.ToArray(typeof(byte));
}
static byte[] s_anStepFractions8BitDecode = new byte[] {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,4,4,4,5,5,6,6,7,8,8,9,10,11,12,14,15,16,18,20,22,24,26,29,32,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,4,4,5,5,5,6,7,7,8,9,10,11,12,13,14,15,17,19,20,22,25,27,30,33,36,40,44,48,53,58,64,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,49,54,60,66,72,79,87,96,106,116,128,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,4,4,5,5,5,5,6,7,8,8,9,10,11,12,14,14,16,18,20,21,23,26,29,32,35,38,42,46,50,56,61,67,74,81,89,98,108,119,131,144,158,174,191,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,5,5,6,6,7,7,8,9,10,11,12,13,15,16,18,19,21,24,26,28,31,34,38,42,46,50,56,61,67,74,81,89,98,108,119,131,144,158,174,192,211,232,255,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,4,4,4,4,5,5,6,6,8,8,9,9,10,11,13,14,15,16,19,20,23,24,26,30,33,35,39,43,48,53,58,63,70,76,84,93,101,111,123,135,149,164,180,198,218,240,255,255,255,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,5,5,5,5,6,6,8,8,9,9,11,11,12,14,15,17,18,20,23,24,27,29,32,36,39,42,47,51,57,63,69,75,84,92,101,111,122,134,147,162,179,197,216,237,255,255,255,255,255,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,5,5,5,5,7,7,9,9,11,11,12,12,14,16,18,19,21,23,26,28,32,33,37,42,46,49,54,60,67,74,81,88,98,107,117,130,142,156,172,189,208,229,252,255,255,255,255,255,255,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,254,253,253,253,252,252,252,251,251,250,250,249,248,248,247,246,245,244,242,241,240,238,236,234,232,230,227,224,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,254,253,253,253,253,252,252,251,251,251,250,249,249,248,247,246,245,244,243,242,241,239,237,236,234,231,229,226,223,220,216,212,208,203,198,192,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,254,253,253,253,253,252,252,252,251,251,250,250,249,248,248,247,246,245,244,243,242,240,239,237,235,233,231,228,225,222,219,215,211,207,202,196,190,184,177,169,160,150,140,128,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,254,254,254,254,253,253,252,252,251,251,251,251,250,249,248,248,247,246,245,244,242,242,240,238,236,235,233,230,227,224,221,218,214,210,206,200,195,189,182,175,167,158,148,137,125,112,98,82,65,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,253,253,253,253,252,252,251,251,250,250,249,249,248,247,246,245,244,243,241,240,238,237,235,232,230,228,225,222,218,214,210,206,200,195,189,182,175,167,158,148,137,125,112,98,82,64,45,24,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,253,253,253,253,253,252,252,252,252,251,251,250,250,248,248,247,247,246,245,243,242,241,240,237,236,233,232,230,226,223,221,217,213,208,203,198,193,186,180,172,163,155,145,133,121,107,92,76,58,38,16,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,254,254,254,254,254,254,254,254,254,254,254,253,253,253,253,253,251,251,251,251,250,250,248,248,247,247,245,245,244,242,241,239,238,236,233,232,229,227,224,220,217,214,209,205,199,193,187,181,172,164,155,145,134,122,109,94,77,59,40,19,1,1,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,254,254,254,254,254,254,254,254,254,254,254,252,252,252,252,252,251,251,251,251,249,249,247,247,245,245,244,244,242,240,238,237,235,233,230,228,224,223,219,214,210,207,202,196,189,182,175,168,158,149,139,126,114,100,84,67,48,27,4,1,1,1,1,1,1
};
public static byte[] DecodeImaAdpcmTableDriven8Bit(byte[] abIn) {
ArrayList alsPcm = new ArrayList();
byte bPredicted = 128;
int nStepIndex = 0;
foreach (byte bT in abIn) {
int nDelta = bT >> 4;
bPredicted += s_anStepFractions8BitDecode[nDelta * 89 + nStepIndex];
alsPcm.Add(bPredicted);
nStepIndex = s_anStepIndexMap[nDelta * 89 + nStepIndex];
nDelta = bT & 0xf;
bPredicted += s_anStepFractions8BitDecode[nDelta * 89 + nStepIndex];
alsPcm.Add(bPredicted);
nStepIndex = s_anStepIndexMap[nDelta * 89 + nStepIndex];
}
return (byte[])alsPcm.ToArray(typeof(byte));
}
public static byte[] EncodeYamahaAdpcm(short[] ashPcm) {
ArrayList alsEncoded = new ArrayList();
int nPcmPredicted = 0;
int nStep = 0x7f;
byte bOutput = 0;
for (int ish = 0; ish < ashPcm.Length; ish++) {
//Console.WriteLine("ish: " + ish + " nPcmPredicted: " + nPcmPredicted + " nStep: " + nStep);
//if (ish == 256)
// Debug.Assert(false);
int nPcm = ashPcm[ish];
int nDiff = nPcm - nPcmPredicted;
bool fNegative = false;
if (nDiff < 0) {
fNegative = true;
nDiff = -nDiff;
}
// Get fraction in multiples of 1/4ths. Note by first shifting down by two, resolution is lost.
// I.e. x / 4 * 2 != x / 2.
int cTimes = 0;
int nStep4th = nStep / 4;
int nFracT = nStep4th;
while (cTimes < 7) {
if (nDiff < nFracT)
break;
nFracT += nStep4th;
cTimes++;
}
// Interestingly this "rebuilding" from bits has more precision that the above
// because of the above nStep / 4. The nStep / 2 below has more precision than
// 2 * (nStep / 4). For example 23 / 4 * 2 == 10 vs. 23 / 2 == 11.
int nStepFraction = 0;
if ((cTimes & 1) != 0)
nStepFraction += nStep / 4;
if ((cTimes & 2) != 0)
nStepFraction += nStep / 2;
if ((cTimes & 4) != 0)
nStepFraction += nStep;
nStepFraction += nStep / 8;
// Add to predicted, do range check
byte b = (byte)cTimes;
if (fNegative) {
nPcmPredicted -= nStepFraction;
b |= 8;
} else {
nPcmPredicted += nStepFraction;
}
if (nPcmPredicted > 32767) {
nPcmPredicted = 32767;
} else if (nPcmPredicted < -32768) {
nPcmPredicted = -32768;
}
// Yamaha calcs the next step like this. Same as MS ADPCM in terms of constants used
switch (b & 7) {
case 0:
case 1:
case 2:
case 3:
nStep = nStep * 230 / 256;
break;
case 4:
nStep = nStep * 307 / 256;
break;
case 5:
nStep = nStep * 409 / 256;
break;
case 6:
nStep = nStep * 512 / 256;
break;
case 7:
nStep = nStep * 614 / 256;
break;
}
// Bounds check the step
if (nStep < 0x7f) {
nStep = 0x7f;
} else if (nStep > 0x6000) {
nStep = 0x6000;
}
// Output a byte. Yamaha uses "little endian" nibble order.
if ((ish & 1) == 0) {
bOutput = (byte)(b & 0x0f);
} else {
bOutput |= (byte)((b << 4) & 0xf0);
alsEncoded.Add(bOutput);
}
}
return (byte[])alsEncoded.ToArray(typeof(byte));
}
public static byte[] EncodeYamahaAdpcmFaster(short[] ashPcm) {
ArrayList alsEncoded = new ArrayList();
int nPcmPredicted = 0;
int nStep = 0x7f;
// Encoding test for "fastest" encoding. Essentially this unrolls the conditionals as much as possible.
// This is an algorithmic test before encoding this in assembly language
for (int ish = 0; ish < ashPcm.Length; ish += 2) {
//Console.WriteLine("ish: " + ish + " nPcmPredicted: " + nPcmPredicted + " nStep: " + nStep);
//if (ish == 256)
// Debug.Assert(false);
byte bOut;
int nDiff;
// Low nibble (first sample of byte)
nDiff = ashPcm[ish] - nPcmPredicted;
if (nDiff >= 0) {
// nDiff positive
int nStepT = nStep & ~3;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT = nStepT >> 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x07
nPcmPredicted += nStep + (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 614) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x07;
} else {
// case 0x06
nPcmPredicted += nStep + (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep <<= 1;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x06;
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x05
nPcmPredicted += nStep + nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 409) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x05;
} else {
// case 0x04
nPcmPredicted += nStep + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 307) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x04;
}
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x03
nPcmPredicted += (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x03;
} else {
// case 0x02
nPcmPredicted += (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x02;
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x01
nPcmPredicted += nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x01;
} else {
// case 0x00
nPcmPredicted += (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x00;
}
}
}
} else {
// nDiff negative
nDiff = -nDiff;
int nStepT = nStep & ~3;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x0f
nPcmPredicted -= nStep + (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 614) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x0f;
} else {
// case 0x0e
nPcmPredicted -= nStep + (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep <<= 1;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x0e;
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x0d
nPcmPredicted -= nStep + nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 409) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x0d;
} else {
// case 0x0c
nPcmPredicted -= nStep + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 307) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
bOut = 0x0c;
}
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x0b
nPcmPredicted -= (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x0b;
} else {
// case 0x0a
nPcmPredicted -= (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x0a;
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x09
nPcmPredicted -= nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x09;
} else {
// case 0x08
nPcmPredicted -= (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
bOut = 0x08;
}
}
}
}
// High nibble, second sample of byte
nDiff = ashPcm[ish + 1] - nPcmPredicted;
if (nDiff >= 0) {
// nDiff positive
int nStepT = nStep & ~3;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x07
nPcmPredicted += nStep + (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 614) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0x70 + bOut));
} else {
// case 0x06
nPcmPredicted += nStep + (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep <<= 1;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0x60 + bOut));
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x05
nPcmPredicted += nStep + nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 409) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0x50 + bOut));
} else {
// case 0x04
nPcmPredicted += nStep + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 307) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0x40 + bOut));
}
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x03
nPcmPredicted += (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0x30 + bOut));
} else {
// case 0x02
nPcmPredicted += (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0x20 + bOut));
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x01
nPcmPredicted += nStepT + (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0x10 + bOut));
} else {
// case 0x00
nPcmPredicted += (nStepT >> 1);
if (nPcmPredicted > 32767)
nPcmPredicted = 32767;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0x00 + bOut));
}
}
}
} else {
// nDiff negative
nDiff = -nDiff;
int nStepT = nStep & ~3;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x0f
nPcmPredicted -= nStep + (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 614) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0xf0 + bOut));
} else {
// case 0x0e
nPcmPredicted -= nStep + (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep <<= 1;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0xe0 + bOut));
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x0d
nPcmPredicted -= nStep + nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 409) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0xd0 + bOut));
} else {
// case 0x0c
nPcmPredicted -= nStep + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 307) >> 8;
if (nStep > 0x6000)
nStep = 0x6000;
alsEncoded.Add((byte)(0xc0 + bOut));
}
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
nDiff -= nStepT;
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x0b
nPcmPredicted -= (nStep >> 1) + nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0xb0 + bOut));
} else {
// case 0x0a
nPcmPredicted -= (nStep >> 1) + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0xa0 + bOut));
}
} else {
nStepT >>= 1;
if (nDiff >= nStepT) {
// case 0x09
nPcmPredicted -= nStepT + (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0x90 + bOut));
} else {
// case 0x08
nPcmPredicted -= (nStepT >> 1);
if (nPcmPredicted < -32768)
nPcmPredicted = -32768;
nStep = (nStep * 230) >> 8;
if (nStep < 0x7f)
nStep = 0x7f;
alsEncoded.Add((byte)(0x80 + bOut));
}
}
}
}
}
return (byte[])alsEncoded.ToArray(typeof(byte));
}
public static void Write8BitAdpcmDecodeTable() {
TextWriter tw = new StreamWriter("decode.s");
tw.WriteLine("Decode8BitAdpcm:");
for (int nStepIndex = 0; nStepIndex < 89; nStepIndex++) {
tw.WriteLine("| Step Index " + nStepIndex);
tw.Write(".byte ");
for (int nDelta = 0; nDelta < 16; nDelta++)
tw.Write(s_anStepFractions8BitDecode[nDelta * 89 + nStepIndex] + (nDelta == 15 ? "\n" : ", "));
tw.Write(".word ");
for (int nDelta = 0; nDelta < 16; nDelta++) {
int offCurrentIndex = 48 * nStepIndex;
int nStepIndexNew = s_anStepIndexMap[nDelta * 89 + nStepIndex];
int offNewIndex = 48 * nStepIndexNew;
tw.Write("0x" + ((ushort)(offNewIndex - offCurrentIndex)).ToString("x") + (nDelta == 15 ? "\n" : ", "));
}
}
tw.Close();
}
public static void Write8BitAdpcmDecodeTableC() {
TextWriter tw = new StreamWriter("decode.cpp");
tw.WriteLine("byte gabAdpcmSteppings[89][16] = {");
for (int nStepIndex = 0; nStepIndex < 89; nStepIndex++) {
tw.Write(" ");
for (int nDelta = 0; nDelta < 16; nDelta++)
tw.Write(s_anStepFractions8BitDecode[nDelta * 89 + nStepIndex] + (nDelta == 15 ? ",\n" : ", "));
}
tw.WriteLine("};");
tw.WriteLine("char s_anStepIndexMap[89][16] = {");
for (int nStepIndex = 0; nStepIndex < 89; nStepIndex++) {
tw.Write(" ");
for (int nDelta = 0; nDelta < 16; nDelta++)
tw.Write(s_anStepIndexMap[nDelta * 89 + nStepIndex] + (nDelta == 15 ? ",\n" : ", "));
}
tw.WriteLine("};");
tw.Close();
}
}
class Pcm {
int m_cBits;
int m_hz;
byte[] m_ab;
short[] m_ash;
// See http://www.intersrv.com/~dcross/wavio.html for format info, or
// http://ccrma-www.stanford.edu/courses/422/projects/WaveFormat/
[StructLayout(LayoutKind.Sequential)]
struct FourCC {
public byte b0;
public byte b1;
public byte b2;
public byte b3;
public FourCC(string str) {
b0 = (byte)str[0];
b1 = (byte)str[1];
b2 = (byte)str[2];
b3 = (byte)str[3];
}
};
[StructLayout(LayoutKind.Sequential)]
struct WavFileHeader {
public FourCC fccRIFF;
public uint cbRiffBytes;
public FourCC fccWAVE;
public FourCC fccfmt;
public uint cbfmtBytes;
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort nBitsPerSample;
public FourCC fccdata;
public uint cbdataBytes;
};
unsafe public Pcm (string strWav) {
if (strWav.EndsWith(".wav") || strWav.EndsWith(".WAV")) {
LoadWavFile(strWav);
}
if (strWav.EndsWith(".snd")) {
LoadSndFile(strWav);
}
}
unsafe void LoadWavFile(string strWav) {
BinaryReader brdr = new BinaryReader(new FileStream(strWav, FileMode.Open, FileAccess.Read, FileShare.Read));
byte[] ab = brdr.ReadBytes((int)brdr.BaseStream.Length);
brdr.Close();
WavFileHeader *pwavhdr = (WavFileHeader *)Marshal.UnsafeAddrOfPinnedArrayElement(ab, 0);
bool fOk = true;
if (pwavhdr->wFormatTag != 1)
fOk = false;
if (pwavhdr->nBitsPerSample != 8 && pwavhdr->nBitsPerSample != 16)
fOk = false;
if (!fOk)
throw new Exception("Only support reading 8 / 16 bit raw pcm!");
m_cBits = pwavhdr->nBitsPerSample;
m_hz = (int)pwavhdr->nSamplesPerSec;
int cbSizeType = Marshal.SizeOf(pwavhdr->GetType());
switch (m_cBits) {
case 8:
m_ab = new byte[pwavhdr->cbdataBytes];
for (int i = 0; i < m_ab.Length; i++)
m_ab[i] = ab[i + cbSizeType];
break;
case 16:
m_ash = new short[pwavhdr->cbdataBytes / 2];
for (int i = 0; i < pwavhdr->cbdataBytes; i += 2)
m_ash[i / 2] = (short)(ab[i + cbSizeType] + ab[1 + i + cbSizeType] * 256);
break;
}
}
void LoadSndFile(string strSnd) {
BinaryReader brdr = new BinaryReader(new FileStream(strSnd, FileMode.Open, FileAccess.Read, FileShare.Read));
byte[] ab = brdr.ReadBytes((int)brdr.BaseStream.Length);
brdr.Close();
m_cBits = 8;
m_hz = 8000;
m_ab = new byte[ab.Length - 6];
for (int i = 0; i < m_ab.Length; i++)
m_ab[i] = ab[i + 6];
}
public Pcm(int hz, byte[] ab) {
m_cBits = 8;
m_hz = hz;
m_ab = ab;
}
public Pcm(int hz, short[] ash) {
m_cBits = 16;
m_hz = hz;
m_ash = ash;
}
public int BitsPerSample {
get {
return m_cBits;
}
}
public int Hertz {
get {
return m_hz;
}
}
public byte[] Data8Bit {
get {
return (byte[])m_ab.Clone();
}
set {
m_cBits = 8;
m_ash = null;
m_ab = (byte[])value.Clone();
}
}
public short[] Data16Bit {
get {
return (short[])m_ash.Clone();
}
set {
m_cBits = 16;
m_ab = null;
m_ash = (short[])value.Clone();
}
}
public void ConvertTo16Bit() {
if (m_cBits == 16)
return;
// 8 bit unsigned (0,127==-128,-1 and 128,255==0,127) to
// 16 bit signed (-32768 -> 32767)
short[] ash = new short[m_ab.Length];
for (int i = 0; i < ash.Length; i++) {
ash[i] = (short)((short)m_ab[i] * 256);
ash[i] = (short)(ash[i] ^ 0x8000);
}
Data16Bit = ash;
}
public void ConvertTo8Bit() {
if (m_cBits == 8)
return;
// 16 bit signed (-32768 -> 32767) to
// 8 bit unsigned (0,127==-128,-1 and 128,255==0,127)
byte[] ab = new byte[m_ash.Length];
for (int i = 0; i < ab.Length; i++)
ab[i] = (byte)((m_ash[i] ^ 0x8000) / 256);
Data8Bit = ab;
}
public void SetMaxSize(int cbMax) {
if (m_cBits == 8) {
if (m_ab.Length > cbMax) {
byte[] abT = new byte[32700];
Array.Copy(m_ab, 0, abT, 0, abT.Length);
m_ab = abT;
}
} else {
if (m_ash.Length * 2 > cbMax) {
short[] ashT = new short[cbMax / 2];
Array.Copy(m_ash, 0, ashT, 0, ashT.Length);
m_ash = ashT;
}
}
}
[DllImportAttribute("winmm.dll")]
private static extern int PlaySoundW(IntPtr pbSound, IntPtr hModule, uint fdwSound);
const UInt32 SND_SYNC = 0x0000; // play synchronously (default)
const UInt32 SND_ASYNC = 0x0001; // play asynchronously
const UInt32 SND_NODEFAULT = 0x0002; // silence (!default) if sound not found
const UInt32 SND_MEMORY = 0x0004; // pszSound points to a memory file
const UInt32 SND_LOOP = 0x0008; // loop the sound until next sndPlaySound
const UInt32 SND_NOSTOP = 0x0010; // don't stop any currently playing sound
const UInt32 SND_NOWAIT = 0x00002000; // don't wait if the driver is busy
const UInt32 SND_ALIAS = 0x00010000; // name is a registry alias
const UInt32 SND_ALIAS_ID = 0x00110000; // alias is a predefined ID
const UInt32 SND_FILENAME = 0x00020000; // name is file name
const UInt32 SND_RESOURCE = 0x00040004; // name is resource name or atom
const UInt32 SND_PURGE = 0x0040;
const UInt32 SND_APPLICATION = 0x0080; // look for application specific association
unsafe public void Play() {
// Fill in the header
if (m_ab == null && m_ash == null)
return;
int cbData = m_cBits == 8 ? m_ab.Length : m_ash.Length * 2;
WavFileHeader wavhdr;
wavhdr.fccRIFF = new FourCC("RIFF");
wavhdr.cbRiffBytes = (uint)(Marshal.SizeOf(typeof(WavFileHeader)) - 8 + cbData);
wavhdr.fccWAVE = new FourCC("WAVE");
wavhdr.fccfmt = new FourCC("fmt ");
wavhdr.cbfmtBytes = 16;
wavhdr.wFormatTag = 1;
wavhdr.nChannels = 1;
wavhdr.nSamplesPerSec = (uint)m_hz;
wavhdr.nAvgBytesPerSec = (uint)(m_cBits / 8 * m_hz);
wavhdr.nBlockAlign = (ushort)(m_cBits / 8);
wavhdr.nBitsPerSample = (ushort)m_cBits;
wavhdr.fccdata = new FourCC("data");
wavhdr.cbdataBytes = (uint)cbData;
// Serialize the data
byte[] ab = SerializeStructure(null, &wavhdr, Marshal.SizeOf(wavhdr.GetType()));
switch (m_cBits) {
case 8:
ab = SerializeStructure(ab, (void *)Marshal.UnsafeAddrOfPinnedArrayElement(m_ab, 0), m_ab.Length);
break;
case 16:
ab = SerializeStructure(ab, (void *)Marshal.UnsafeAddrOfPinnedArrayElement(m_ash, 0), m_ash.Length * 2);
break;
}
// Play the sound
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(ab, 0);
int nSuccess = PlaySoundW(ptr, IntPtr.Zero, SND_ASYNC | SND_MEMORY);
Debug.Assert(nSuccess != 0);
}
unsafe static byte[] SerializeStructure(byte[] ab, void *pv, int cb) {
byte *pb = (byte *)pv;
byte[] abNew = null;
if (ab == null) {
abNew = new byte[cb];
for (int i = 0; i < cb; i++)
abNew[i] = pb[i];
} else {
abNew = new byte[ab.Length + cb];
for (int i = 0; i < ab.Length; i++)
abNew[i] = ab[i];
for (int i = 0; i < cb; i++)
abNew[i + ab.Length] = pb[i];
}
return abNew;
}
unsafe public static void PlayWavFile(string strWav) {
// Get the bytes
BinaryReader brdr = new BinaryReader(new FileStream(strWav, FileMode.Open));
byte[] ab = brdr.ReadBytes((int)brdr.BaseStream.Length);
brdr.Close();
// Play the wav
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(ab, 0);
int nSuccess = PlaySoundW(ptr, IntPtr.Zero, SND_ASYNC | SND_MEMORY);
Debug.Assert(nSuccess != 0);
}
public byte[] GetSndEncoding() {
ConvertTo8Bit();
SetMaxSize(32700 * 2);
return AudioFormats.EncodeImaAdpcmTableDriven8Bit(Data8Bit);
}
#if false
static byte[] MassageSample(byte[] abPcm) {
// Need to make sure that the encoded size is a multiple of 2 bytes in size, which means the
// raw size needs to be a multiple of 4 in size, and need to trail the amplitude to 128 to
// reduce click sounds.
byte[] abPcmNew = new byte[(abPcm.Length + 7) & ~3];
// Copy in the existing pcm
Array.Copy(abPcm, 0, abPcmNew, 0, abPcm.Length);
// Perform fade
int cSamplesFade = abPcmNew.Length - abPcm.Length;
int nSampleLast = (int)abPcm[abPcm.Length - 1];
int nStep = -((nSampleLast - 128) / cSamplesFade);
for (int iSample = abPcm.Length; iSample < abPcmNew.Length; iSample++) {
if (iSample == abPcmNew.Length - 1) {
nSampleLast = 0;
} else {
nSampleLast += nStep;
}
abPcmNew[iSample] = (byte)nSampleLast;
}
return abPcmNew;
}
#endif
}
}