diff --git a/APEDotNet/APEDotNet.vcproj b/APEDotNet/APEDotNet.vcproj index f474f1a..c35b71c 100644 --- a/APEDotNet/APEDotNet.vcproj +++ b/APEDotNet/APEDotNet.vcproj @@ -337,6 +337,10 @@ ReferencedProjectIdentifier="{CA200BCB-DFC6-4153-9BD4-785BC768B26B}" RelativePathToProject="..\APETagDotNet\APETagDotNet.csproj" /> + GetInfo (APE_INFO_BLOCK_ALIGN, 0, 0); - pBuffer = new unsigned char [16384 * nBlockAlign]; + _samplesBuffer = gcnew array (16384 * nBlockAlign); // loop through the whole file _sampleCount = pAPEDecompress->GetInfo (APE_DECOMPRESS_TOTAL_BLOCKS, 0, 0); // * ? @@ -137,7 +140,6 @@ namespace APEDotNet { ~APEReader () { - if (pBuffer) delete [] pBuffer; if (_winFileIO) delete _winFileIO; if (_gchIO.IsAllocated) @@ -146,50 +148,57 @@ namespace APEDotNet { _gchReadBuffer.Free(); } - property Int32 BitsPerSample { + virtual property Int32 BitsPerSample { Int32 get() { return _bitsPerSample; } } - property Int32 ChannelCount { + virtual property Int32 ChannelCount { Int32 get() { return _channelCount; } } - property Int32 SampleRate { + virtual property Int32 SampleRate { Int32 get() { return _sampleRate; } } - property Int64 Length { - Int64 get() { + virtual property UInt64 Length { + UInt64 get() { return _sampleCount; } } - property Int64 Position { - Int64 get() { - return _sampleOffset; + virtual property UInt64 Position + { + UInt64 get() { + return _sampleOffset - SamplesInBuffer; } - void set(Int64 offset) { + void set(UInt64 offset) { _sampleOffset = offset; + _bufferOffset = 0; + _bufferLength = 0; if (pAPEDecompress->Seek ((int) offset /*? */)) throw gcnew Exception("Unable to seek."); } } - property Int64 Remaining { - Int64 get() { - return _sampleCount - _sampleOffset; + virtual property UInt64 Remaining { + UInt64 get() { + return _sampleCount - _sampleOffset + SamplesInBuffer; } } - void Close() { - if (pAPEDecompress) delete pAPEDecompress; - pAPEDecompress = NULL; + virtual void Close() + { + if (pAPEDecompress) + { + delete pAPEDecompress; + pAPEDecompress = NULL; + } if (_IO != nullptr) { _IO->Close (); @@ -197,14 +206,15 @@ namespace APEDotNet { } } - property String^ Path { + virtual property String^ Path { String^ get() { return _path; } } - property NameValueCollection^ Tags { - NameValueCollection^ get () { + virtual property NameValueCollection^ Tags { + NameValueCollection^ get () + { if (!_tags) { APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true); @@ -213,33 +223,35 @@ namespace APEDotNet { } return _tags; } - void set (NameValueCollection ^tags) { + void set (NameValueCollection ^tags) + { _tags = tags; } } - Int32 Read([Out] array^% sampleBuffer) { - int sampleCount; - - int nBlocksRetrieved; - if (pAPEDecompress->GetData ((char *) pBuffer, 16384, &nBlocksRetrieved)) - throw gcnew Exception("An error occurred while decoding."); - - sampleCount = nBlocksRetrieved; - array^ _sampleBuffer = gcnew array (nBlocksRetrieved, 2); - interior_ptr pMyBuffer = &_sampleBuffer[0, 0]; - - short * pAPEBuffer = (short *) pBuffer; - short * pAPEBufferEnd = (short *) pBuffer + 2 * nBlocksRetrieved; - - while (pAPEBuffer < pAPEBufferEnd) { - *(pMyBuffer++) = *(pAPEBuffer++); - *(pMyBuffer++) = *(pAPEBuffer++); - } - - sampleBuffer = _sampleBuffer; - _sampleOffset += nBlocksRetrieved; + virtual UInt32 Read([Out] array^ buff, UInt32 sampleCount) + { + UInt32 buffOffset = 0; + UInt32 samplesNeeded = sampleCount; + while (samplesNeeded != 0) + { + if (SamplesInBuffer == 0) + { + int nBlocksRetrieved; + pin_ptr pSampleBuffer = &_samplesBuffer[0]; + if (pAPEDecompress->GetData ((char *) pSampleBuffer, 16384, &nBlocksRetrieved)) + throw gcnew Exception("An error occurred while decoding."); + _bufferOffset = 0; + _bufferLength = nBlocksRetrieved; + _sampleOffset += nBlocksRetrieved; + } + UInt32 copyCount = Math::Min(samplesNeeded, SamplesInBuffer); + AudioSamples::BytesToFLACSamples_16(_samplesBuffer, _bufferOffset*nBlockAlign, buff, buffOffset, copyCount, _channelCount); + samplesNeeded -= copyCount; + buffOffset += copyCount; + _bufferOffset += copyCount; + } return sampleCount; } @@ -249,22 +261,33 @@ namespace APEDotNet { NameValueCollection^ _tags; Int64 _sampleCount, _sampleOffset; Int32 _bitsPerSample, _channelCount, _sampleRate; + UInt32 _bufferOffset, _bufferLength; int nBlockAlign; - unsigned char * pBuffer; + array^ _samplesBuffer; String^ _path; Stream^ _IO; array^ _readBuffer; CWinFileIO* _winFileIO; GCHandle _gchIO, _gchReadBuffer; + + property UInt32 SamplesInBuffer + { + UInt32 get () + { + return (UInt32) (_bufferLength - _bufferOffset); + } + } }; - public ref class APEWriter { + public ref class APEWriter : IAudioDest + { public: - APEWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) { - - if ((channelCount != 1) && (channelCount != 2)) { + APEWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) + { + if (bitsPerSample != 16 && bitsPerSample != 24) + throw gcnew Exception("Bits per sample must be 16 or 24."); + if (channelCount != 1 && channelCount != 2) throw gcnew Exception("Only stereo and mono audio formats are allowed."); - } _path = path; _tags = gcnew NameValueCollection(); @@ -279,9 +302,8 @@ namespace APEDotNet { int nRetVal; pAPECompress = CreateIAPECompress (&nRetVal); - if (!pAPECompress) { - throw gcnew Exception("Unable to open file."); - } + if (!pAPECompress) + throw gcnew Exception("Unable to open APE compressor."); } ~APEWriter() @@ -294,7 +316,8 @@ namespace APEDotNet { _gchBuffer.Free(); } - void Close() { + virtual void Close() + { if (pAPECompress) { pAPECompress->Finish (NULL, 0, 0); @@ -322,21 +345,47 @@ namespace APEDotNet { } } - property Int32 FinalSampleCount { - Int32 get() { + virtual property Int64 FinalSampleCount + { + Int64 get() + { return _finalSampleCount; } - void set(Int32 value) { - if (value < 0) { + void set(Int64 value) + { + if (value < 0) throw gcnew Exception("Invalid final sample count."); - } - if (_initialized) { + if (_initialized) throw gcnew Exception("Final sample count cannot be changed after encoding begins."); - } _finalSampleCount = value; } } + virtual void Write(array^ buff, UInt32 sampleCount) + { + if (_sampleBuffer == nullptr || _sampleBuffer.Length < sampleCount * _blockAlign) + _sampleBuffer = gcnew array(sampleCount * _blockAlign); + AudioSamples::FLACSamplesToBytes(buff, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample); + if (!_initialized) Initialize(); + pin_ptr pSampleBuffer = &_sampleBuffer[0]; + if (pAPECompress->AddData (pSampleBuffer, sampleCount * _blockAlign)) + throw gcnew Exception("An error occurred while encoding."); + _samplesWritten += sampleCount; + } + + virtual property String^ Path + { + String^ get() { + return _path; + } + } + + virtual bool SetTags (NameValueCollection^ tags) + { + _tags = tags; + return true; + } + property Int32 CompressionLevel { Int32 get() { return _compressionLevel; @@ -349,24 +398,6 @@ namespace APEDotNet { } } - void Write(array^ sampleBuffer, UInt32 sampleCount) { - if (!_initialized) Initialize(); - pin_ptr pSampleBuffer = &sampleBuffer[0]; - if (pAPECompress->AddData (pSampleBuffer, sampleCount * _blockAlign)) - throw gcnew Exception("An error occurred while encoding."); - _samplesWritten += sampleCount; - } - - property String^ Path { - String^ get() { - return _path; - } - } - - void SetTags (NameValueCollection^ tags) { - _tags = tags; - } - private: IAPECompress * pAPECompress; bool _initialized; @@ -379,6 +410,7 @@ namespace APEDotNet { GCHandle _gchIO, _gchBuffer; CWinFileIO* _winFileIO; array^ _writeBuffer; + array^ _sampleBuffer; void Initialize() { _IO = gcnew FileStream (_path, FileMode::Create, FileAccess::ReadWrite, FileShare::Read); @@ -408,7 +440,10 @@ namespace APEDotNet { { array^ buff = (array^) _gchBuffer.Target; if (buff->Length < nBytesToRead) + { Array::Resize (buff, nBytesToRead); + _gchBuffer.Target = buff; + } int len = ((Stream^)_gchIO.Target)->Read (buff, 0, nBytesToRead); if (len) Marshal::Copy (buff, 0, (IntPtr)pBuffer, len); *pBytesRead = len; @@ -419,7 +454,10 @@ namespace APEDotNet { { array^ buff = (array^) _gchBuffer.Target; if (buff->Length < nBytesToWrite) + { Array::Resize (buff, nBytesToWrite); + _gchBuffer.Target = buff; + } Marshal::Copy ((IntPtr)(void*)pBuffer, buff, 0, nBytesToWrite); ((Stream^)_gchIO.Target)->Write (buff, 0, nBytesToWrite); *pBytesWritten = nBytesToWrite; diff --git a/AudioCodecsDotNet/AudioCodecsDotNet.cs b/AudioCodecsDotNet/AudioCodecsDotNet.cs index 3be1f7f..59e5463 100644 --- a/AudioCodecsDotNet/AudioCodecsDotNet.cs +++ b/AudioCodecsDotNet/AudioCodecsDotNet.cs @@ -29,7 +29,7 @@ namespace AudioCodecsDotNet string Path { get; } } - public class AudioCodecsDotNet + public class AudioSamples { public static unsafe void FLACSamplesToBytes_16(int[,] inSamples, uint inSampleOffset, byte[] outSamples, uint outByteOffset, uint sampleCount, int channelCount) @@ -92,9 +92,9 @@ namespace AudioCodecsDotNet byte[] outSamples, uint outByteOffset, uint sampleCount, int channelCount, int bitsPerSample) { if (bitsPerSample == 16) - AudioCodecsDotNet.FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount); + AudioSamples.FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount); else if (bitsPerSample == 24) - AudioCodecsDotNet.FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount); + AudioSamples.FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount); else throw new Exception("Unsupported bitsPerSample value"); } @@ -483,7 +483,7 @@ namespace AudioCodecsDotNet _sampleBuffer = new byte[byteCount]; if (_IO.Read(_sampleBuffer, 0, (int)byteCount) != byteCount) throw new Exception("Incomplete file read."); - AudioCodecsDotNet.BytesToFLACSamples_16 (_sampleBuffer, 0, buff, 0, + AudioSamples.BytesToFLACSamples_16(_sampleBuffer, 0, buff, 0, sampleCount, _channelCount); _samplePos += sampleCount; return sampleCount; @@ -596,7 +596,7 @@ namespace AudioCodecsDotNet return; if (_sampleBuffer == null || _sampleBuffer.Length < sampleCount * _blockAlign) _sampleBuffer = new byte[sampleCount * _blockAlign]; - AudioCodecsDotNet.FLACSamplesToBytes(buff, 0, _sampleBuffer, 0, + AudioSamples.FLACSamplesToBytes(buff, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample); _IO.Write(_sampleBuffer, 0, (int)sampleCount * _blockAlign); _sampleLen += sampleCount; diff --git a/CUEToolsLib/AudioReadWrite.cs b/CUEToolsLib/AudioReadWrite.cs index e699c87..edea85d 100644 --- a/CUEToolsLib/AudioReadWrite.cs +++ b/CUEToolsLib/AudioReadWrite.cs @@ -53,500 +53,4 @@ namespace CUEToolsLib { return dest; } } - -#if !MONO - class FLACReader : IAudioSource { - FLACDotNet.FLACReader _flacReader; - int[,] _sampleBuffer; - uint _bufferOffset, _bufferLength; - - public FLACReader(string path, Stream IO) - { - _flacReader = new FLACDotNet.FLACReader(path, IO); - _bufferOffset = 0; - _bufferLength = 0; - } - - public void Close() { - _flacReader.Close(); - } - - public NameValueCollection Tags - { - get { return _flacReader.Tags; } - set { _flacReader.Tags = value; } - } - - public bool UpdateTags(bool preserveTime) - { - return _flacReader.UpdateTags(preserveTime); - } - - public ulong Length { - get { - return (ulong) _flacReader.Length; - } - } - - public ulong Remaining { - get { - return (ulong) _flacReader.Remaining + SamplesInBuffer; - } - } - - public ulong Position { - get { - return (ulong) _flacReader.Position - SamplesInBuffer; - } - set { - _flacReader.Position = (long) value; - _bufferOffset = 0; - _bufferLength = 0; - } - } - - private uint SamplesInBuffer { - get { - return (uint) (_bufferLength - _bufferOffset); - } - } - - public int BitsPerSample { - get { - return _flacReader.BitsPerSample; - } - } - - public int ChannelCount { - get { - return _flacReader.ChannelCount; - } - } - - public int SampleRate { - get { - return _flacReader.SampleRate; - } - } - - public uint Read(int [,] buff, uint sampleCount) { - if (_flacReader.BitsPerSample != 16) { - throw new Exception("Reading is only supported for 16 bit sample depth."); - } - int chanCount = _flacReader.ChannelCount; - uint copyCount; - uint buffOffset = 0; - uint samplesNeeded = sampleCount; - - while (samplesNeeded != 0) { - if (SamplesInBuffer == 0) { - _bufferOffset = 0; - _bufferLength = (uint) _flacReader.Read(out _sampleBuffer); - } - - copyCount = Math.Min(samplesNeeded, SamplesInBuffer); - Array.Copy(_sampleBuffer, _bufferOffset * chanCount, buff, buffOffset * chanCount, copyCount * chanCount); - - samplesNeeded -= copyCount; - buffOffset += copyCount; - _bufferOffset += copyCount; - } - - return sampleCount; - } - - public string Path { get { return _flacReader.Path; } } - } - - class FLACWriter : IAudioDest { - FLACDotNet.FLACWriter _flacWriter; - int _bitsPerSample; - int _channelCount; - int _sampleRate; - - public FLACWriter(string path, int bitsPerSample, int channelCount, int sampleRate) { - if (bitsPerSample != 16 && bitsPerSample != 24) { - throw new Exception("Bits per sample must be 16 or 24."); - } - _bitsPerSample = bitsPerSample; - _channelCount = channelCount; - _sampleRate = sampleRate; - _flacWriter = new FLACDotNet.FLACWriter(path, bitsPerSample, channelCount, sampleRate); - } - - public long FinalSampleCount { - get { - return _flacWriter.FinalSampleCount; - } - set { - _flacWriter.FinalSampleCount = value; - } - } - - public int CompressionLevel { - get { - return _flacWriter.CompressionLevel; - } - set { - _flacWriter.CompressionLevel = value; - } - } - - public bool Verify { - get { - return _flacWriter.Verify; - } - set { - _flacWriter.Verify = value; - } - } - - public bool SetTags(NameValueCollection tags) - { - _flacWriter.SetTags (tags); - return true; - } - - public void Close() { - _flacWriter.Close(); - } - - public void Write(int[,] buff, uint sampleCount) - { - _flacWriter.Write(buff, (int) sampleCount); - } - - public string Path { get { return _flacWriter.Path; } } - } -#endif - -#if !MONO - class APEReader : IAudioSource { - APEDotNet.APEReader _apeReader; - int[,] _sampleBuffer; - uint _bufferOffset, _bufferLength; - - public APEReader(string path, Stream IO) { - _apeReader = new APEDotNet.APEReader(path, IO); - _bufferOffset = 0; - _bufferLength = 0; - } - - public void Close() { - _apeReader.Close(); - } - - public ulong Length { - get { - return (ulong) _apeReader.Length; - } - } - - public ulong Remaining { - get { - return (ulong) _apeReader.Remaining + SamplesInBuffer; - } - } - - public ulong Position { - get { - return (ulong) _apeReader.Position - SamplesInBuffer; - } - set { - _apeReader.Position = (long) value; - _bufferOffset = 0; - _bufferLength = 0; - } - } - - private uint SamplesInBuffer { - get { - return (uint) (_bufferLength - _bufferOffset); - } - } - - public int BitsPerSample { - get { - return _apeReader.BitsPerSample; - } - } - - public int ChannelCount { - get { - return _apeReader.ChannelCount; - } - } - - public int SampleRate { - get { - return _apeReader.SampleRate; - } - } - - public NameValueCollection Tags - { - get { return _apeReader.Tags; } - set { _apeReader.Tags = value; } - } - - private unsafe void APESamplesToFLACSamples(int[,] inSamples, uint inSampleOffset, - int[,] outSamples, uint outSampleOffset, uint sampleCount, int channelCount) - { - uint loopCount = sampleCount * (uint) channelCount; - - if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) || - (outSamples.GetLength(0) - outSampleOffset < sampleCount)) - { - throw new IndexOutOfRangeException(); - } - - fixed (int* pInSamplesFixed = &inSamples[inSampleOffset, 0]) { - fixed (int * pOutSamplesFixed = &outSamples[outSampleOffset, 0]) { - int* pInSamples = pInSamplesFixed; - int* pOutSamples = pOutSamplesFixed; - - for (int i = 0; i < loopCount; i++) { - *(pOutSamples++) = *(pInSamples++); - } - } - } - } - - public uint Read(int[,] buff, uint sampleCount) { - if (_apeReader.BitsPerSample != 16) { - throw new Exception("Reading is only supported for 16 bit sample depth."); - } - int chanCount = _apeReader.ChannelCount; - uint samplesNeeded, copyCount, buffOffset; - - buffOffset = 0; - samplesNeeded = sampleCount; - - while (samplesNeeded != 0) { - if (SamplesInBuffer == 0) { - _bufferOffset = 0; - _bufferLength = (uint) _apeReader.Read(out _sampleBuffer); - } - - copyCount = Math.Min(samplesNeeded, SamplesInBuffer); - - - Array.Copy(_sampleBuffer, _bufferOffset * chanCount, buff, buffOffset * chanCount, copyCount * chanCount); - //APESamplesToFLACSamples(_sampleBuffer, _bufferOffset, buff, buffOffset, - // copyCount, chanCount); - - samplesNeeded -= copyCount; - buffOffset += copyCount; - _bufferOffset += copyCount; - } - - return sampleCount; - } - - public string Path { get { return _apeReader.Path; } } - } - - class APEWriter : IAudioDest - { - APEDotNet.APEWriter _apeWriter; - byte[] _sampleBuffer; - int _bitsPerSample; - int _channelCount; - int _sampleRate; - int _blockAlign; - - public APEWriter(string path, int bitsPerSample, int channelCount, int sampleRate) - { - if (bitsPerSample != 16 && bitsPerSample != 24) - { - throw new Exception("Bits per sample must be 16 or 24."); - } - _bitsPerSample = bitsPerSample; - _channelCount = channelCount; - _sampleRate = sampleRate; - _blockAlign = _channelCount * ((_bitsPerSample + 7) / 8); - _apeWriter = new APEDotNet.APEWriter(path, bitsPerSample, channelCount, sampleRate); - } - - public long FinalSampleCount - { - get { return _apeWriter.FinalSampleCount; } - set { _apeWriter.FinalSampleCount = (int) value; } - } - public int CompressionLevel - { - get { return _apeWriter.CompressionLevel; } - set { _apeWriter.CompressionLevel = value; } - } - public bool SetTags(NameValueCollection tags) - { - _apeWriter.SetTags(tags); - return true; - } - public void Close() - { - _apeWriter.Close(); - } - public void Write(int [,] buff, uint sampleCount) - { - if (_sampleBuffer == null || _sampleBuffer.Length < sampleCount * _blockAlign) - _sampleBuffer = new byte[sampleCount * _blockAlign]; - AudioCodecsDotNet.AudioCodecsDotNet.FLACSamplesToBytes (buff, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample); - _apeWriter.Write(_sampleBuffer, sampleCount); - } - public string Path { get { return _apeWriter.Path; } } - } -#endif - -#if !MONO - class WavPackReader : IAudioSource { - WavPackDotNet.WavPackReader _wavPackReader; - - public WavPackReader(string path, Stream IO, Stream IO_WVC) { - _wavPackReader = new WavPackDotNet.WavPackReader(path, IO, IO_WVC); - } - - public void Close() { - _wavPackReader.Close(); - } - - public ulong Length { - get { - return (ulong) _wavPackReader.Length; - } - } - - public ulong Remaining { - get { - return (ulong) _wavPackReader.Remaining; - } - } - - public ulong Position { - get { - return (ulong) _wavPackReader.Position; - } - set { - _wavPackReader.Position = (int) value; - } - } - - public int BitsPerSample { - get { - return _wavPackReader.BitsPerSample; - } - } - - public int ChannelCount { - get { - return _wavPackReader.ChannelCount; - } - } - - public int SampleRate { - get { - return _wavPackReader.SampleRate; - } - } - - public NameValueCollection Tags - { - get { return _wavPackReader.Tags; } - set { _wavPackReader.Tags = value; } - } - - public uint Read(int[,] buff, uint sampleCount) { - if (_wavPackReader.BitsPerSample != 16) { - throw new Exception("Reading is only supported for 16 bit sample depth."); - } - _wavPackReader.Read(buff, (int) sampleCount); - return sampleCount; - } - - public string Path { get { return _wavPackReader.Path; } } - } - - class WavPackWriter : IAudioDest { - WavPackDotNet.WavPackWriter _wavPackWriter; - int _bitsPerSample; - int _channelCount; - int _sampleRate; - int _blockAlign; - byte[] _sampleBuffer; - - public WavPackWriter(string path, int bitsPerSample, int channelCount, int sampleRate) { - if (bitsPerSample != 16 && bitsPerSample != 24) - { - throw new Exception("Bits per sample must be 16 or 24."); - } - _bitsPerSample = bitsPerSample; - _channelCount = channelCount; - _sampleRate = sampleRate; - _blockAlign = _channelCount * ((_bitsPerSample + 7) / 8); - _wavPackWriter = new WavPackDotNet.WavPackWriter(path, bitsPerSample, channelCount, sampleRate); - } - - public bool SetTags(NameValueCollection tags) - { - _wavPackWriter.SetTags(tags); - return true; - } - - public long FinalSampleCount { - get { - return _wavPackWriter.FinalSampleCount; - } - set { - _wavPackWriter.FinalSampleCount = (int)value; - } - } - - public int CompressionMode { - get { - return _wavPackWriter.CompressionMode; - } - set { - _wavPackWriter.CompressionMode = value; - } - } - - public int ExtraMode { - get { - return _wavPackWriter.ExtraMode; - } - set { - _wavPackWriter.ExtraMode = value; - } - } - - public bool MD5Sum - { - get - { - return _wavPackWriter.MD5Sum; - } - set - { - _wavPackWriter.MD5Sum = value; - } - } - - public void Close() { - _wavPackWriter.Close(); - } - - public void Write(int[,] sampleBuffer, uint sampleCount) { - if (MD5Sum) - { - if (_sampleBuffer == null || _sampleBuffer.Length < sampleCount * _blockAlign) - _sampleBuffer = new byte[sampleCount * _blockAlign]; - AudioCodecsDotNet.AudioCodecsDotNet.FLACSamplesToBytes(sampleBuffer, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample); - _wavPackWriter.UpdateHash(_sampleBuffer, (int) sampleCount * _blockAlign); - } - _wavPackWriter.Write(sampleBuffer, (int) sampleCount); - } - - public string Path { get { return _wavPackWriter.Path; } } - } -#endif } \ No newline at end of file diff --git a/CUEToolsLib/Main.cs b/CUEToolsLib/Main.cs index 408984b..c306a83 100644 --- a/CUEToolsLib/Main.cs +++ b/CUEToolsLib/Main.cs @@ -31,6 +31,9 @@ using AudioCodecsDotNet; using HDCDDotNet; #if !MONO using UnRarDotNet; +using FLACDotNet; +using APEDotNet; +using WavPackDotNet; #endif namespace CUEToolsLib diff --git a/FLACDotNet/FLACDotNet.vcproj b/FLACDotNet/FLACDotNet.vcproj index cb73c9f..d11a418 100644 --- a/FLACDotNet/FLACDotNet.vcproj +++ b/FLACDotNet/FLACDotNet.vcproj @@ -328,6 +328,10 @@ RelativePath="System.XML.dll" AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL" /> + @@ -67,9 +68,11 @@ namespace FLACDotNet { [UnmanagedFunctionPointer(CallingConvention::Cdecl)] public delegate FLAC__bool DecoderEofDelegate (const FLAC__StreamDecoder *decoder, void *client_data); - public ref class FLACReader { + public ref class FLACReader : public IAudioSource + { public: - FLACReader(String^ path, Stream^ IO) { + FLACReader(String^ path, Stream^ IO) + { _tags = gcnew NameValueCollection(); _writeDel = gcnew DecoderWriteDelegate(this, &FLACReader::WriteCallback); @@ -84,9 +87,10 @@ namespace FLACDotNet { _decoderActive = false; _sampleOffset = 0; - _samplesWaiting = 0; _sampleBuffer = nullptr; _path = path; + _bufferOffset = 0; + _bufferLength = 0; _IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read); @@ -122,50 +126,53 @@ namespace FLACDotNet { Close (); } - property Int32 BitsPerSample { + virtual property Int32 BitsPerSample { Int32 get() { return _bitsPerSample; } } - property Int32 ChannelCount { + virtual property Int32 ChannelCount { Int32 get() { return _channelCount; } } - property Int32 SampleRate { + virtual property Int32 SampleRate { Int32 get() { return _sampleRate; } } - property Int64 Length { - Int64 get() { + virtual property UInt64 Length { + UInt64 get() { return _sampleCount; } } - property Int64 Position { - Int64 get() { - return _sampleOffset; + virtual property UInt64 Position { + UInt64 get() + { + return _sampleOffset - SamplesInBuffer; } - void set(Int64 offset) { + void set(UInt64 offset) + { _sampleOffset = offset; - _samplesWaiting = 0; + _bufferOffset = 0; + _bufferLength = 0; if (!FLAC__stream_decoder_seek_absolute(_decoder, offset)) { throw gcnew Exception("Unable to seek."); } } } - property String^ Path { + virtual property String^ Path { String^ get() { return _path; } } - property NameValueCollection^ Tags { + virtual property NameValueCollection^ Tags { NameValueCollection^ get () { return _tags; } @@ -238,13 +245,13 @@ namespace FLACDotNet { return 0 != res; } - property Int64 Remaining { - Int64 get() { - return _sampleCount - _sampleOffset; + virtual property UInt64 Remaining { + UInt64 get() { + return _sampleCount - _sampleOffset + SamplesInBuffer; } } - void Close() { + virtual void Close() { if (_decoderActive) { FLAC__stream_decoder_finish(_decoder); @@ -258,18 +265,30 @@ namespace FLACDotNet { } } - Int32 Read([Out] array^% sampleBuffer) + virtual UInt32 Read([Out] array^ buff, UInt32 sampleCount) { - while (_samplesWaiting == 0) { - if (!FLAC__stream_decoder_process_single(_decoder)) { - throw gcnew Exception("An error occurred while decoding."); - } - } + UInt32 buffOffset = 0; + UInt32 samplesNeeded = sampleCount; - int sampleCount = _samplesWaiting; - sampleBuffer = _sampleBuffer; - _sampleOffset += sampleCount; - _samplesWaiting = 0; + while (samplesNeeded != 0) + { + if (SamplesInBuffer == 0) + { + _bufferOffset = 0; + _bufferLength = 0; + do + { + if (!FLAC__stream_decoder_process_single(_decoder)) + throw gcnew Exception("An error occurred while decoding."); + } while (_bufferLength == 0); + _sampleOffset += _bufferLength; + } + UInt32 copyCount = Math::Min(samplesNeeded, SamplesInBuffer); + Array::Copy(_sampleBuffer, _bufferOffset * _channelCount, buff, buffOffset * _channelCount, copyCount * _channelCount); + samplesNeeded -= copyCount; + buffOffset += copyCount; + _bufferOffset += copyCount; + } return sampleCount; } @@ -287,18 +306,25 @@ namespace FLACDotNet { Int32 _bitsPerSample, _channelCount, _sampleRate; array^ _sampleBuffer; array^ _readBuffer; - int _samplesWaiting; NameValueCollection^ _tags; String^ _path; bool _decoderActive; Stream^ _IO; + UInt32 _bufferOffset, _bufferLength; + + property UInt32 SamplesInBuffer { + UInt32 get () + { + return (UInt32) (_bufferLength - _bufferOffset); + } + } FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { Int32 sampleCount = frame->header.blocksize; - if (_samplesWaiting > 0) { + if (_bufferLength > 0) { throw gcnew Exception("Received unrequested samples."); } @@ -325,8 +351,7 @@ namespace FLACDotNet { } } - _samplesWaiting = sampleCount; - + _bufferLength = sampleCount; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } @@ -425,9 +450,14 @@ namespace FLACDotNet { } }; - public ref class FLACWriter { + public ref class FLACWriter : IAudioDest + { public: - FLACWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) { + FLACWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) + { + if (bitsPerSample != 16 && bitsPerSample != 24) + throw gcnew Exception("Bits per sample must be 16 or 24."); + _initialized = false; _path = path; _finalSampleCount = 0; @@ -447,7 +477,7 @@ namespace FLACDotNet { FLAC__stream_encoder_set_sample_rate(_encoder, sampleRate); } - void Close() { + virtual void Close() { FLAC__stream_encoder_finish(_encoder); for (int i = 0; i < _metadataCount; i++) { @@ -466,7 +496,7 @@ namespace FLACDotNet { _tags->Clear (); } - property Int64 FinalSampleCount { + virtual property Int64 FinalSampleCount { Int64 get() { return _finalSampleCount; } @@ -481,6 +511,32 @@ namespace FLACDotNet { } } + virtual bool SetTags (NameValueCollection^ tags) + { + _tags = tags; + return true; + } + + virtual property String^ Path { + String^ get() { + return _path; + } + } + + virtual void Write(array^ sampleBuffer, UInt32 sampleCount) { + if (!_initialized) Initialize(); + + pin_ptr pSampleBuffer = &sampleBuffer[0, 0]; + + if (!FLAC__stream_encoder_process_interleaved(_encoder, + (const FLAC__int32*)pSampleBuffer, sampleCount)) + { + throw gcnew Exception("An error occurred while encoding."); + } + + _samplesWritten += sampleCount; + } + property Int32 CompressionLevel { Int32 get() { return _compressionLevel; @@ -514,30 +570,6 @@ namespace FLACDotNet { } } - void SetTags (NameValueCollection^ tags) { - _tags = tags; - } - - property String^ Path { - String^ get() { - return _path; - } - } - - void Write(array^ sampleBuffer, Int32 sampleCount) { - if (!_initialized) Initialize(); - - pin_ptr pSampleBuffer = &sampleBuffer[0, 0]; - - if (!FLAC__stream_encoder_process_interleaved(_encoder, - (const FLAC__int32*)pSampleBuffer, sampleCount)) - { - throw gcnew Exception("An error occurred while encoding."); - } - - _samplesWritten += sampleCount; - } - private: FLAC__StreamEncoder *_encoder; bool _initialized; diff --git a/HDCDDotNet/HDCDDotNet.cs b/HDCDDotNet/HDCDDotNet.cs index 0465ef5..cbdf9c3 100644 --- a/HDCDDotNet/HDCDDotNet.cs +++ b/HDCDDotNet/HDCDDotNet.cs @@ -116,7 +116,7 @@ namespace HDCDDotNet { if (_inSampleBuffer == null || _inSampleBuffer.GetLength(0) < sampleCount) _inSampleBuffer = new int[sampleCount, _channelCount]; - AudioCodecsDotNet.AudioCodecsDotNet.BytesToFLACSamples_16(buff, 0, _inSampleBuffer, 0, sampleCount, _channelCount); + AudioSamples.BytesToFLACSamples_16(buff, 0, _inSampleBuffer, 0, sampleCount, _channelCount); Process(_inSampleBuffer, sampleCount); } diff --git a/MAC_SDK/Source/MACLib/Assembly/Assembly.obj b/MAC_SDK/Source/MACLib/Assembly/Assembly.obj index 1535ff7..5424340 100644 Binary files a/MAC_SDK/Source/MACLib/Assembly/Assembly.obj and b/MAC_SDK/Source/MACLib/Assembly/Assembly.obj differ diff --git a/WavPackDotNet/WavPackDotNet.cpp b/WavPackDotNet/WavPackDotNet.cpp index 244c700..00727e6 100644 --- a/WavPackDotNet/WavPackDotNet.cpp +++ b/WavPackDotNet/WavPackDotNet.cpp @@ -35,6 +35,7 @@ using namespace System::Collections::Specialized; using namespace System::Security::Cryptography; using namespace System::IO; using namespace APETagsDotNet; +using namespace AudioCodecsDotNet; #include #include @@ -59,9 +60,11 @@ namespace WavPackDotNet { [UnmanagedFunctionPointer(CallingConvention::Cdecl)] public delegate int DecoderCanSeekDelegate(void *id); - public ref class WavPackReader { + public ref class WavPackReader : public IAudioSource + { public: - WavPackReader(String^ path, Stream^ IO, Stream^ IO_WVC) { + WavPackReader(String^ path, Stream^ IO, Stream^ IO_WVC) + { char errorMessage[256]; _readDel = gcnew DecoderReadDelegate (this, &WavPackReader::ReadCallback); @@ -89,14 +92,6 @@ namespace WavPackDotNet { _IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read); _IO_WVC = (IO != nullptr) ? IO_WVC : System::IO::File::Exists (path+"c") ? gcnew FileStream (path+"c", FileMode::Open, FileAccess::Read, FileShare::Read) : nullptr; - //IntPtr pathChars; - //pathChars = Marshal::StringToHGlobalUni(path); - //size_t pathLen = wcslen ((const wchar_t*)pathChars.ToPointer())+1; - //wchar_t * pPath = new wchar_t[pathLen]; - //memcpy ((void*) pPath, (const wchar_t*)pathChars.ToPointer(), pathLen*sizeof(wchar_t)); - //Marshal::FreeHGlobal(pathChars); - //_wpc = WavpackOpenFileInput (pPath, errorMessage, OPEN_WVC, 0); - _wpc = WavpackOpenFileInputEx (ioReader, "v", _IO_WVC != nullptr ? "c" : NULL, errorMessage, OPEN_WVC, 0); if (_wpc == NULL) { throw gcnew Exception("Unable to initialize the decoder."); @@ -114,35 +109,35 @@ namespace WavPackDotNet { delete ioReader; } - property Int32 BitsPerSample { + virtual property Int32 BitsPerSample { Int32 get() { return _bitsPerSample; } } - property Int32 ChannelCount { + virtual property Int32 ChannelCount { Int32 get() { return _channelCount; } } - property Int32 SampleRate { + virtual property Int32 SampleRate { Int32 get() { return _sampleRate; } } - property Int32 Length { - Int32 get() { + virtual property UInt64 Length { + UInt64 get() { return _sampleCount; } } - property Int32 Position { - Int32 get() { + virtual property UInt64 Position { + UInt64 get() { return _sampleOffset; } - void set(Int32 offset) { + void set(UInt64 offset) { _sampleOffset = offset; if (!WavpackSeekSample(_wpc, offset)) { throw gcnew Exception("Unable to seek."); @@ -150,19 +145,19 @@ namespace WavPackDotNet { } } - property Int32 Remaining { - Int32 get() { + virtual property UInt64 Remaining { + UInt64 get() { return _sampleCount - _sampleOffset; } } - property String^ Path { + virtual property String^ Path { String^ get() { return _path; } } - property NameValueCollection^ Tags { + virtual property NameValueCollection^ Tags { NameValueCollection^ get () { if (!_tags) { @@ -177,7 +172,7 @@ namespace WavPackDotNet { } } - void Close() + virtual void Close() { _wpc = WavpackCloseFile(_wpc); if (_IO != nullptr) @@ -192,16 +187,14 @@ namespace WavPackDotNet { } } - void Read(array^ sampleBuffer, Int32 sampleCount) { + virtual UInt32 Read(array^ sampleBuffer, UInt32 sampleCount) + { pin_ptr pSampleBuffer = &sampleBuffer[0, 0]; - int samplesRead; - - samplesRead = WavpackUnpackSamples(_wpc, pSampleBuffer, sampleCount); + int samplesRead = WavpackUnpackSamples(_wpc, pSampleBuffer, sampleCount); _sampleOffset += samplesRead; - - if (samplesRead != sampleCount) { + if (samplesRead != sampleCount) throw gcnew Exception("Decoder returned a different number of samples than requested."); - } + return sampleCount; } private: @@ -312,14 +305,17 @@ namespace WavPackDotNet { } }; - public ref class WavPackWriter { + public ref class WavPackWriter : IAudioDest + { public: - WavPackWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) { + WavPackWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) + { IntPtr pathChars; - if ((channelCount != 1) && (channelCount != 2)) { + if (channelCount != 1 && channelCount != 2) throw gcnew Exception("Only stereo and mono audio formats are allowed."); - } + if (bitsPerSample != 16 && bitsPerSample != 24) + throw gcnew Exception("Bits per sample must be 16 or 24."); _path = path; _tags = gcnew NameValueCollection(); @@ -330,6 +326,7 @@ namespace WavPackDotNet { _bitsPerSample = bitsPerSample; _channelCount = channelCount; _sampleRate = sampleRate; + _blockAlign = _channelCount * ((_bitsPerSample + 7) / 8); pathChars = Marshal::StringToHGlobalUni(path); _hFile = _wfopen((const wchar_t*)pathChars.ToPointer(), L"w+b"); @@ -339,7 +336,8 @@ namespace WavPackDotNet { } } - void Close() { + virtual void Close() + { if (_md5Sum) { _md5hasher->TransformFinalBlock (gcnew array(1), 0, 0); @@ -365,21 +363,56 @@ namespace WavPackDotNet { } } - property Int32 FinalSampleCount { - Int32 get() { + virtual property Int64 FinalSampleCount + { + Int64 get() + { return _finalSampleCount; } - void set(Int32 value) { - if (value < 0) { + void set(Int64 value) + { + if (value < 0) throw gcnew Exception("Invalid final sample count."); - } - if (_initialized) { + if (_initialized) throw gcnew Exception("Final sample count cannot be changed after encoding begins."); - } _finalSampleCount = value; } } + virtual void Write(array^ sampleBuffer, UInt32 sampleCount) + { + if (!_initialized) + Initialize(); + + if (MD5Sum) + { + if (_sampleBuffer == nullptr || _sampleBuffer.Length < sampleCount * _blockAlign) + _sampleBuffer = gcnew array(sampleCount * _blockAlign); + AudioSamples::FLACSamplesToBytes(sampleBuffer, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample); + UpdateHash(_sampleBuffer, (int) sampleCount * _blockAlign); + } + + pin_ptr pSampleBuffer = &sampleBuffer[0, 0]; + if (!WavpackPackSamples(_wpc, (int32_t*)pSampleBuffer, sampleCount)) { + throw gcnew Exception("An error occurred while encoding."); + } + + _samplesWritten += sampleCount; + } + + virtual property String^ Path + { + String^ get() { + return _path; + } + } + + virtual bool SetTags (NameValueCollection^ tags) + { + _tags = tags; + return true; + } + property Int32 CompressionMode { Int32 get() { return _compressionMode; @@ -422,38 +455,18 @@ namespace WavPackDotNet { _md5hasher->TransformBlock (buff, 0, len, buff, 0); } - void Write(array^ sampleBuffer, Int32 sampleCount) { - if (!_initialized) Initialize(); - - pin_ptr pSampleBuffer = &sampleBuffer[0, 0]; - if (!WavpackPackSamples(_wpc, (int32_t*)pSampleBuffer, sampleCount)) { - throw gcnew Exception("An error occurred while encoding."); - } - - _samplesWritten += sampleCount; - } - - property String^ Path { - String^ get() { - return _path; - } - } - - void SetTags (NameValueCollection^ tags) { - _tags = tags; - } - private: FILE *_hFile; bool _initialized; WavpackContext *_wpc; Int32 _finalSampleCount, _samplesWritten; - Int32 _bitsPerSample, _channelCount, _sampleRate; + Int32 _bitsPerSample, _channelCount, _sampleRate, _blockAlign; Int32 _compressionMode, _extraMode; NameValueCollection^ _tags; String^ _path; bool _md5Sum; MD5^ _md5hasher; + array^ _sampleBuffer; void Initialize() { WavpackConfig config; diff --git a/WavPackDotNet/WavPackDotNet.vcproj b/WavPackDotNet/WavPackDotNet.vcproj index 8416406..de23456 100644 --- a/WavPackDotNet/WavPackDotNet.vcproj +++ b/WavPackDotNet/WavPackDotNet.vcproj @@ -92,81 +92,6 @@ Name="VCPostBuildEventTool" /> - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + +