#region Header File // // ImaEncoder.cs - IMA audio encoder // // Copyright (C) Javier Valcarce. BSD License #endregion #region Using Statements using System; using System.Diagnostics; #endregion namespace wavutil { /// /// IMA audio codec (Encoder) /// public class ImaEncoder { // Internal state sbyte index; // index for step table __state int pred; // predicted signal (acumulated) __state sbyte[] indexTable = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; short[] deltaTable = { 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}; #region Constructors public ImaEncoder() { // Set initial state index = 0; pred = 0; } #endregion /// /// Encodes a sample /// /// /// public byte Encode(short sample) { int e; // residue, to be quantized int er; // residue, reconstructed byte eq; // residue, quantized (only 4 LSB are used) short step; // quantizer step byte mask; // compute the residue e = sample - pred; // quantize the residue // reconstruct the residue if (e >= 0) eq = 0; else { eq = 8; // set sign bit e = -e; } mask = 4; step = deltaTable[index]; for (int j = 0; j < 3; j++) { if (e >= step) { eq |= mask; e -= step; } step >>= 1; mask >>= 1; } /**/ er = 0; step = deltaTable[index]; if ((eq & 4) != 0) er += step; if ((eq & 2) != 0) er += step >> 1; if ((eq & 1) != 0) er += step >> 2; er += (step >> 3); if ((eq & 8) != 0) er = -er; // accumulate the residue (predicted sample) pred += er; /**/ if (pred > +32767) pred = +32767; else if (pred < -32768) pred = -32768; // update index index += indexTable[eq]; if (index < 00) index = 00; if (index > 88) index = 88; return eq; } /// /// Encodes a sample /// /// /// public byte Encode(double sample) { // clip if (sample > +1.0) sample = +1.0; if (sample < -1.0) sample = -1.0; short s = (short) (sample * 32767); return Encode(s); } /// /// IMA-ADPCM Encoder /// /// Input audio sample 16-bit C2 audio sample array /// Compressed audio array. Each compressed audio sample is a 4-bit code stored /// in the 4 least significant bits of each byte, the other bits are zero public byte[] EncodeOne(short[] ibuf, int offset, int count) { byte[] obuf = new byte[count]; for (int i = 0; i < count; i++) { obuf[i] = Encode(ibuf[offset + i]); } return obuf; } /// /// /// /// /// /// /// public byte[] EncodeOne(double[] ibuf, int offset, int count) { byte[] obuf = new byte[count]; for (int i = 0; i < count; i++) { obuf[i] = Encode(ibuf[offset + i]); } return obuf; } /// /// /// /// /// /// Must be ODD /// public byte[] EncodeTwo(short[] ibuf, int offset, int count) { Debug.Assert(count % 2 == 0); byte[] obuf = new byte[count / 2]; byte s0; byte s1; for (int i = 0; i < count/2; i++) { s0 = Encode(ibuf[offset + 2*i + 0]); s1 = Encode(ibuf[offset + 2*i + 1]); obuf[i] = (byte) ((s1 << 4) | s0); } return obuf; } /// /// /// /// /// /// /// public byte[] EncodeTwo(double[] ibuf, int offset, int count) { Debug.Assert(count % 2 == 0); byte[] obuf = new byte[count / 2]; byte s0; byte s1; for (int i = 0; i < count / 2; i++) { s0 = Encode(ibuf[offset + 2 * i + 0]); s1 = Encode(ibuf[offset + 2 * i + 1]); obuf[i] = (byte)((s1 << 4) | s0); } return obuf; } /// /// Set the internal state /// /// Predicted sample /// Index in the Index-ROM public void SetState(int pred, sbyte index) { this.index = index; this.pred = pred; } /// /// Gets codec's internal state /// /// /// public void GetState(out int pred, out sbyte index) { index = this.index; pred = this.pred; } } }