mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
Refactoring of CUETools.Codecs.
This commit is contained in:
484
CUETools.Codecs/AudioBuffer.cs
Normal file
484
CUETools.Codecs/AudioBuffer.cs
Normal file
@@ -0,0 +1,484 @@
|
||||
using System;
|
||||
|
||||
namespace CUETools.Codecs
|
||||
{
|
||||
public class AudioBuffer
|
||||
{
|
||||
#region Static Methods
|
||||
|
||||
public static unsafe void FLACSamplesToBytes_16(int[,] inSamples, int inSampleOffset,
|
||||
byte* outSamples, int sampleCount, int channelCount)
|
||||
{
|
||||
int loopCount = sampleCount * channelCount;
|
||||
|
||||
if (inSamples.GetLength(0) - inSampleOffset < sampleCount)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
fixed (int* pInSamplesFixed = &inSamples[inSampleOffset, 0])
|
||||
{
|
||||
int* pInSamples = pInSamplesFixed;
|
||||
short* pOutSamples = (short*)outSamples;
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
pOutSamples[i] = (short)pInSamples[i];
|
||||
//*(pOutSamples++) = (short)*(pInSamples++);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void FLACSamplesToBytes_16(int[,] inSamples, int inSampleOffset,
|
||||
byte[] outSamples, int outByteOffset, int sampleCount, int channelCount)
|
||||
{
|
||||
int loopCount = sampleCount * channelCount;
|
||||
|
||||
if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) ||
|
||||
(outSamples.Length - outByteOffset < loopCount * 2))
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
fixed (byte* pOutSamplesFixed = &outSamples[outByteOffset])
|
||||
FLACSamplesToBytes_16(inSamples, inSampleOffset, pOutSamplesFixed, sampleCount, channelCount);
|
||||
}
|
||||
|
||||
public static unsafe void FLACSamplesToBytes_24(int[,] inSamples, int inSampleOffset,
|
||||
byte[] outSamples, int outByteOffset, int sampleCount, int channelCount, int wastedBits)
|
||||
{
|
||||
int loopCount = sampleCount * channelCount;
|
||||
|
||||
if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) ||
|
||||
(outSamples.Length - outByteOffset < loopCount * 3))
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
fixed (int* pInSamplesFixed = &inSamples[inSampleOffset, 0])
|
||||
{
|
||||
fixed (byte* pOutSamplesFixed = &outSamples[outByteOffset])
|
||||
{
|
||||
int* pInSamples = pInSamplesFixed;
|
||||
byte* pOutSamples = pOutSamplesFixed;
|
||||
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
{
|
||||
uint sample_out = (uint)*(pInSamples++) << wastedBits;
|
||||
*(pOutSamples++) = (byte)(sample_out & 0xFF);
|
||||
sample_out >>= 8;
|
||||
*(pOutSamples++) = (byte)(sample_out & 0xFF);
|
||||
sample_out >>= 8;
|
||||
*(pOutSamples++) = (byte)(sample_out & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void FloatToBytes_16(float[,] inSamples, int inSampleOffset,
|
||||
byte[] outSamples, int outByteOffset, int sampleCount, int channelCount)
|
||||
{
|
||||
int loopCount = sampleCount * channelCount;
|
||||
|
||||
if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) ||
|
||||
(outSamples.Length - outByteOffset < loopCount * 2))
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
fixed (float* pInSamplesFixed = &inSamples[inSampleOffset, 0])
|
||||
{
|
||||
fixed (byte* pOutSamplesFixed = &outSamples[outByteOffset])
|
||||
{
|
||||
float* pInSamples = pInSamplesFixed;
|
||||
short* pOutSamples = (short*)pOutSamplesFixed;
|
||||
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
{
|
||||
*(pOutSamples++) = (short)(32758 * (*(pInSamples++)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void FloatToBytes(float[,] inSamples, int inSampleOffset,
|
||||
byte[] outSamples, int outByteOffset, int sampleCount, int channelCount, int bitsPerSample)
|
||||
{
|
||||
if (bitsPerSample == 16)
|
||||
FloatToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount);
|
||||
//else if (bitsPerSample > 16 && bitsPerSample <= 24)
|
||||
// FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount, 24 - bitsPerSample);
|
||||
else if (bitsPerSample == 32)
|
||||
Buffer.BlockCopy(inSamples, inSampleOffset * 4 * channelCount, outSamples, outByteOffset, sampleCount * 4 * channelCount);
|
||||
else
|
||||
throw new Exception("Unsupported bitsPerSample value");
|
||||
}
|
||||
|
||||
public static unsafe void FLACSamplesToBytes(int[,] inSamples, int inSampleOffset,
|
||||
byte[] outSamples, int outByteOffset, int sampleCount, int channelCount, int bitsPerSample)
|
||||
{
|
||||
if (bitsPerSample == 16)
|
||||
FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount);
|
||||
else if (bitsPerSample > 16 && bitsPerSample <= 24)
|
||||
FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount, 24 - bitsPerSample);
|
||||
else
|
||||
throw new Exception("Unsupported bitsPerSample value");
|
||||
}
|
||||
|
||||
public static unsafe void FLACSamplesToBytes(int[,] inSamples, int inSampleOffset,
|
||||
byte* outSamples, int sampleCount, int channelCount, int bitsPerSample)
|
||||
{
|
||||
if (bitsPerSample == 16)
|
||||
FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, sampleCount, channelCount);
|
||||
else
|
||||
throw new Exception("Unsupported bitsPerSample value");
|
||||
}
|
||||
|
||||
public static unsafe void Bytes16ToFloat(byte[] inSamples, int inByteOffset,
|
||||
float[,] outSamples, int outSampleOffset, int sampleCount, int channelCount)
|
||||
{
|
||||
int loopCount = sampleCount * channelCount;
|
||||
|
||||
if ((inSamples.Length - inByteOffset < loopCount * 2) ||
|
||||
(outSamples.GetLength(0) - outSampleOffset < sampleCount))
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
fixed (byte* pInSamplesFixed = &inSamples[inByteOffset])
|
||||
{
|
||||
fixed (float* pOutSamplesFixed = &outSamples[outSampleOffset, 0])
|
||||
{
|
||||
short* pInSamples = (short*)pInSamplesFixed;
|
||||
float* pOutSamples = pOutSamplesFixed;
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
*(pOutSamples++) = *(pInSamples++) / 32768.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void BytesToFLACSamples_16(byte[] inSamples, int inByteOffset,
|
||||
int[,] outSamples, int outSampleOffset, int sampleCount, int channelCount)
|
||||
{
|
||||
int loopCount = sampleCount * channelCount;
|
||||
|
||||
if ((inSamples.Length - inByteOffset < loopCount * 2) ||
|
||||
(outSamples.GetLength(0) - outSampleOffset < sampleCount))
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
fixed (byte* pInSamplesFixed = &inSamples[inByteOffset])
|
||||
{
|
||||
fixed (int* pOutSamplesFixed = &outSamples[outSampleOffset, 0])
|
||||
{
|
||||
short* pInSamples = (short*)pInSamplesFixed;
|
||||
int* pOutSamples = pOutSamplesFixed;
|
||||
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
{
|
||||
*(pOutSamples++) = (int)*(pInSamples++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void BytesToFLACSamples_24(byte[] inSamples, int inByteOffset,
|
||||
int[,] outSamples, int outSampleOffset, int sampleCount, int channelCount, int wastedBits)
|
||||
{
|
||||
int loopCount = sampleCount * channelCount;
|
||||
|
||||
if ((inSamples.Length - inByteOffset < loopCount * 3) ||
|
||||
(outSamples.GetLength(0) - outSampleOffset < sampleCount))
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
fixed (byte* pInSamplesFixed = &inSamples[inByteOffset])
|
||||
{
|
||||
fixed (int* pOutSamplesFixed = &outSamples[outSampleOffset, 0])
|
||||
{
|
||||
byte* pInSamples = (byte*)pInSamplesFixed;
|
||||
int* pOutSamples = pOutSamplesFixed;
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
{
|
||||
int sample = (int)*(pInSamples++);
|
||||
sample += (int)*(pInSamples++) << 8;
|
||||
sample += (int)*(pInSamples++) << 16;
|
||||
*(pOutSamples++) = (sample << 8) >> (8 + wastedBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void BytesToFLACSamples(byte[] inSamples, int inByteOffset,
|
||||
int[,] outSamples, int outSampleOffset, int sampleCount, int channelCount, int bitsPerSample)
|
||||
{
|
||||
if (bitsPerSample == 16)
|
||||
BytesToFLACSamples_16(inSamples, inByteOffset, outSamples, outSampleOffset, sampleCount, channelCount);
|
||||
else if (bitsPerSample > 16 && bitsPerSample <= 24)
|
||||
BytesToFLACSamples_24(inSamples, inByteOffset, outSamples, outSampleOffset, sampleCount, channelCount, 24 - bitsPerSample);
|
||||
else
|
||||
throw new Exception("Unsupported bitsPerSample value");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private int[,] samples;
|
||||
private float[,] fsamples;
|
||||
private byte[] bytes;
|
||||
private int length;
|
||||
private int size;
|
||||
private AudioPCMConfig pcm;
|
||||
private bool dataInSamples = false;
|
||||
private bool dataInBytes = false;
|
||||
private bool dataInFloat = false;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return length; }
|
||||
set { length = value; }
|
||||
}
|
||||
|
||||
public int Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public AudioPCMConfig PCM { get { return pcm; } }
|
||||
|
||||
public int ByteLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return length * pcm.BlockAlign;
|
||||
}
|
||||
}
|
||||
|
||||
public int[,] Samples
|
||||
{
|
||||
get
|
||||
{
|
||||
if (samples == null || samples.GetLength(0) < length)
|
||||
samples = new int[size, pcm.ChannelCount];
|
||||
if (!dataInSamples && dataInBytes && length != 0)
|
||||
BytesToFLACSamples(bytes, 0, samples, 0, length, pcm.ChannelCount, pcm.BitsPerSample);
|
||||
dataInSamples = true;
|
||||
return samples;
|
||||
}
|
||||
}
|
||||
|
||||
public float[,] Float
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fsamples == null || fsamples.GetLength(0) < length)
|
||||
fsamples = new float[size, pcm.ChannelCount];
|
||||
if (!dataInFloat && dataInBytes && length != 0)
|
||||
{
|
||||
if (pcm.BitsPerSample == 16)
|
||||
Bytes16ToFloat(bytes, 0, fsamples, 0, length, pcm.ChannelCount);
|
||||
//else if (pcm.BitsPerSample > 16 && PCM.BitsPerSample <= 24)
|
||||
// BytesToFLACSamples_24(bytes, 0, fsamples, 0, length, pcm.ChannelCount, 24 - pcm.BitsPerSample);
|
||||
else if (pcm.BitsPerSample == 32)
|
||||
Buffer.BlockCopy(bytes, 0, fsamples, 0, length * 4 * pcm.ChannelCount);
|
||||
else
|
||||
throw new Exception("Unsupported bitsPerSample value");
|
||||
}
|
||||
dataInFloat = true;
|
||||
return fsamples;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Bytes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (bytes == null || bytes.Length < length * pcm.BlockAlign)
|
||||
bytes = new byte[size * pcm.BlockAlign];
|
||||
if (!dataInBytes && length != 0)
|
||||
{
|
||||
if (dataInSamples)
|
||||
FLACSamplesToBytes(samples, 0, bytes, 0, length, pcm.ChannelCount, pcm.BitsPerSample);
|
||||
else if (dataInFloat)
|
||||
FloatToBytes(fsamples, 0, bytes, 0, length, pcm.ChannelCount, pcm.BitsPerSample);
|
||||
}
|
||||
dataInBytes = true;
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
public AudioBuffer(AudioPCMConfig _pcm, int _size)
|
||||
{
|
||||
pcm = _pcm;
|
||||
size = _size;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
public AudioBuffer(AudioPCMConfig _pcm, int[,] _samples, int _length)
|
||||
{
|
||||
pcm = _pcm;
|
||||
// assert _samples.GetLength(1) == pcm.ChannelCount
|
||||
Prepare(_samples, _length);
|
||||
}
|
||||
|
||||
public AudioBuffer(AudioPCMConfig _pcm, byte[] _bytes, int _length)
|
||||
{
|
||||
pcm = _pcm;
|
||||
Prepare(_bytes, _length);
|
||||
}
|
||||
|
||||
public AudioBuffer(IAudioSource source, int _size)
|
||||
{
|
||||
pcm = source.PCM;
|
||||
size = _size;
|
||||
}
|
||||
|
||||
public void Prepare(IAudioDest dest)
|
||||
{
|
||||
if (dest.PCM.ChannelCount != pcm.ChannelCount || dest.PCM.BitsPerSample != pcm.BitsPerSample)
|
||||
throw new Exception("AudioBuffer format mismatch");
|
||||
}
|
||||
|
||||
public void Prepare(IAudioSource source, int maxLength)
|
||||
{
|
||||
if (source.PCM.ChannelCount != pcm.ChannelCount || source.PCM.BitsPerSample != pcm.BitsPerSample)
|
||||
throw new Exception("AudioBuffer format mismatch");
|
||||
length = size;
|
||||
if (maxLength >= 0)
|
||||
length = Math.Min(length, maxLength);
|
||||
if (source.Remaining >= 0)
|
||||
length = (int)Math.Min((long)length, source.Remaining);
|
||||
dataInBytes = false;
|
||||
dataInSamples = false;
|
||||
dataInFloat = false;
|
||||
}
|
||||
|
||||
public void Prepare(int maxLength)
|
||||
{
|
||||
length = size;
|
||||
if (maxLength >= 0)
|
||||
length = Math.Min(length, maxLength);
|
||||
dataInBytes = false;
|
||||
dataInSamples = false;
|
||||
dataInFloat = false;
|
||||
}
|
||||
|
||||
public void Prepare(int[,] _samples, int _length)
|
||||
{
|
||||
length = _length;
|
||||
size = _samples.GetLength(0);
|
||||
samples = _samples;
|
||||
dataInSamples = true;
|
||||
dataInBytes = false;
|
||||
dataInFloat = false;
|
||||
if (length > size)
|
||||
throw new Exception("Invalid length");
|
||||
}
|
||||
|
||||
public void Prepare(byte[] _bytes, int _length)
|
||||
{
|
||||
length = _length;
|
||||
size = _bytes.Length / PCM.BlockAlign;
|
||||
bytes = _bytes;
|
||||
dataInSamples = false;
|
||||
dataInBytes = true;
|
||||
dataInFloat = false;
|
||||
if (length > size)
|
||||
throw new Exception("Invalid length");
|
||||
}
|
||||
|
||||
internal unsafe void Load(int dstOffset, AudioBuffer src, int srcOffset, int copyLength)
|
||||
{
|
||||
if (dataInBytes)
|
||||
Buffer.BlockCopy(src.Bytes, srcOffset * pcm.BlockAlign, Bytes, dstOffset * pcm.BlockAlign, copyLength * pcm.BlockAlign);
|
||||
if (dataInSamples)
|
||||
Buffer.BlockCopy(src.Samples, srcOffset * pcm.ChannelCount * 4, Samples, dstOffset * pcm.ChannelCount * 4, copyLength * pcm.ChannelCount * 4);
|
||||
if (dataInFloat)
|
||||
Buffer.BlockCopy(src.Float, srcOffset * pcm.ChannelCount * 4, Float, dstOffset * pcm.ChannelCount * 4, copyLength * pcm.ChannelCount * 4);
|
||||
}
|
||||
|
||||
public unsafe void Prepare(AudioBuffer _src, int _offset, int _length)
|
||||
{
|
||||
length = Math.Min(size, _src.Length - _offset);
|
||||
if (_length >= 0)
|
||||
length = Math.Min(length, _length);
|
||||
dataInBytes = false;
|
||||
dataInFloat = false;
|
||||
dataInSamples = false;
|
||||
if (_src.dataInBytes)
|
||||
dataInBytes = true;
|
||||
else if (_src.dataInSamples)
|
||||
dataInSamples = true;
|
||||
else if (_src.dataInFloat)
|
||||
dataInFloat = true;
|
||||
Load(0, _src, _offset, length);
|
||||
}
|
||||
|
||||
public void Swap(AudioBuffer buffer)
|
||||
{
|
||||
if (pcm.BitsPerSample != buffer.PCM.BitsPerSample || pcm.ChannelCount != buffer.PCM.ChannelCount)
|
||||
throw new Exception("AudioBuffer format mismatch");
|
||||
|
||||
int[,] samplesTmp = samples;
|
||||
float[,] floatsTmp = fsamples;
|
||||
byte[] bytesTmp = bytes;
|
||||
|
||||
fsamples = buffer.fsamples;
|
||||
samples = buffer.samples;
|
||||
bytes = buffer.bytes;
|
||||
length = buffer.length;
|
||||
size = buffer.size;
|
||||
dataInSamples = buffer.dataInSamples;
|
||||
dataInBytes = buffer.dataInBytes;
|
||||
dataInFloat = buffer.dataInFloat;
|
||||
|
||||
buffer.samples = samplesTmp;
|
||||
buffer.bytes = bytesTmp;
|
||||
buffer.fsamples = floatsTmp;
|
||||
buffer.length = 0;
|
||||
buffer.dataInSamples = false;
|
||||
buffer.dataInBytes = false;
|
||||
buffer.dataInFloat = false;
|
||||
}
|
||||
|
||||
unsafe public void Interlace(int pos, int* src1, int* src2, int n)
|
||||
{
|
||||
if (PCM.ChannelCount != 2)
|
||||
{
|
||||
throw new Exception("Must be stereo");
|
||||
}
|
||||
if (PCM.BitsPerSample == 16)
|
||||
{
|
||||
fixed (byte* bs = Bytes)
|
||||
{
|
||||
int* res = ((int*)bs) + pos;
|
||||
for (int i = n; i > 0; i--)
|
||||
*(res++) = (*(src1++) & 0xffff) ^ (*(src2++) << 16);
|
||||
}
|
||||
}
|
||||
else if (PCM.BitsPerSample == 24)
|
||||
{
|
||||
fixed (byte* bs = Bytes)
|
||||
{
|
||||
byte* res = bs + pos * 6;
|
||||
for (int i = n; i > 0; i--)
|
||||
{
|
||||
uint sample_out = (uint)*(src1++);
|
||||
*(res++) = (byte)(sample_out & 0xFF);
|
||||
sample_out >>= 8;
|
||||
*(res++) = (byte)(sample_out & 0xFF);
|
||||
sample_out >>= 8;
|
||||
*(res++) = (byte)(sample_out & 0xFF);
|
||||
sample_out = (uint)*(src2++);
|
||||
*(res++) = (byte)(sample_out & 0xFF);
|
||||
sample_out >>= 8;
|
||||
*(res++) = (byte)(sample_out & 0xFF);
|
||||
sample_out >>= 8;
|
||||
*(res++) = (byte)(sample_out & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unsupported BPS");
|
||||
}
|
||||
}
|
||||
|
||||
//public void Clear()
|
||||
//{
|
||||
// length = 0;
|
||||
//}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user