diff --git a/CUETools.Codecs/AudioBuffer.cs b/CUETools.Codecs/AudioBuffer.cs new file mode 100644 index 0000000..016ecbb --- /dev/null +++ b/CUETools.Codecs/AudioBuffer.cs @@ -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; + //} + } +} diff --git a/CUETools.Codecs/AudioDecoderClass.cs b/CUETools.Codecs/AudioDecoderClass.cs new file mode 100644 index 0000000..1e4b392 --- /dev/null +++ b/CUETools.Codecs/AudioDecoderClass.cs @@ -0,0 +1,42 @@ +using System; + +namespace CUETools.Codecs +{ + /// + /// This class provides an attribute for marking + /// classes that provide . + /// + /// + /// When plugins with classes that provide are + /// registered, their attributes are read. + /// + /// + /// using CUETools.Codecs; + /// + ///[AudioDecoderClass("libFLAC", "flac")] + ///public class MyDecoder : IAudioSource { + /// ... + ///} + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public sealed class AudioDecoderClass : Attribute + { + private string _decoderName, _extension; + + public string DecoderName + { + get { return _decoderName; } + } + + public string Extension + { + get { return _extension; } + } + + public AudioDecoderClass(string decoderName, string extension) + { + _decoderName = decoderName; + _extension = extension; + } + } +} diff --git a/CUETools.Codecs/AudioEncoderClass.cs b/CUETools.Codecs/AudioEncoderClass.cs new file mode 100644 index 0000000..9b59b08 --- /dev/null +++ b/CUETools.Codecs/AudioEncoderClass.cs @@ -0,0 +1,75 @@ +using System; + +namespace CUETools.Codecs +{ + /// + /// This class provides an attribute for marking + /// classes that provide . + /// + /// + /// When plugins with classes that provide are + /// registered, their attributes are read. + /// + /// + /// using CUETools.Codecs; + /// + ///[AudioEncoderClass("libFLAC", "flac", true, "0 1 2 3 4 5 6 7 8", "5", 1)] + ///public class MyEncoder : IAudioDest { + /// ... + ///} + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public sealed class AudioEncoderClass : Attribute + { + private string _encoderName, _extension, _supportedModes, _defaultMode; + private bool _lossless; + private int _priority; + private Type _settings; + + public string EncoderName + { + get { return _encoderName; } + } + + public string Extension + { + get { return _extension; } + } + + public string SupportedModes + { + get { return _supportedModes; } + } + + public string DefaultMode + { + get { return _defaultMode; } + } + + public bool Lossless + { + get { return _lossless; } + } + + public int Priority + { + get { return _priority; } + } + + public Type Settings + { + get { return _settings; } + } + + public AudioEncoderClass(string encoderName, string extension, bool lossless, string supportedModes, string defaultMode, int priority, Type settings) + { + _encoderName = encoderName; + _extension = extension; + _supportedModes = supportedModes; + _defaultMode = defaultMode; + _lossless = lossless; + _priority = priority; + _settings = settings; + } + } +} diff --git a/CUETools.Codecs/AudioPCMConfig.cs b/CUETools.Codecs/AudioPCMConfig.cs new file mode 100644 index 0000000..b7791cc --- /dev/null +++ b/CUETools.Codecs/AudioPCMConfig.cs @@ -0,0 +1,24 @@ +namespace CUETools.Codecs +{ + public class AudioPCMConfig + { + public static readonly AudioPCMConfig RedBook = new AudioPCMConfig(16, 2, 44100); + + private int _bitsPerSample; + private int _channelCount; + private int _sampleRate; + + public int BitsPerSample { get { return _bitsPerSample; } } + public int ChannelCount { get { return _channelCount; } } + public int SampleRate { get { return _sampleRate; } } + public int BlockAlign { get { return _channelCount * ((_bitsPerSample + 7) / 8); } } + public bool IsRedBook { get { return _bitsPerSample == 16 && _channelCount == 2 && _sampleRate == 44100; } } + + public AudioPCMConfig(int bitsPerSample, int channelCount, int sampleRate) + { + _bitsPerSample = bitsPerSample; + _channelCount = channelCount; + _sampleRate = sampleRate; + } + } +} diff --git a/CUETools.Codecs/AudioPipe.cs b/CUETools.Codecs/AudioPipe.cs new file mode 100644 index 0000000..d98d454 --- /dev/null +++ b/CUETools.Codecs/AudioPipe.cs @@ -0,0 +1,265 @@ +using System; +using System.Threading; + +namespace CUETools.Codecs +{ + public class AudioPipe : IAudioSource//, IDisposable + { + private AudioBuffer _readBuffer, _writeBuffer; + private AudioPCMConfig pcm; + private long _sampleLen, _samplePos; + private int _maxLength; + private Thread _workThread; + private IAudioSource _source; + private bool _close = false; + private bool _haveData = false; + private int _bufferPos = 0; + private Exception _ex = null; + private bool own; + private ThreadPriority priority; + + public long Position + { + get + { + return _samplePos; + } + set + { + if (value == _samplePos) + return; + + if (_source == null) + throw new NotSupportedException(); + + lock (this) + { + _close = true; + Monitor.Pulse(this); + } + if (_workThread != null) + { + _workThread.Join(); + _workThread = null; + } + _source.Position = value; + _samplePos = value; + _bufferPos = 0; + _haveData = false; + _close = false; + //Go(); + //throw new Exception("not supported"); + } + } + + public long Length + { + get + { + return _sampleLen; + } + } + + public long Remaining + { + get + { + return _sampleLen - _samplePos; + } + } + + public AudioPCMConfig PCM + { + get + { + return pcm; + } + } + + public string Path + { + get + { + if (_source == null) + return ""; + return _source.Path; + } + } + + public AudioPipe(AudioPCMConfig pcm, int size) + { + this.pcm = pcm; + _readBuffer = new AudioBuffer(pcm, size); + _writeBuffer = new AudioBuffer(pcm, size); + _maxLength = size; + _sampleLen = -1; + _samplePos = 0; + } + + public AudioPipe(IAudioSource source, int size, bool own, ThreadPriority priority) + : this(source.PCM, size) + { + this.own = own; + this.priority = priority; + _source = source; + _sampleLen = _source.Length; + _samplePos = _source.Position; + } + + public AudioPipe(IAudioSource source, int size) + : this(source, size, true, ThreadPriority.BelowNormal) + { + } + + private void Decompress(object o) + { +#if !DEBUG + try +#endif + { + bool done = false; + do + { + done = _source.Read(_writeBuffer, -1) == 0; + lock (this) + { + while (_haveData && !_close) + Monitor.Wait(this); + if (_close) + break; + AudioBuffer temp = _writeBuffer; + _writeBuffer = _readBuffer; + _readBuffer = temp; + _haveData = true; + Monitor.Pulse(this); + } + } while (!done); + } +#if !DEBUG + catch (Exception ex) + { + lock (this) + { + _ex = ex; + Monitor.Pulse(this); + } + } +#endif + } + + private void Go() + { + if (_workThread != null || _ex != null || _source == null) return; + _workThread = new Thread(Decompress); + _workThread.Priority = priority; + _workThread.IsBackground = true; + _workThread.Name = "AudioPipe"; + _workThread.Start(null); + } + + //public new void Dispose() + //{ + // _buffer.Clear(); + //} + + public void Close() + { + lock (this) + { + _close = true; + Monitor.Pulse(this); + } + if (_workThread != null) + { + _workThread.Join(); + _workThread = null; + } + if (_source != null) + { + if (own) _source.Close(); + _source = null; + } + if (_readBuffer != null) + { + //_readBuffer.Clear(); + _readBuffer = null; + } + if (_writeBuffer != null) + { + //_writeBuffer.Clear(); + _writeBuffer = null; + } + } + + public int Write(AudioBuffer buff) + { + if (_writeBuffer.Size < _writeBuffer.Length + buff.Length) + { + AudioBuffer realloced = new AudioBuffer(pcm, _writeBuffer.Size + buff.Size); + realloced.Prepare(_writeBuffer, 0, _writeBuffer.Length); + _writeBuffer = realloced; + } + if (_writeBuffer.Length == 0) + _writeBuffer.Prepare(buff, 0, buff.Length); + else + { + _writeBuffer.Load(_writeBuffer.Length, buff, 0, buff.Length); + _writeBuffer.Length += buff.Length; + } + lock (this) + { + if (!_haveData) + { + AudioBuffer temp = _writeBuffer; + _writeBuffer = _readBuffer; + _writeBuffer.Length = 0; + _readBuffer = temp; + _haveData = true; + Monitor.Pulse(this); + } + } + return _writeBuffer.Length; + } + + public int Read(AudioBuffer buff, int maxLength) + { + Go(); + + bool needToCopy = false; + if (_bufferPos != 0) + needToCopy = true; + else + lock (this) + { + while (!_haveData && _ex == null) + Monitor.Wait(this); + if (_ex != null) + throw _ex; + if (_bufferPos == 0 && (maxLength < 0 || _readBuffer.Length <= maxLength)) + { + buff.Swap(_readBuffer); + _haveData = false; + Monitor.Pulse(this); + } + else + needToCopy = true; + } + if (needToCopy) + { + buff.Prepare(_readBuffer, _bufferPos, maxLength); + _bufferPos += buff.Length; + if (_bufferPos == _readBuffer.Length) + { + _bufferPos = 0; + lock (this) + { + _haveData = false; + Monitor.Pulse(this); + } + } + } + _samplePos += buff.Length; + return buff.Length; + } + } +} diff --git a/CUETools.Codecs/AudioSamples.cs b/CUETools.Codecs/AudioSamples.cs new file mode 100644 index 0000000..8676773 --- /dev/null +++ b/CUETools.Codecs/AudioSamples.cs @@ -0,0 +1,142 @@ +using System; + +namespace CUETools.Codecs +{ + public class AudioSamples + { + public const uint UINT32_MAX = 0xffffffff; + + unsafe public static void Interlace(int* res, int* src1, int* src2, int n) + { + for (int i = n; i > 0; i--) + { + *(res++) = *(src1++); + *(res++) = *(src2++); + } + } + + unsafe public static void Deinterlace(int* dst1, int* dst2, int* src, int n) + { + for (int i = n; i > 0; i--) + { + *(dst1++) = *(src++); + *(dst2++) = *(src++); + } + } + + unsafe public static bool MemCmp(int* res, int* smp, int n) + { + for (int i = n; i > 0; i--) + if (*(res++) != *(smp++)) + return true; + return false; + } + + unsafe public static void MemCpy(uint* res, uint* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(int* res, int* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(long* res, long* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(short* res, short* smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemCpy(byte* res, byte* smp, int n) + { + if ((((IntPtr)smp).ToInt64() & 7) == (((IntPtr)res).ToInt64() & 7) && n > 32) + { + int delta = (int)((8 - (((IntPtr)smp).ToInt64() & 7)) & 7); + for (int i = delta; i > 0; i--) + *(res++) = *(smp++); + n -= delta; + + MemCpy((long*)res, (long*)smp, n >> 3); + int n8 = (n >> 3) << 3; + n -= n8; + smp += n8; + res += n8; + } + if ((((IntPtr)smp).ToInt64() & 3) == (((IntPtr)res).ToInt64() & 3) && n > 16) + { + int delta = (int)((4 - (((IntPtr)smp).ToInt64() & 3)) & 3); + for (int i = delta; i > 0; i--) + *(res++) = *(smp++); + n -= delta; + + MemCpy((int*)res, (int*)smp, n >> 2); + int n4 = (n >> 2) << 2; + n -= n4; + smp += n4; + res += n4; + } + for (int i = n; i > 0; i--) + *(res++) = *(smp++); + } + + unsafe public static void MemSet(int* res, int smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(long* res, long smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(byte* res, byte smp, int n) + { + if (IntPtr.Size == 8 && (((IntPtr)res).ToInt64() & 7) == 0 && smp == 0 && n > 8) + { + MemSet((long*)res, 0, n >> 3); + int n8 = (n >> 3) << 3; + n -= n8; + res += n8; + } + if ((((IntPtr)res).ToInt64() & 3) == 0 && smp == 0 && n > 4) + { + MemSet((int*)res, 0, n >> 2); + int n4 = (n >> 2) << 2; + n -= n4; + res += n4; + } + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(byte[] res, byte smp, int offs, int n) + { + fixed (byte* pres = &res[offs]) + MemSet(pres, smp, n); + } + + unsafe public static void MemSet(int[] res, int smp, int offs, int n) + { + fixed (int* pres = &res[offs]) + MemSet(pres, smp, n); + } + + unsafe public static void MemSet(long[] res, long smp, int offs, int n) + { + fixed (long* pres = &res[offs]) + MemSet(pres, smp, n); + } + } + +} diff --git a/CUETools.Codecs/BitReader.cs b/CUETools.Codecs/BitReader.cs index afb1322..eab17b6 100644 --- a/CUETools.Codecs/BitReader.cs +++ b/CUETools.Codecs/BitReader.cs @@ -1,58 +1,34 @@ -/** - * CUETools.Codecs: common audio encoder/decoder routines - * Copyright (c) 2009 Gregory S. Chudov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - using System; -using System.Collections.Generic; -using System.Text; namespace CUETools.Codecs { unsafe public class BitReader - { - byte* buffer; - int pos, len; - int _bitaccumulator; - uint cache; + { + #region Static Methods - public static int log2i(int v) - { - return log2i((uint)v); - } + public static int log2i(int v) + { + return log2i((uint)v); + } - public static int log2i(ulong v) - { - int n = 0; - if (0 != (v & 0xffffffff00000000)) { v >>= 32; n += 32; } - if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; } - if (0 != (v & 0xff00)) { v >>= 8; n += 8; } - return n + byte_to_log2_table[v]; - } + public static int log2i(ulong v) + { + int n = 0; + if (0 != (v & 0xffffffff00000000)) { v >>= 32; n += 32; } + if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; } + if (0 != (v & 0xff00)) { v >>= 8; n += 8; } + return n + byte_to_log2_table[v]; + } - public static int log2i(uint v) - { - int n = 0; - if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; } - if (0 != (v & 0xff00)) { v >>= 8; n += 8; } - return n + byte_to_log2_table[v]; - } + public static int log2i(uint v) + { + int n = 0; + if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; } + if (0 != (v & 0xff00)) { v >>= 8; n += 8; } + return n + byte_to_log2_table[v]; + } - public static readonly byte[] byte_to_unary_table = new byte[] + public static readonly byte[] byte_to_unary_table = new byte[] { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -72,7 +48,7 @@ namespace CUETools.Codecs 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - public static readonly byte[] byte_to_log2_table = new byte[] + public static readonly byte[] byte_to_log2_table = new byte[] { 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, @@ -92,6 +68,13 @@ namespace CUETools.Codecs 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; + #endregion + + private byte* buffer; + private int pos, len; + private int _bitaccumulator; + private uint cache; + public int Position { get { return pos; } @@ -285,13 +268,15 @@ namespace CUETools.Codecs v = x & 0x01; i = 5; } - else if (0xFE == x) /* 11111110 */ - { - v = 0; - i = 6; - } - else - throw new Exception("invalid utf8 encoding"); + else if (0xFE == x) /* 11111110 */ + { + v = 0; + i = 6; + } + else + { + throw new Exception("invalid utf8 encoding"); + } for (; i > 0; i--) { x = readbits(8); @@ -322,60 +307,70 @@ namespace CUETools.Codecs fixed (byte* unary_table = byte_to_unary_table) { uint mask = (1U << k) - 1; - if (k == 0) - for (int i = n; i > 0; i--) - *(r++) = read_unary_signed(); - else if (k <= 8) - for (int i = n; i > 0; i--) - { - //*(r++) = read_rice_signed((int)k); - uint bits = unary_table[cache >> 24]; - uint msbs = bits; - while (bits == 8) - { - skipbits8(8); - bits = unary_table[cache >> 24]; - msbs += bits; - } - int btsk = k + (int)bits + 1; - uint uval = (msbs << k) | ((cache >> (32 - btsk)) & mask); - skipbits16(btsk); - *(r++) = (int)(uval >> 1 ^ -(int)(uval & 1)); - } - else if (k <= 16) - for (int i = n; i > 0; i--) - { - //*(r++) = read_rice_signed((int)k); - uint bits = unary_table[cache >> 24]; - uint msbs = bits; - while (bits == 8) - { - skipbits8(8); - bits = unary_table[cache >> 24]; - msbs += bits; - } - int btsk = k + (int)bits + 1; - uint uval = (msbs << k) | ((cache >> (32 - btsk)) & mask); - skipbits(btsk); - *(r++) = (int)(uval >> 1 ^ -(int)(uval & 1)); - } - else - for (int i = n; i > 0; i--) - { - //*(r++) = read_rice_signed((int)k); - uint bits = unary_table[cache >> 24]; - uint msbs = bits; - while (bits == 8) - { - skipbits8(8); - bits = unary_table[cache >> 24]; - msbs += bits; - } - skipbits8((int)(msbs & 7) + 1); - uint uval = (msbs << k) | ((cache >> (32 - k))); - skipbits(k); - *(r++) = (int)(uval >> 1 ^ -(int)(uval & 1)); - } + if (k == 0) + { + for (int i = n; i > 0; i--) + { + *(r++) = read_unary_signed(); + } + } + else if (k <= 8) + { + for (int i = n; i > 0; i--) + { + //*(r++) = read_rice_signed((int)k); + uint bits = unary_table[cache >> 24]; + uint msbs = bits; + while (bits == 8) + { + skipbits8(8); + bits = unary_table[cache >> 24]; + msbs += bits; + } + int btsk = k + (int)bits + 1; + uint uval = (msbs << k) | ((cache >> (32 - btsk)) & mask); + skipbits16(btsk); + *(r++) = (int)(uval >> 1 ^ -(int)(uval & 1)); + } + } + else if (k <= 16) + { + for (int i = n; i > 0; i--) + { + //*(r++) = read_rice_signed((int)k); + uint bits = unary_table[cache >> 24]; + uint msbs = bits; + while (bits == 8) + { + skipbits8(8); + bits = unary_table[cache >> 24]; + msbs += bits; + } + int btsk = k + (int)bits + 1; + uint uval = (msbs << k) | ((cache >> (32 - btsk)) & mask); + skipbits(btsk); + *(r++) = (int)(uval >> 1 ^ -(int)(uval & 1)); + } + } + else + { + for (int i = n; i > 0; i--) + { + //*(r++) = read_rice_signed((int)k); + uint bits = unary_table[cache >> 24]; + uint msbs = bits; + while (bits == 8) + { + skipbits8(8); + bits = unary_table[cache >> 24]; + msbs += bits; + } + skipbits8((int)(msbs & 7) + 1); + uint uval = (msbs << k) | ((cache >> (32 - k))); + skipbits(k); + *(r++) = (int)(uval >> 1 ^ -(int)(uval & 1)); + } + } } } } diff --git a/CUETools.Codecs/BitWriter.cs b/CUETools.Codecs/BitWriter.cs index 78b71ca..1f31005 100644 --- a/CUETools.Codecs/BitWriter.cs +++ b/CUETools.Codecs/BitWriter.cs @@ -1,372 +1,353 @@ -/** - * CUETools.Codecs: common audio encoder/decoder routines - * Copyright (c) 2009 Gregory S. Chudov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - using System; -using System.Collections.Generic; -using System.Text; namespace CUETools.Codecs { - public class BitWriter - { - uint bit_buf; - int bit_left; - byte[] buffer; - int buf_start, buf_ptr, buf_end; - bool eof; + public class BitWriter + { + private uint bit_buf; + private int bit_left; + private byte[] buffer; + private int buf_start, buf_ptr, buf_end; + private bool eof; - public BitWriter(byte[] buf, int pos, int len) - { - buffer = buf; - buf_start = pos; - buf_ptr = pos; - buf_end = pos + len; - bit_left = 32; - bit_buf = 0; - eof = false; - } + public byte[] Buffer + { + get + { + return buffer; + } + } - public void Reset() - { - buf_ptr = buf_start; - bit_left = 32; - bit_buf = 0; - eof = false; - } + public int Length + { + get + { + return buf_ptr - buf_start; + } + set + { + flush(); + buf_ptr = buf_start + value; + } + } - public void writebytes(int bytes, byte c) - { - for (; bytes > 0; bytes--) - writebits(8, c); - } + public int BitLength + { + get + { + return buf_ptr * 8 + 32 - bit_left; + } + } - public unsafe void writeints(int len, int pos, byte* buf) - { - int old_pos = BitLength; - int start = old_pos / 8; - int start1 = pos / 8; - int end = (old_pos + len) / 8; - int end1 = (pos + len) / 8; - flush(); - byte start_val = old_pos % 8 != 0 ? buffer[start] : (byte)0; - fixed (byte* buf1 = &buffer[0]) - AudioSamples.MemCpy(buf1 + start, buf + start1, end - start); - buffer[start] |= start_val; - buf_ptr = end; - if ((old_pos + len) % 8 != 0) - writebits((old_pos + len) % 8, buf[end1] >> (8 - ((old_pos + len) % 8))); - } + public BitWriter(byte[] buf, int pos, int len) + { + buffer = buf; + buf_start = pos; + buf_ptr = pos; + buf_end = pos + len; + bit_left = 32; + bit_buf = 0; + eof = false; + } - public void write(params char [] chars) - { - foreach (char c in chars) - writebits(8, (byte)c); - } + public void Reset() + { + buf_ptr = buf_start; + bit_left = 32; + bit_buf = 0; + eof = false; + } - public void write(string s) - { - for (int i = 0; i < s.Length; i++) - writebits(8, (byte)s[i]); - } + public void writebytes(int bytes, byte c) + { + for (; bytes > 0; bytes--) + { + writebits(8, c); + } + } - public void writebits_signed(int bits, int val) - { - writebits(bits, val & ((1 << bits) - 1)); - } + public unsafe void writeints(int len, int pos, byte* buf) + { + int old_pos = BitLength; + int start = old_pos / 8; + int start1 = pos / 8; + int end = (old_pos + len) / 8; + int end1 = (pos + len) / 8; + flush(); + byte start_val = old_pos % 8 != 0 ? buffer[start] : (byte)0; + fixed (byte* buf1 = &buffer[0]) + AudioSamples.MemCpy(buf1 + start, buf + start1, end - start); + buffer[start] |= start_val; + buf_ptr = end; + if ((old_pos + len) % 8 != 0) + writebits((old_pos + len) % 8, buf[end1] >> (8 - ((old_pos + len) % 8))); + } - public void writebits_signed(uint bits, int val) - { - writebits((int) bits, val & ((1 << (int) bits) - 1)); - } + public void write(params char[] chars) + { + foreach (char c in chars) + writebits(8, (byte)c); + } - public void writebits(int bits, int val) - { - writebits(bits, (uint)val); - } + public void write(string s) + { + for (int i = 0; i < s.Length; i++) + writebits(8, (byte)s[i]); + } - public void writebits(DateTime val) - { - TimeSpan span = val.ToUniversalTime() - new DateTime(1904, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); - writebits(32, (uint)span.TotalSeconds); - } + public void writebits_signed(int bits, int val) + { + writebits(bits, val & ((1 << bits) - 1)); + } - public void writebits64(int bits, ulong val) - { - if (bits > 32) - { - writebits(bits - 32, (uint)(val >> 32)); - val &= 0xffffffffL; - bits = 32; - } - writebits(bits, (uint)val); - } + public void writebits_signed(uint bits, int val) + { + writebits((int)bits, val & ((1 << (int)bits) - 1)); + } - public void writebits(int bits, uint val) - { - //assert(bits == 32 || val < (1U << bits)); + public void writebits(int bits, int val) + { + writebits(bits, (uint)val); + } - if (bits == 0 || eof) return; - if ((buf_ptr + 3) >= buf_end) - { - eof = true; - return; - } - if (bits < bit_left) - { - bit_buf = (bit_buf << bits) | val; - bit_left -= bits; - } - else - { - uint bb = 0; - if (bit_left == 32) - { - //assert(bits == 32); - bb = val; - } - else - { - bb = (bit_buf << bit_left) | (val >> (bits - bit_left)); - bit_left += (32 - bits); - } - if (buffer != null) - { - buffer[buf_ptr + 3] = (byte)(bb & 0xFF); bb >>= 8; - buffer[buf_ptr + 2] = (byte)(bb & 0xFF); bb >>= 8; - buffer[buf_ptr + 1] = (byte)(bb & 0xFF); bb >>= 8; - buffer[buf_ptr + 0] = (byte)(bb & 0xFF); - } - buf_ptr += 4; - bit_buf = val; - } - } + public void writebits(DateTime val) + { + TimeSpan span = val.ToUniversalTime() - new DateTime(1904, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + writebits(32, (uint)span.TotalSeconds); + } - /// - /// Assumes there's enough space, buffer != null and bits is in range 1..31 - /// - /// - /// - unsafe void writebits_fast(int bits, uint val, ref byte * buf) - { + public void writebits64(int bits, ulong val) + { + if (bits > 32) + { + writebits(bits - 32, (uint)(val >> 32)); + val &= 0xffffffffL; + bits = 32; + } + writebits(bits, (uint)val); + } + + public void writebits(int bits, uint val) + { + //assert(bits == 32 || val < (1U << bits)); + + if (bits == 0 || eof) return; + if ((buf_ptr + 3) >= buf_end) + { + eof = true; + return; + } + if (bits < bit_left) + { + bit_buf = (bit_buf << bits) | val; + bit_left -= bits; + } + else + { + uint bb = 0; + if (bit_left == 32) + { + //assert(bits == 32); + bb = val; + } + else + { + bb = (bit_buf << bit_left) | (val >> (bits - bit_left)); + bit_left += (32 - bits); + } + if (buffer != null) + { + buffer[buf_ptr + 3] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr + 2] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr + 1] = (byte)(bb & 0xFF); bb >>= 8; + buffer[buf_ptr + 0] = (byte)(bb & 0xFF); + } + buf_ptr += 4; + bit_buf = val; + } + } + + /// + /// Assumes there's enough space, buffer != null and bits is in range 1..31 + /// + /// + /// +// unsafe void writebits_fast(int bits, uint val, ref byte* buf) +// { +//#if DEBUG +// if ((buf_ptr + 3) >= buf_end) +// { +// eof = true; +// return; +// } +//#endif +// if (bits < bit_left) +// { +// bit_buf = (bit_buf << bits) | val; +// bit_left -= bits; +// } +// else +// { +// uint bb = (bit_buf << bit_left) | (val >> (bits - bit_left)); +// bit_left += (32 - bits); + +// *(buf++) = (byte)(bb >> 24); +// *(buf++) = (byte)(bb >> 16); +// *(buf++) = (byte)(bb >> 8); +// *(buf++) = (byte)(bb); + +// bit_buf = val; +// } +// } + + public void write_utf8(int val) + { + write_utf8((uint)val); + } + + public void write_utf8(uint val) + { + if (val < 0x80) + { + writebits(8, val); + return; + } + int bytes = (BitReader.log2i(val) + 4) / 5; + int shift = (bytes - 1) * 6; + writebits(8, (256U - (256U >> bytes)) | (val >> shift)); + while (shift >= 6) + { + shift -= 6; + writebits(8, 0x80 | ((val >> shift) & 0x3F)); + } + } + + public void write_unary_signed(int val) + { + // convert signed to unsigned + int v = -2 * val - 1; + v ^= (v >> 31); + + // write quotient in unary + int q = v + 1; + while (q > 31) + { + writebits(31, 0); + q -= 31; + } + writebits(q, 1); + } + + public void write_rice_signed(int k, int val) + { + // convert signed to unsigned + int v = -2 * val - 1; + v ^= (v >> 31); + + // write quotient in unary + int q = (v >> k) + 1; + while (q + k > 31) + { + int b = Math.Min(q + k - 31, 31); + writebits(b, 0); + q -= b; + } + + // write remainder in binary using 'k' bits + writebits(k + q, (v & ((1 << k) - 1)) | (1 << k)); + } + + public unsafe void write_rice_block_signed(byte* fixedbuf, int k, int* residual, int count) + { + byte* buf = &fixedbuf[buf_ptr]; + //fixed (byte* fixbuf = &buffer[buf_ptr]) + { + //byte* buf = fixbuf; + for (int i = count; i > 0; i--) + { + int v = *(residual++); + v = (v << 1) ^ (v >> 31); + + // write quotient in unary + int q = (v >> k) + 1; + int bits = k + q; + while (bits > 31) + { #if DEBUG - if ((buf_ptr + 3) >= buf_end) - { - eof = true; - return; - } + if (buf + 3 >= fixedbuf + buf_end) + { + eof = true; + return; + } #endif - if (bits < bit_left) - { - bit_buf = (bit_buf << bits) | val; - bit_left -= bits; - } - else - { - uint bb = (bit_buf << bit_left) | (val >> (bits - bit_left)); - bit_left += (32 - bits); - - *(buf++) = (byte)(bb >> 24); - *(buf++) = (byte)(bb >> 16); - *(buf++) = (byte)(bb >> 8); - *(buf++) = (byte)(bb); - - bit_buf = val; - } - } - - public void write_utf8(int val) - { - write_utf8((uint)val); - } - - public void write_utf8(uint val) - { - if (val < 0x80) - { - writebits(8, val); - return; - } - int bytes = (BitReader.log2i(val) + 4) / 5; - int shift = (bytes - 1) * 6; - writebits(8, (256U - (256U >> bytes)) | (val >> shift)); - while (shift >= 6) - { - shift -= 6; - writebits(8, 0x80 | ((val >> shift) & 0x3F)); - } - } - - public void write_unary_signed(int val) - { - // convert signed to unsigned - int v = -2 * val - 1; - v ^= (v >> 31); - - // write quotient in unary - int q = v + 1; - while (q > 31) - { - writebits(31, 0); - q -= 31; - } - writebits(q, 1); - } - - public void write_rice_signed(int k, int val) - { - // convert signed to unsigned - int v = -2 * val - 1; - v ^= (v >> 31); - - // write quotient in unary - int q = (v >> k) + 1; - while (q + k > 31) - { - int b = Math.Min(q + k - 31, 31); - writebits(b, 0); - q -= b; - } - - // write remainder in binary using 'k' bits - writebits(k + q, (v & ((1 << k) - 1)) | (1 << k)); - } - - public unsafe void write_rice_block_signed(byte * fixedbuf, int k, int* residual, int count) - { - byte* buf = &fixedbuf[buf_ptr]; - //fixed (byte* fixbuf = &buffer[buf_ptr]) - { - //byte* buf = fixbuf; - for (int i = count; i > 0; i--) - { - int v = *(residual++); - v = (v << 1) ^ (v >> 31); - - // write quotient in unary - int q = (v >> k) + 1; - int bits = k + q; - while (bits > 31) - { -#if DEBUG - if (buf + 3 >= fixedbuf + buf_end) - { - eof = true; - return; - } -#endif - int b = Math.Min(bits - 31, 31); - if (b < bit_left) - { - bit_buf = (bit_buf << b); - bit_left -= b; - } - else - { - uint bb = bit_buf << bit_left; - bit_buf = 0; - bit_left += (32 - b); - *(buf++) = (byte)(bb >> 24); - *(buf++) = (byte)(bb >> 16); - *(buf++) = (byte)(bb >> 8); - *(buf++) = (byte)(bb); - } - bits -= b; - } + int b = Math.Min(bits - 31, 31); + if (b < bit_left) + { + bit_buf = (bit_buf << b); + bit_left -= b; + } + else + { + uint bb = bit_buf << bit_left; + bit_buf = 0; + bit_left += (32 - b); + *(buf++) = (byte)(bb >> 24); + *(buf++) = (byte)(bb >> 16); + *(buf++) = (byte)(bb >> 8); + *(buf++) = (byte)(bb); + } + bits -= b; + } #if DEBUG - if (buf + 3 >= fixedbuf + buf_end) - { - eof = true; - return; - } + if (buf + 3 >= fixedbuf + buf_end) + { + eof = true; + return; + } #endif - // write remainder in binary using 'k' bits - //writebits_fast(k + q, (uint)((v & ((1 << k) - 1)) | (1 << k)), ref buf); - uint val = (uint)((v & ((1 << k) - 1)) | (1 << k)); - if (bits < bit_left) - { - bit_buf = (bit_buf << bits) | val; - bit_left -= bits; - } - else - { - uint bb = (bit_buf << bit_left) | (val >> (bits - bit_left)); - bit_buf = val; - bit_left += (32 - bits); - *(buf++) = (byte)(bb >> 24); - *(buf++) = (byte)(bb >> 16); - *(buf++) = (byte)(bb >> 8); - *(buf++) = (byte)(bb); - } - } - buf_ptr = (int)(buf - fixedbuf); - } - } + // write remainder in binary using 'k' bits + //writebits_fast(k + q, (uint)((v & ((1 << k) - 1)) | (1 << k)), ref buf); + uint val = (uint)((v & ((1 << k) - 1)) | (1 << k)); + if (bits < bit_left) + { + bit_buf = (bit_buf << bits) | val; + bit_left -= bits; + } + else + { + uint bb = (bit_buf << bit_left) | (val >> (bits - bit_left)); + bit_buf = val; + bit_left += (32 - bits); + *(buf++) = (byte)(bb >> 24); + *(buf++) = (byte)(bb >> 16); + *(buf++) = (byte)(bb >> 8); + *(buf++) = (byte)(bb); + } + } + buf_ptr = (int)(buf - fixedbuf); + } + } - public void flush() - { - bit_buf <<= bit_left; - while (bit_left < 32 && !eof) - { - if (buf_ptr >= buf_end) - { - eof = true; - break; - } - if (buffer != null) - buffer[buf_ptr] = (byte)(bit_buf >> 24); - buf_ptr++; - bit_buf <<= 8; - bit_left += 8; - } - bit_left = 32; - bit_buf = 0; - } - - public byte[] Buffer - { - get - { - return buffer; - } - } - - public int Length - { - get - { - return buf_ptr - buf_start; - } - set - { - flush(); - buf_ptr = buf_start + value; - } - } - - public int BitLength - { - get - { - return buf_ptr * 8 + 32 - bit_left; - } - } - } + public void flush() + { + bit_buf <<= bit_left; + while (bit_left < 32 && !eof) + { + if (buf_ptr >= buf_end) + { + eof = true; + break; + } + if (buffer != null) + buffer[buf_ptr] = (byte)(bit_buf >> 24); + buf_ptr++; + bit_buf <<= 8; + bit_left += 8; + } + bit_left = 32; + bit_buf = 0; + } + } } diff --git a/CUETools.Codecs/CRCs/CRC16.cs b/CUETools.Codecs/CRC/CRC16.cs similarity index 88% rename from CUETools.Codecs/CRCs/CRC16.cs rename to CUETools.Codecs/CRC/CRC16.cs index fc25dc6..6b11860 100644 --- a/CUETools.Codecs/CRCs/CRC16.cs +++ b/CUETools.Codecs/CRC/CRC16.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace CUETools.Codecs { public class Crc16 diff --git a/CUETools.Codecs/CRCs/CRC16CCITT.cs b/CUETools.Codecs/CRC/CRC16CCITT.cs similarity index 90% rename from CUETools.Codecs/CRCs/CRC16CCITT.cs rename to CUETools.Codecs/CRC/CRC16CCITT.cs index 99c5273..0209ef3 100644 --- a/CUETools.Codecs/CRCs/CRC16CCITT.cs +++ b/CUETools.Codecs/CRC/CRC16CCITT.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace CUETools.Codecs { public enum InitialCrcValue { Zeros, NonZero1 = 0xffff, NonZero2 = 0x1D0F } diff --git a/CUETools.Codecs/CRCs/CRC32.cs b/CUETools.Codecs/CRC/CRC32.cs similarity index 95% rename from CUETools.Codecs/CRCs/CRC32.cs rename to CUETools.Codecs/CRC/CRC32.cs index 7f0c6c6..da24981 100644 --- a/CUETools.Codecs/CRCs/CRC32.cs +++ b/CUETools.Codecs/CRC/CRC32.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace CUETools.Codecs { diff --git a/CUETools.Codecs/CRC/CRC8.cs b/CUETools.Codecs/CRC/CRC8.cs new file mode 100644 index 0000000..cf4de32 --- /dev/null +++ b/CUETools.Codecs/CRC/CRC8.cs @@ -0,0 +1,43 @@ +namespace CUETools.Codecs +{ + public class Crc8 + { + private const ushort poly8 = 0x07; + + private ushort[] table = new ushort[256]; + + public Crc8() + { + int bits = 8; + ushort poly = (ushort) (poly8 + (1U << bits)); + for (ushort i = 0; i < table.Length; i++) + { + ushort crc = i; + for (int j = 0; j < bits; j++) + { + if ((crc & (1U << (bits - 1))) != 0) + crc = (ushort)((crc << 1) ^ poly); + else + crc <<= 1; + } + table[i] = (ushort)(crc & 0x00ff); + } + } + + public byte ComputeChecksum(byte[] bytes, int pos, int count) + { + ushort crc = 0; + for (int i = pos; i < pos + count; i++) + crc = table[crc ^ bytes[i]]; + return (byte)crc; + } + + public unsafe byte ComputeChecksum(byte* bytes, int pos, int count) + { + ushort crc = 0; + for (int i = pos; i < pos + count; i++) + crc = table[crc ^ bytes[i]]; + return (byte)crc; + } + } +} diff --git a/CUETools.Codecs/CRCs/CRC8.cs b/CUETools.Codecs/CRCs/CRC8.cs deleted file mode 100644 index 68a2209..0000000 --- a/CUETools.Codecs/CRCs/CRC8.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace CUETools.Codecs -{ - - public class Crc8 - { - const ushort poly8 = 0x07; - ushort[] table = new ushort[256]; - - public byte ComputeChecksum(byte[] bytes, int pos, int count) - { - ushort crc = 0; - for (int i = pos; i < pos + count; i++) - crc = table[crc ^ bytes[i]]; - return (byte) crc; - } - - public unsafe byte ComputeChecksum(byte * bytes, int pos, int count) - { - ushort crc = 0; - for (int i = pos; i < pos + count; i++) - crc = table[crc ^ bytes[i]]; - return (byte)crc; - } - - public Crc8() - { - int bits = 8; - ushort poly = (ushort) (poly8 + (1U << bits)); - for (ushort i = 0; i < table.Length; i++) - { - ushort crc = i; - for (int j = 0; j < bits; j++) - { - if ((crc & (1U << (bits - 1))) != 0) - crc = (ushort)((crc << 1) ^ poly); - else - crc <<= 1; - } - table[i] = (ushort)(crc & 0x00ff); - } - } - } -} diff --git a/CUETools.Codecs/CUETools.Codecs.csproj b/CUETools.Codecs/CUETools.Codecs.csproj index 5fff9ad..07feb74 100644 --- a/CUETools.Codecs/CUETools.Codecs.csproj +++ b/CUETools.Codecs/CUETools.Codecs.csproj @@ -62,16 +62,37 @@ + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -90,6 +111,9 @@ true + + +