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
+
+
+