Luski.Net/Luski.net/Sound/Utils.cs

196 lines
6.3 KiB
C#
Raw Normal View History

2023-01-01 22:50:39 -05:00
using System;
namespace Luski.net.Sound
{
internal class Utils
{
internal Utils()
{
}
private const int SIGN_BIT = 0x80;
private const int QUANT_MASK = 0xf;
private const int SEG_SHIFT = 4;
private const int SEG_MASK = 0x70;
private const int BIAS = 0x84;
private const int CLIP = 8159;
private static readonly short[] seg_uend = new short[] { 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF };
internal static int GetBytesPerInterval(uint SamplesPerSecond, int BitsPerSample, int Channels)
{
int blockAlign = ((BitsPerSample * Channels) >> 3);
int bytesPerSec = (int)(blockAlign * SamplesPerSecond);
uint sleepIntervalFactor = 1000 / 20;
int bytesPerInterval = (int)(bytesPerSec / sleepIntervalFactor);
return bytesPerInterval;
}
internal static int MulawToLinear(int ulaw)
{
ulaw = ~ulaw;
int t = ((ulaw & QUANT_MASK) << 3) + BIAS;
t <<= (ulaw & SEG_MASK) >> SEG_SHIFT;
return ((ulaw & SIGN_BIT) > 0 ? (BIAS - t) : (t - BIAS));
}
private static short Search(short val, short[] table, short size)
{
short i;
int index = 0;
for (i = 0; i < size; i++)
{
if (val <= table[index])
{
return (i);
}
index++;
}
return (size);
}
internal static byte Linear2ulaw(short pcm_val)
{
/* Get the sign and the magnitude of the value. */
pcm_val = (short)(pcm_val >> 2);
short mask;
if (pcm_val < 0)
{
pcm_val = (short)-pcm_val;
mask = 0x7F;
}
else
{
mask = 0xFF;
}
/* clip the magnitude */
if (pcm_val > CLIP)
{
pcm_val = CLIP;
}
pcm_val += (BIAS >> 2);
/* Convert the scaled magnitude to segment number. */
short seg = Search(pcm_val, seg_uend, 8);
/*
* Combine the sign, segment, quantization bits;
* and complement the code word.
*/
/* out of range, return maximum value. */
if (seg >= 8)
{
return (byte)(0x7F ^ mask);
}
else
{
byte uval = (byte)((seg << 4) | ((pcm_val >> (seg + 1)) & 0xF));
return ((byte)(uval ^ mask));
}
}
internal static byte[] MuLawToLinear(byte[] bytes, int bitsPerSample, int channels)
{
int blockAlign = channels * bitsPerSample / 8;
byte[] result = new byte[bytes.Length * blockAlign];
for (int i = 0, counter = 0; i < bytes.Length; i++, counter += blockAlign)
{
int value = MulawToLinear(bytes[i]);
byte[] values = BitConverter.GetBytes(value);
switch (bitsPerSample)
{
case 8:
switch (channels)
{
//8 Bit 1 Channel
case 1:
result[counter] = values[0];
break;
//8 Bit 2 Channel
case 2:
result[counter] = values[0];
result[counter + 1] = values[0];
break;
}
break;
case 16:
switch (channels)
{
//16 Bit 1 Channel
case 1:
result[counter] = values[0];
result[counter + 1] = values[1];
break;
//16 Bit 2 Channels
case 2:
result[counter] = values[0];
result[counter + 1] = values[1];
result[counter + 2] = values[0];
result[counter + 3] = values[1];
break;
}
break;
}
}
return result;
}
internal static byte[] LinearToMulaw(byte[] bytes, int bitsPerSample, int channels)
{
int blockAlign = channels * bitsPerSample / 8;
byte[] result = new byte[bytes.Length / blockAlign];
int resultIndex = 0;
for (int i = 0; i < result.Length; i++)
{
switch (bitsPerSample)
{
case 8:
switch (channels)
{
//8 Bit 1 Channel
case 1:
result[i] = Linear2ulaw(bytes[resultIndex]);
resultIndex += 1;
break;
//8 Bit 2 Channel
case 2:
result[i] = Linear2ulaw(bytes[resultIndex]);
resultIndex += 2;
break;
}
break;
case 16:
switch (channels)
{
//16 Bit 1 Channel
case 1:
result[i] = Linear2ulaw(BitConverter.ToInt16(bytes, resultIndex));
resultIndex += 2;
break;
//16 Bit 2 Channels
case 2:
result[i] = Linear2ulaw(BitConverter.ToInt16(bytes, resultIndex));
resultIndex += 4;
break;
}
break;
}
}
return result;
}
}
}