#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;
}
}
}