|
using System;
using System.Collections.Generic;
using System.Text;
namespace VoiceEncoder
{
#region G.711 Encoder Classes
namespace G711Audio
{
/// <summary>
/// Turns 16-bit linear PCM values into 8-bit A-law bytes.
/// </summary>
public class ALawEncoder
{
public const int MAX = 0x7fff; //maximum that can be held in 15 bits
/// <summary>
/// An array where the index is the 16-bit PCM input, and the value is
/// the a-law result.
/// </summary>
private static byte[] pcmToALawMap;
static ALawEncoder()
{
pcmToALawMap = new byte[65536];
for (int i = short.MinValue; i <= short.MaxValue; i++)
pcmToALawMap[(i & 0xffff)] = encode(i);
}
/// <summary>
/// Encode one a-law byte from a 16-bit signed integer. protected use only.
/// </summary>
/// <param name="pcm">A 16-bit signed pcm value</param>
/// <returns>A a-law encoded byte</returns>
private static byte encode(int pcm)
{
//Get the sign bit. Shift it for later use without further modification
int sign = (pcm & 0x8000) >> 8;
//If the number is negative, make it positive (now it's a magnitude)
if (sign != 0)
pcm = -pcm;
//The magnitude must fit in 15 bits to avoid overflow
if (pcm > MAX) pcm = MAX;
/* Finding the "exponent"
* Bits:
* 1 2 3 4 5 6 7 8 9 A B C D E F G
* S 7 6 5 4 3 2 1 0 0 0 0 0 0 0 0
* We want to find where the first 1 after the sign bit is.
* We take the corresponding value from the second row as the exponent value.
* (i.e. if first 1 at position 7 -> exponent = 2)
* The exponent is 0 if the 1 is not found in bits 2 through 8.
* This means the exponent is 0 even if the "first 1" doesn't exist.
*/
int exponent = 7;
//Move to the right and decrement exponent until we hit the 1 or the exponent hits 0
for (int expMask = 0x4000; (pcm & expMask) == 0 && exponent > 0; exponent--, expMask >>= 1) { }
/* The last part - the "mantissa"
* We need to take the four bits after the 1 we just found.
* To get it, we shift 0x0f :
* 1 2 3 4 5 6 7 8 9 A B C D E F G
* S 0 0 0 0 0 1 . . . . . . . . . (say that exponent is 2)
* . . . . . . . . . . . . 1 1 1 1
* We shift it 5 times for an exponent of two, meaning
* we will shift our four bits (exponent + 3) bits.
* For convenience, we will actually just shift the number, then AND with 0x0f.
*
* NOTE: If the exponent is 0:
* 1 2 3 4 5 6 7 8 9 A B C D E F G
* S 0 0 0 0 0 0 0 Z Y X W V U T S (we know nothing about bit 9)
* . . . . . . . . . . . . 1 1 1 1
* We want to get ZYXW, which means a shift of 4 instead of 3
*/
int mantissa = (pcm >> ((exponent == 0) ? 4 : (exponent + 3))) & 0x0f;
//The a-law byte bit arrangement is SEEEMMMM (Sign, Exponent, and Mantissa.)
byte alaw = (byte)(sign | exponent << 4 | mantissa);
//Last is to flip every other bit, and the sign bit (0xD5 = 1101 0101)
return (byte)(alaw ^ 0xD5);
}
/// <summary>
/// Encode a pcm value into a a-law byte
/// </summary>
/// <param name="pcm">A 16-bit pcm value</param>
/// <returns>A a-law encoded byte</returns>
public static byte ALawEncode(int pcm)
{
return pcmToALawMap[pcm & 0xffff];
}
/// <summary>
/// Encode a pcm value into a a-law byte
/// </summary>
/// <param name="pcm">A 16-bit pcm value</param>
/// <returns>A a-law encoded byte</returns>
public static byte ALawEncode(short pcm)
{
return pcmToALawMap[pcm & 0xffff];
}
/// <summary>
/// Encode an array of pcm values
/// </summary>
/// <param name="data">An array of 16-bit pcm values</param>
/// <returns>An array of a-law bytes containing the results</returns>
public static byte[] ALawEncode(int[] data)
{
int size = data.Length;
byte[] encoded = new byte[size];
for (int i = 0; i < size; i++)
encoded[i] = ALawEncode(data[i]);
return encoded;
}
/// <summary>
/// Encode an array of pcm values
/// </summary>
/// <param name="data">An array of 16-bit pcm values</param>
/// <returns>An array of a-law bytes containing the results</returns>
public static byte[] ALawEncode(short[] data)
{
int size = data.Length;
byte[] encoded = new byte[size];
for (int i = 0; i < size; i++)
encoded[i] = ALawEncode(data[i]);
return encoded;
}
/// <summary>
/// Encode an array of pcm values
/// </summary>
/// <param name="data">An array of bytes in Little-Endian format</param>
/// <returns>An array of a-law bytes containing the results</returns>
public static byte[] ALawEncode(byte[] data)
{
int size = data.Length / 2;
byte[] encoded = new byte[size];
for (int i = 0; i < size; i++)
encoded[i] = ALawEncode((data[2 * i + 1] << 8) | data[2 * i]);
return encoded;
}
/// <summary>
/// Encode an array of pcm values into a pre-allocated target array
/// </summary>
/// <param name="data">An array of bytes in Little-Endian format</param>
/// <param name="target">A pre-allocated array to receive the A-law bytes. This array must be at least half the size of the source.</param>
public static void ALawEncode(byte[] data, byte[] target)
{
int size = data.Length / 2;
for (int i = 0; i < size; i++)
target[i] = ALawEncode((data[2 * i + 1] << 8) | data[2 * i]);
}
}
/// <summary>
/// Turns 8-bit A-law bytes back into 16-bit PCM values.
/// </summary>
public static class ALawDecoder
{
/// <summary>
/// An array where the index is the a-law input, and the value is
/// the 16-bit PCM result.
/// </summary>
private static short[] aLawToPcmMap;
static ALawDecoder()
{
aLawToPcmMap = new short[256];
for (byte i = 0; i < byte.MaxValue; i++)
aLawToPcmMap[i] = decode(i);
}
/// <summary>
/// Decode one a-law byte. For protected use only.
/// </summary>
/// <param name="alaw">The encoded a-law byte</param>
/// <returns>A short containing the 16-bit result</returns>
private static short decode(byte alaw)
{
//Invert every other bit, and the sign bit (0xD5 = 1101 0101)
alaw ^= 0xD5;
//Pull out the value of the sign bit
int sign = alaw & 0x80;
//Pull out and shift over the value of the exponent
int exponent = (alaw & 0x70) >> 4;
//Pull out the four bits of data
int data = alaw & 0x0f;
//Shift the data four bits to the left
data <<= 4;
//Add 8 to put the result in the middle of the range (like adding a half)
data += 8;
//If the exponent is not 0, then we know the four bits followed a 1,
//and can thus add this implicit 1 with 0x100.
if (exponent != 0)
data += 0x100;
/* Shift the bits to where they need to be: left (exponent - 1) places
* Why (exponent - 1) ?
* 1 2 3 4 5 6 7 8 9 A B C D E F G
* . 7 6 5 4 3 2 1 . . . . . . . . <-- starting bit (based on exponent)
* . . . . . . . Z x x x x 1 0 0 0 <-- our data (Z is 0 only when exponent is 0)
* We need to move the one under the value of the exponent,
* which means it must move (exponent - 1) times
* It also means shifting is unnecessary if exponent is 0 or 1.
*/
if (exponent > 1)
data <<= (exponent - 1);
return (short)(sign == 0 ? data : -data);
}
/// <summary>
/// Decode one a-law byte
/// </summary>
/// <param name="alaw">The encoded a-law byte</param>
/// <returns>A short containing the 16-bit result</returns>
public static short ALawDecode(byte alaw)
{
return aLawToPcmMap[alaw];
}
/// <summary>
/// Decode an array of a-law encoded bytes
/// </summary>
/// <param name="data">An array of a-law encoded bytes</param>
/// <returns>An array of shorts containing the results</returns>
public static short[] ALawDecode(byte[] data)
{
int size = data.Length;
short[] decoded = new short[size];
for (int i = 0; i < size; i++)
decoded[i] = aLawToPcmMap[data[i]];
return decoded;
}
/// <summary>
/// Decode an array of a-law encoded bytes
/// </summary>
/// <param name="data">An array of a-law encoded bytes</param>
/// <param name="decoded">An array of shorts containing the results</param>
/// <remarks>Same as the other method that returns an array of shorts</remarks>
public static void ALawDecode(byte[] data, out short[] decoded)
{
int size = data.Length;
decoded = new short[size];
for (int i = 0; i < size; i++)
decoded[i] = aLawToPcmMap[data[i]];
}
/// <summary>
/// Decode an array of a-law encoded bytes
/// </summary>
/// <param name="data">An array of a-law encoded bytes</param>
/// <param name="decoded">An array of bytes in Little-Endian format containing the results</param>
public static void ALawDecode(byte[] data, out byte[] decoded)
{
int size = data.Length;
decoded = new byte[size * 2];
for (int i = 0; i < size; i++)
{
//First byte is the less significant byte
decoded[2 * i] = (byte)(aLawToPcmMap[data[i]] & 0xff);
//Second byte is the more significant byte
decoded[2 * i + 1] = (byte)(aLawToPcmMap[data[i]] >> 8);
}
}
}
}
#endregion G.711 Encoding
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.