diff --git a/CUETools.Codecs.WavPack/CUETools.Codecs.WavPack.cpp b/CUETools.Codecs.WavPack/CUETools.Codecs.WavPack.cpp deleted file mode 100644 index df54ebf..0000000 --- a/CUETools.Codecs.WavPack/CUETools.Codecs.WavPack.cpp +++ /dev/null @@ -1,550 +0,0 @@ -// **************************************************************************** -// -// Copyright (c) 2006-2007 Moitah (moitah@yahoo.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the author nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// **************************************************************************** - -using namespace System; -using namespace System::Runtime::InteropServices; -using namespace System::Collections::Specialized; -using namespace System::Security::Cryptography; -using namespace System::IO; -using namespace APETagsDotNet; -using namespace CUETools::Codecs; - -#include -#include -#include "wavpack.h" -#include - -namespace WavPackDotNet { - int write_block(void *id, void *data, int32_t length); - - [UnmanagedFunctionPointer(CallingConvention::Cdecl)] - public delegate int32_t DecoderReadDelegate(void *id, void *data, int32_t bcount); - [UnmanagedFunctionPointer(CallingConvention::Cdecl)] - public delegate uint32_t DecoderTellDelegate(void *id); - [UnmanagedFunctionPointer(CallingConvention::Cdecl)] - public delegate int DecoderSeekDelegate(void *id, uint32_t pos); - [UnmanagedFunctionPointer(CallingConvention::Cdecl)] - public delegate int DecoderSeekRelativeDelegate(void *id, int32_t delta, int mode); - [UnmanagedFunctionPointer(CallingConvention::Cdecl)] - public delegate int DecoderPushBackDelegate(void *id, int c); - [UnmanagedFunctionPointer(CallingConvention::Cdecl)] - public delegate uint32_t DecoderLengthDelegate(void *id); - [UnmanagedFunctionPointer(CallingConvention::Cdecl)] - public delegate int DecoderCanSeekDelegate(void *id); - - public ref class WavPackReader : public IAudioSource - { - public: - WavPackReader(String^ path, Stream^ IO, Stream^ IO_WVC) - { - char errorMessage[256]; - - _readDel = gcnew DecoderReadDelegate (this, &WavPackReader::ReadCallback); - _tellDel = gcnew DecoderTellDelegate (this, &WavPackReader::TellCallback); - _seekDel = gcnew DecoderSeekDelegate (this, &WavPackReader::SeekCallback); - _seekRelDel = gcnew DecoderSeekRelativeDelegate (this, &WavPackReader::SeekRelCallback); - _pushBackDel = gcnew DecoderPushBackDelegate (this, &WavPackReader::PushBackCallback); - _lengthDel = gcnew DecoderLengthDelegate (this, &WavPackReader::LengthCallback); - _canSeekDel = gcnew DecoderCanSeekDelegate (this, &WavPackReader::CanSeekCallback); - - ioReader = new WavpackStreamReader; - ioReader->read_bytes = (int32_t (*)(void *, void *, int32_t)) Marshal::GetFunctionPointerForDelegate(_readDel).ToPointer(); - ioReader->get_pos = (uint32_t (*)(void *)) Marshal::GetFunctionPointerForDelegate(_tellDel).ToPointer(); - ioReader->set_pos_abs = (int (*)(void *, uint32_t)) Marshal::GetFunctionPointerForDelegate(_seekDel).ToPointer(); - ioReader->set_pos_rel = (int (*)(void *, int32_t, int)) Marshal::GetFunctionPointerForDelegate(_seekRelDel).ToPointer(); - ioReader->push_back_byte = (int (*)(void *, int)) Marshal::GetFunctionPointerForDelegate(_pushBackDel).ToPointer(); - ioReader->get_length = (uint32_t (*)(void *)) Marshal::GetFunctionPointerForDelegate(_lengthDel).ToPointer(); - ioReader->can_seek = (int (*)(void *)) Marshal::GetFunctionPointerForDelegate(_canSeekDel).ToPointer(); - ioReader->write_bytes = NULL; - - _IO_ungetc = _IO_WVC_ungetc = -1; - - _path = path; - - _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; - - _wpc = WavpackOpenFileInputEx (ioReader, "v", _IO_WVC != nullptr ? "c" : NULL, errorMessage, OPEN_WVC, 0); - if (_wpc == NULL) { - throw gcnew Exception("Unable to initialize the decoder."); - } - - _bitsPerSample = WavpackGetBitsPerSample(_wpc); - _channelCount = WavpackGetNumChannels(_wpc); - _sampleRate = WavpackGetSampleRate(_wpc); - _sampleCount = WavpackGetNumSamples(_wpc); - _sampleOffset = 0; - } - - ~WavPackReader() - { - delete ioReader; - } - - virtual property Int32 BitsPerSample { - Int32 get() { - return _bitsPerSample; - } - } - - virtual property Int32 ChannelCount { - Int32 get() { - return _channelCount; - } - } - - virtual property Int32 SampleRate { - Int32 get() { - return _sampleRate; - } - } - - virtual property UInt64 Length { - UInt64 get() { - return _sampleCount; - } - } - - virtual property UInt64 Position { - UInt64 get() { - return _sampleOffset; - } - void set(UInt64 offset) { - _sampleOffset = offset; - if (!WavpackSeekSample(_wpc, offset)) { - throw gcnew Exception("Unable to seek."); - } - } - } - - virtual property UInt64 Remaining { - UInt64 get() { - return _sampleCount - _sampleOffset; - } - } - - virtual property String^ Path { - String^ get() { - return _path; - } - } - - virtual property NameValueCollection^ Tags { - NameValueCollection^ get () { - if (!_tags) - { - APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true); - _tags = apeTag->GetStringTags (true); - apeTag->Close (); - } - return _tags; - } - void set (NameValueCollection ^tags) { - _tags = tags; - } - } - - virtual void Close() - { - _wpc = WavpackCloseFile(_wpc); - if (_IO != nullptr) - { - _IO->Close (); - _IO = nullptr; - } - if (_IO_WVC != nullptr) - { - _IO_WVC->Close (); - _IO_WVC = nullptr; - } - } - - virtual UInt32 Read(array^ sampleBuffer, UInt32 sampleCount) - { - pin_ptr pSampleBuffer = &sampleBuffer[0, 0]; - int samplesRead = WavpackUnpackSamples(_wpc, pSampleBuffer, sampleCount); - _sampleOffset += samplesRead; - if (samplesRead != sampleCount) - throw gcnew Exception("Decoder returned a different number of samples than requested."); - return sampleCount; - } - - private: - WavpackContext *_wpc; - NameValueCollection^ _tags; - Int32 _sampleCount, _sampleOffset; - Int32 _bitsPerSample, _channelCount, _sampleRate; - String^ _path; - Stream^ _IO; - Stream^ _IO_WVC; - DecoderReadDelegate^ _readDel; - DecoderTellDelegate^ _tellDel; - DecoderSeekDelegate^ _seekDel; - DecoderSeekRelativeDelegate^ _seekRelDel; - DecoderPushBackDelegate^ _pushBackDel; - DecoderLengthDelegate^ _lengthDel; - DecoderCanSeekDelegate^ _canSeekDel; - array^ _readBuffer; - int _IO_ungetc, _IO_WVC_ungetc; - WavpackStreamReader* ioReader; - - int32_t ReadCallback (void *id, void *data, int32_t bcount) - { - Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO; - int IO_ungetc = (*(char*)id=='c') ? _IO_WVC_ungetc : _IO_ungetc; - int unget_len = 0; - - if (IO_ungetc != -1) - { - *(unsigned char*)data = (unsigned char) IO_ungetc; - if (IO == _IO) - _IO_ungetc = -1; - else - _IO_WVC_ungetc = -1; - bcount --; - if (!bcount) - return 1; - data = 1 + (unsigned char*)data; - unget_len = 1; - } - - if (_readBuffer == nullptr || _readBuffer->Length < bcount) - _readBuffer = gcnew array(bcount < 0x4000 ? 0x4000 : bcount); - int len = IO->Read (_readBuffer, 0, bcount); - if (len) Marshal::Copy (_readBuffer, 0, (IntPtr)data, len); - return len + unget_len; - } - - uint32_t TellCallback(void *id) - { - Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO; - return IO->Position; - } - - int SeekCallback (void *id, uint32_t pos) - { - Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO; - IO->Position = pos; - return 0; - } - - int SeekRelCallback (void *id, int32_t delta, int mode) - { - Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO; - switch (mode) - { - case SEEK_SET: - IO->Seek (delta, System::IO::SeekOrigin::Begin); - break; - case SEEK_END: - IO->Seek (delta, System::IO::SeekOrigin::End); - break; - case SEEK_CUR: - IO->Seek (delta, System::IO::SeekOrigin::Current); - break; - default: - return -1; - } - return 0; - } - - int PushBackCallback (void *id, int c) - { - Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO; - if (IO == _IO) - { - if (_IO_ungetc != -1) - throw gcnew Exception("Double PushBackCallback unsupported."); - _IO_ungetc = c; - } else - { - if (_IO_WVC_ungetc != -1) - throw gcnew Exception("Double PushBackCallback unsupported."); - _IO_WVC_ungetc = c; - } - } - - uint32_t LengthCallback (void *id) - { - Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO; - return IO->Length; - } - - int CanSeekCallback(void *id) - { - Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO; - return IO->CanSeek; - } - }; - - public ref class WavPackWriter : IAudioDest - { - public: - WavPackWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) - { - IntPtr pathChars; - - 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..24."); - - _path = path; - _tags = gcnew NameValueCollection(); - - _compressionMode = 1; - _extraMode = 0; - _blockSize = 0; - - _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"); - Marshal::FreeHGlobal(pathChars); - if (!_hFile) { - throw gcnew Exception("Unable to open file."); - } - } - - virtual void Close() - { - if (_md5Sum) - { - _md5hasher->TransformFinalBlock (gcnew array(1), 0, 0); - pin_ptr md5_digest = &_md5hasher->Hash[0]; - WavpackStoreMD5Sum (_wpc, md5_digest); - } - - WavpackFlushSamples(_wpc); - _wpc = WavpackCloseFile(_wpc); - fclose(_hFile); - - if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) { - throw gcnew Exception("Samples written differs from the expected sample count."); - } - - if (_tags->Count > 0) - { - APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, false); - apeTag->SetStringTags (_tags, true); - apeTag->Save(); - apeTag->Close(); - _tags->Clear (); - } - } - - virtual void Delete() - { - try { Close (); } catch (Exception^) {} - File::Delete(_path); - } - - virtual property Int64 FinalSampleCount - { - Int64 get() - { - return _finalSampleCount; - } - void set(Int64 value) - { - if (value < 0) - throw gcnew Exception("Invalid final sample count."); - if (_initialized) - throw gcnew Exception("Final sample count cannot be changed after encoding begins."); - _finalSampleCount = value; - } - } - - virtual property Int64 BlockSize - { - void set(Int64 value) - { - _blockSize = value; - } - } - - virtual property int BitsPerSample - { - int get() { return _bitsPerSample; } - } - - 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); - } - - if ((_bitsPerSample & 7) != 0) - { - if (_shiftedSampleBuffer == nullptr || _shiftedSampleBuffer.GetLength(0) < sampleCount) - _shiftedSampleBuffer = gcnew array(sampleCount, _channelCount); - for (int i = 0; i < sampleCount; i++) - for (int c = 0; c < _channelCount; c++) - _shiftedSampleBuffer[i,c] = sampleBuffer[i,c] << 8 - (_bitsPerSample & 7); - pin_ptr pSampleBuffer = &_shiftedSampleBuffer[0, 0]; - if (!WavpackPackSamples(_wpc, (int32_t*)pSampleBuffer, sampleCount)) - throw gcnew Exception("An error occurred while encoding."); - } else - { - 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; - } - void set(Int32 value) { - if ((value < 0) || (value > 3)) { - throw gcnew Exception("Invalid compression mode."); - } - _compressionMode = value; - } - } - - property Int32 ExtraMode { - Int32 get() { - return _extraMode; - } - void set(Int32 value) { - if ((value < 0) || (value > 6)) { - throw gcnew Exception("Invalid extra mode."); - } - _extraMode = value; - } - } - - property bool MD5Sum { - bool get() { - return _md5Sum; - } - void set(bool value) { - _md5Sum = value; - } - } - - void UpdateHash(array^ buff, Int32 len) - { - if (!_initialized) Initialize(); - - if (!_md5Sum || !_md5hasher) - throw gcnew Exception("MD5 not enabled."); - _md5hasher->TransformBlock (buff, 0, len, buff, 0); - } - - private: - FILE *_hFile; - bool _initialized; - WavpackContext *_wpc; - Int32 _finalSampleCount, _samplesWritten; - Int32 _bitsPerSample, _channelCount, _sampleRate, _blockAlign; - Int32 _compressionMode, _extraMode, _blockSize; - NameValueCollection^ _tags; - String^ _path; - bool _md5Sum; - MD5^ _md5hasher; - array^ _sampleBuffer; - array^ _shiftedSampleBuffer; - - void Initialize() { - WavpackConfig config; - - _wpc = WavpackOpenFileOutput(write_block, _hFile, NULL); - if (!_wpc) { - throw gcnew Exception("Unable to create the encoder."); - } - - memset(&config, 0, sizeof(WavpackConfig)); - config.bits_per_sample = _bitsPerSample; - config.bytes_per_sample = (_bitsPerSample + 7) / 8; - config.num_channels = _channelCount; - config.channel_mask = 5 - _channelCount; - config.sample_rate = _sampleRate; - if (_compressionMode == 0) config.flags |= CONFIG_FAST_FLAG; - if (_compressionMode == 2) config.flags |= CONFIG_HIGH_FLAG; - if (_compressionMode == 3) config.flags |= CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG; - if (_extraMode != 0) { - config.flags |= CONFIG_EXTRA_MODE; - config.xmode = _extraMode; - } - if (_md5Sum) - { - _md5hasher = gcnew MD5CryptoServiceProvider (); - config.flags |= CONFIG_MD5_CHECKSUM; - } - config.block_samples = (int)_blockSize; - if (_blockSize > 0 && _blockSize < 2048) - config.flags |= CONFIG_MERGE_BLOCKS; - - if (!WavpackSetConfiguration(_wpc, &config, (_finalSampleCount == 0) ? -1 : _finalSampleCount)) { - throw gcnew Exception("Invalid configuration setting."); - } - - if (!WavpackPackInit(_wpc)) { - throw gcnew Exception("Unable to initialize the encoder."); - } - - _initialized = true; - } - }; - -#pragma unmanaged - int write_block(void *id, void *data, int32_t length) { - return (fwrite(data, 1, length, (FILE*)id) == length); - } -}