diff --git a/.gitignore b/.gitignore index 055c62c..3011dd5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,7 @@ launchSettings.json /CUETools/TestResults /ThirdParty/*/libFLAC_dynamic.* /ThirdParty/*/MACLib.* +/ThirdParty/*/MACLibDll.* /ThirdParty/*/wavpackdll.* /ThirdParty/*/libwavpack.* +/ThirdPartyDebug/ diff --git a/CUETools.Codecs.APE/AssemblyInfo.cpp b/CUETools.Codecs.APE/AssemblyInfo.cpp deleted file mode 100644 index 21bd68a..0000000 --- a/CUETools.Codecs.APE/AssemblyInfo.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "stdafx.h" - -using namespace System; -using namespace System::Reflection; -using namespace System::Runtime::CompilerServices; -using namespace System::Runtime::InteropServices; -using namespace System::Security::Permissions; - -// -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -// -[assembly:AssemblyTitleAttribute("APEDotNet")]; -[assembly:AssemblyDescriptionAttribute("")]; -[assembly:AssemblyConfigurationAttribute("")]; -[assembly:AssemblyCompanyAttribute("")]; -[assembly:AssemblyProductAttribute("APEDotNet")]; -[assembly:AssemblyCopyrightAttribute("Copyright (c) Greg Chudov 2008")]; -[assembly:AssemblyTrademarkAttribute("")]; -[assembly:AssemblyCultureAttribute("")]; - -// -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the value or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly:AssemblyVersionAttribute("2.1.7.0")]; - -[assembly:ComVisible(false)]; - -[assembly:CLSCompliantAttribute(true)]; - -[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; diff --git a/CUETools.Codecs.APE/CUETools.Codecs.APE.cpp b/CUETools.Codecs.APE/CUETools.Codecs.APE.cpp deleted file mode 100644 index 199fa52..0000000 --- a/CUETools.Codecs.APE/CUETools.Codecs.APE.cpp +++ /dev/null @@ -1,627 +0,0 @@ -// This is the main DLL file. - -using namespace System; -using namespace System::Text; -using namespace System::Collections::Generic; -using namespace System::Runtime::InteropServices; -using namespace System::IO; -using namespace CUETools::Codecs; - -#define PLATFORM_WINDOWS -#define PLATFORM_WINDOWS_NO_HEADER -#define EXCLUDE_CIO -#include "All.h" -#include "MACLib.h" -#include "IO.h" - -using namespace ::APE; - -namespace CUETools { namespace Codecs { namespace APE { - - class CWinFileIO : public ::APE::CIO - { - public: - - // construction / destruction - CWinFileIO(GCHandle gchIO, GCHandle gchBuffer) - { - _gchIO = gchIO; - _gchBuffer = gchBuffer; - } - ~CWinFileIO() - { - } - - // open / close - int Open(const wchar_t * pName, bool bOpenReadOnly = false) - { - throw gcnew Exception("CIO::Open Unsupported."); - } - int Close() - { - throw gcnew Exception("CIO::Close Unsupported."); - } - - // read / write - int Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead); - int Write(const void * pBuffer, unsigned int nBytesToWrite, unsigned int * pBytesWritten); - - // seek - int Seek(int nDistance, unsigned int nMoveMode); - - // other functions - int SetEOF() - { - throw gcnew Exception("CIO::SetEOF unsupported."); - } - - // creation / destruction - int Create(const wchar_t * pName) - { - throw gcnew Exception("CIO::Create unsupported."); - } - - int Delete() - { - throw gcnew Exception("CIO::Delete unsupported."); - } - - // attributes - int GetPosition(); - unsigned int GetSize(); - - int GetName(wchar_t * pBuffer) - { - throw gcnew Exception("CIO::GetName unsupported."); - } - - private: - GCHandle _gchIO; - GCHandle _gchBuffer; - }; - - ref class AudioDecoder; - - [Newtonsoft::Json::JsonObject(Newtonsoft::Json::MemberSerialization::OptIn)] - public ref class DecoderSettings : public IAudioDecoderSettings - { - public: - DecoderSettings() - { - } - - [System::ComponentModel::Browsable(false)] - virtual property String^ Name - { - String^ get() { return "MAC_SDK"; } - } - - [System::ComponentModel::Browsable(false)] - virtual property String^ Extension - { - String^ get() { return "ape"; } - } - - [System::ComponentModel::Browsable(false)] - virtual property Type^ DecoderType - { - Type^ get() { return AudioDecoder::typeid; } - } - - [System::ComponentModel::Browsable(false)] - virtual property int Priority - { - int get() { return 1; } - } - - virtual IAudioDecoderSettings^ Clone() - { - return (IAudioDecoderSettings^)MemberwiseClone(); - } - - property String^ Version - { - String^ get() - { - return MAC_VERSION_STRING; - } - } - }; - - public ref class AudioDecoder : public IAudioSource - { - public: - AudioDecoder(DecoderSettings^ settings, String^ path, Stream^ IO) - { - m_settings = settings; - pAPEDecompress = NULL; - _sampleOffset = 0; - _bufferOffset = 0; - _bufferLength = 0; - _path = path; - - int nRetVal = 0; - - _IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read); - _readBuffer = gcnew array(0x4000); - _gchIO = GCHandle::Alloc(_IO); - _gchReadBuffer = GCHandle::Alloc(_readBuffer); - _winFileIO = new CWinFileIO(_gchIO, _gchReadBuffer); - pAPEDecompress = CreateIAPEDecompressEx (_winFileIO, &nRetVal); - if (!pAPEDecompress) { - throw gcnew Exception("Unable to open file."); - } - - pcm = gcnew AudioPCMConfig( - pAPEDecompress->GetInfo (APE_INFO_BITS_PER_SAMPLE, 0, 0), - pAPEDecompress->GetInfo (APE_INFO_CHANNELS, 0, 0), - pAPEDecompress->GetInfo (APE_INFO_SAMPLE_RATE, 0, 0), - (AudioPCMConfig::SpeakerConfig)0); - - // make a buffer to hold 16384 blocks of audio data - nBlockAlign = pAPEDecompress->GetInfo (APE_INFO_BLOCK_ALIGN, 0, 0); - _samplesBuffer = gcnew array (16384 * nBlockAlign); - - // loop through the whole file - _sampleCount = pAPEDecompress->GetInfo (APE_DECOMPRESS_TOTAL_BLOCKS, 0, 0); // * ? - } - - ~AudioDecoder () - { - if (_winFileIO) - delete _winFileIO; - if (_gchIO.IsAllocated) - _gchIO.Free(); - if (_gchReadBuffer.IsAllocated) - _gchReadBuffer.Free(); - } - - virtual property AudioPCMConfig^ PCM { - AudioPCMConfig^ get() { - return pcm; - } - } - - virtual property Int64 Length { - Int64 get() { - return _sampleCount; - } - } - - virtual property Int64 Position - { - Int64 get() { - return _sampleOffset - SamplesInBuffer; - } - void set(Int64 offset) { - _sampleOffset = offset; - _bufferOffset = 0; - _bufferLength = 0; - if (pAPEDecompress->Seek ((int) offset /*? */)) - throw gcnew Exception("Unable to seek."); - } - } - - virtual property Int64 Remaining { - Int64 get() { - return _sampleCount - _sampleOffset + SamplesInBuffer; - } - } - - virtual void Close() - { - if (pAPEDecompress) - { - delete pAPEDecompress; - pAPEDecompress = NULL; - } - if (_IO != nullptr) - { - _IO->Close (); - _IO = nullptr; - } - } - - virtual property String^ Path { - String^ get() { - return _path; - } - } - - virtual int Read(AudioBuffer^ buff, int maxLength) - { - buff->Prepare(this, maxLength); - - Int32 buffOffset = 0; - Int32 samplesNeeded = buff->Length; - Int32 _channelCount = pcm->ChannelCount; - - 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; - } - Int32 copyCount = Math::Min(samplesNeeded, SamplesInBuffer); - AudioBuffer::BytesToFLACSamples_16(_samplesBuffer, _bufferOffset*nBlockAlign, buff->Samples, buffOffset, copyCount, _channelCount); - samplesNeeded -= copyCount; - buffOffset += copyCount; - _bufferOffset += copyCount; - } - return buff->Length; - } - - virtual property IAudioDecoderSettings^ Settings { - IAudioDecoderSettings^ get(void) { - return m_settings; - } - } - - private: - ::APE::IAPEDecompress * pAPEDecompress; - - Int64 _sampleCount, _sampleOffset; - AudioPCMConfig^ pcm; - Int32 _bufferOffset, _bufferLength; - int nBlockAlign; - array^ _samplesBuffer; - String^ _path; - Stream^ _IO; - array^ _readBuffer; - CWinFileIO* _winFileIO; - GCHandle _gchIO, _gchReadBuffer; - DecoderSettings^ m_settings; - - property Int32 SamplesInBuffer - { - Int32 get () - { - return _bufferLength - _bufferOffset; - } - } - }; - - ref class AudioEncoder; - - [Newtonsoft::Json::JsonObject(Newtonsoft::Json::MemberSerialization::OptIn)] - public ref class EncoderSettings : public IAudioEncoderSettings - { - public: - [System::ComponentModel::Browsable(false)] - virtual property String^ Name - { - String^ get() { return "MAC_SDK"; } - } - - [System::ComponentModel::Browsable(false)] - virtual property String^ Extension - { - String^ get() { return "ape"; } - } - - [System::ComponentModel::Browsable(false)] - virtual property Type^ EncoderType - { - Type^ get() { return AudioEncoder::typeid; } - } - - [System::ComponentModel::Browsable(false)] - virtual property bool Lossless - { - bool get() { return true; } - } - - [System::ComponentModel::Browsable(false)] - virtual property int Priority - { - int get() { return 1; } - } - - [System::ComponentModel::Browsable(false)] - virtual property String^ SupportedModes - { - String^ get() { return "fast normal high extra insane"; } - } - - [System::ComponentModel::Browsable(false)] - virtual property String^ DefaultMode - { - String^ get() { return "high"; } - } - - [System::ComponentModel::Browsable(false)] - [Newtonsoft::Json::JsonProperty] - virtual property String^ EncoderMode - { - String^ get() { return encoderMode; } - void set(String^ value) { encoderMode = value; } - } - - [System::ComponentModel::Browsable(false)] - virtual property AudioPCMConfig^ PCM - { - AudioPCMConfig^ get() { return pcm; } - void set(AudioPCMConfig^ value) { pcm = value; } - } - - [System::ComponentModel::Browsable(false)] - virtual property int BlockSize - { - int get() { return blockSize; } - void set(int value) { blockSize = value; } - } - - [System::ComponentModel::Browsable(false)] - virtual property int Padding - { - int get() { return padding; } - void set(int value) { padding = value; } - } - - virtual IAudioEncoderSettings^ Clone() - { - return (IAudioEncoderSettings^)MemberwiseClone(); - } - - EncoderSettings() - { - IAudioEncoderSettingsExtensions::Init(this, nullptr); - } - - property String^ Version - { - String^ get() - { - return MAC_VERSION_STRING; - } - } - private: - String ^ encoderMode; - AudioPCMConfig^ pcm; - int blockSize; - int padding; - }; - - public ref class AudioEncoder : IAudioDest - { - public: - AudioEncoder(EncoderSettings^ settings, String^ path, Stream^ IO) - { - _settings = settings; - _IO = IO; - - if (_settings->PCM->ChannelCount != 1 && _settings->PCM->ChannelCount != 2) - throw gcnew Exception("Only stereo and mono audio formats are allowed."); - if (_settings->PCM->BitsPerSample != 16 && _settings->PCM->BitsPerSample != 24) - throw gcnew Exception("Monkey's Audio doesn't support selected bits per sample value."); - - _path = path; - _winFileIO = NULL; - - int nRetVal; - pAPECompress = CreateIAPECompress (&nRetVal); - if (!pAPECompress) - throw gcnew Exception("Unable to open APE compressor."); - } - - ~AudioEncoder() - { - if (_winFileIO) - delete _winFileIO; - if (_gchIO.IsAllocated) - _gchIO.Free(); - if (_gchBuffer.IsAllocated) - _gchBuffer.Free(); - } - - void DoClose() - { - if (pAPECompress) - { - pAPECompress->Finish (NULL, 0, 0); - delete pAPECompress; - pAPECompress = NULL; - } - - if (_IO != nullptr) - { - _IO->Close (); - _IO = nullptr; - } - } - - virtual void Close() - { - DoClose(); - - if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) { - throw gcnew Exception("Samples written differs from the expected sample count."); - } - } - - virtual void Delete() - { - DoClose (); - - 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 void Write(AudioBuffer^ buff) - { - if (!_initialized) - Initialize(); - buff->Prepare(this); - pin_ptr pSampleBuffer = &buff->Bytes[0]; - if (pAPECompress->AddData (pSampleBuffer, buff->ByteLength)) - throw gcnew Exception("An error occurred while encoding."); - _samplesWritten += buff->Length; - } - - virtual property String^ Path - { - String^ get() { - return _path; - } - } - - virtual property IAudioEncoderSettings^ Settings - { - IAudioEncoderSettings^ get() - { - return _settings; - } - } - - private: - IAPECompress * pAPECompress; - bool _initialized; - Int64 _finalSampleCount, _samplesWritten; - EncoderSettings^ _settings; - String^ _path; - Stream^ _IO; - GCHandle _gchIO, _gchBuffer; - CWinFileIO* _winFileIO; - array^ _writeBuffer; - array^ _sampleBuffer; - - void Initialize() { - if (_IO == nullptr) - _IO = gcnew FileStream (_path, FileMode::Create, FileAccess::ReadWrite, FileShare::Read); - _writeBuffer = gcnew array(0x4000); - - _gchIO = GCHandle::Alloc(_IO); - _gchBuffer = GCHandle::Alloc(_writeBuffer); - _winFileIO = new CWinFileIO(_gchIO, _gchBuffer); - - WAVEFORMATEX waveFormat; - FillWaveFormatEx (&waveFormat, _settings->PCM->SampleRate, _settings->PCM->BitsPerSample, _settings->PCM->ChannelCount); - - Int32 _compressionLevel = (IAudioEncoderSettingsExtensions::GetEncoderModeIndex(_settings) + 1) * 1000; - - int res = pAPECompress->StartEx (_winFileIO, - &waveFormat, - (_finalSampleCount == 0) ? MAX_AUDIO_BYTES_UNKNOWN : _finalSampleCount * _settings->PCM->BlockAlign, - _compressionLevel, - NULL, - CREATE_WAV_HEADER_ON_DECOMPRESSION); - if (res) - throw gcnew Exception("Unable to create the encoder."); - - _initialized = true; - } - }; - - int CWinFileIO::Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead) - { - 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; - return 0; - } - - int CWinFileIO::Write(const void * pBuffer, unsigned int nBytesToWrite, unsigned int * pBytesWritten) - { - 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; - return 0; - } - - int CWinFileIO::GetPosition() - { - return ((Stream^)_gchIO.Target)->Position; - } - - unsigned int CWinFileIO::GetSize() - { - return ((Stream^)_gchIO.Target)->Length; - } - - int CWinFileIO::Seek(int delta, unsigned int mode) - { - switch (mode) - { - case FILE_BEGIN: - ((Stream^)_gchIO.Target)->Seek (delta, System::IO::SeekOrigin::Begin); - break; - case FILE_END: - ((Stream^)_gchIO.Target)->Seek (delta, System::IO::SeekOrigin::End); - break; - case FILE_CURRENT: - ((Stream^)_gchIO.Target)->Seek (delta, System::IO::SeekOrigin::Current); - break; - default: - return -1; - } - return 0; - } - -#if 0 -extern "C" -{ - BOOL GetMMXAvailable(); - int CalculateDotProduct8(const short* pA, const short* pB, int nOrder); -}; - - public ref class SSE2Functions - { - public: - SSE2Functions () - { - _haveSSE2 = GetMMXAvailable(); - } - int SumInts (short*a, short*b, int count) - { - if (_haveSSE2 && count == 8) - return CalculateDotProduct8(a, b, count); - int sum = 0; - for (int j = 0; j < count; j++) - sum += a[j] * b[j]; - return sum; - } - int SumInts (int*a, short*b, int count) - { - int sum = 0; - for (int j = 0; j < count; j++) - sum += a[j] * b[j]; - return sum; - } - private: - bool _haveSSE2; - }; -#endif -}}} diff --git a/CUETools.Codecs.APE/CUETools.Codecs.APE.h b/CUETools.Codecs.APE/CUETools.Codecs.APE.h deleted file mode 100644 index e69de29..0000000 diff --git a/CUETools.Codecs.APE/CUETools.Codecs.APE.vcxproj b/CUETools.Codecs.APE/CUETools.Codecs.APE.vcxproj deleted file mode 100644 index 7f7e1db..0000000 --- a/CUETools.Codecs.APE/CUETools.Codecs.APE.vcxproj +++ /dev/null @@ -1,243 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {9AE965C4-301E-4C01-B90F-297AF341ACC6} - CUETools.Codecs.APE - ManagedCProj - 10.0.16299.0 - v4.0 - - - - DynamicLibrary - Unicode - true - true - v141 - - - DynamicLibrary - Unicode - true - v141 - - - DynamicLibrary - Unicode - true - true - v141 - - - DynamicLibrary - Unicode - true - v141 - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\ - $(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\ - true - $(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\ - $(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\ - true - $(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\ - $(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\ - false - $(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\ - $(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\ - false - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - Disabled - ..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - - - %(AdditionalLibraryDirectories) - true - true - false - - - MachineX86 - - - - - X64 - - - Disabled - ..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - - - %(AdditionalLibraryDirectories) - true - true - false - - - MachineX64 - - - - - ..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - - - %(AdditionalLibraryDirectories) - true - false - - - MachineX86 - UseLinkTimeCodeGeneration - - - - - X64 - - - ..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - - - %(AdditionalLibraryDirectories) - true - false - - - MachineX64 - UseLinkTimeCodeGeneration - - - - - ..\bin\Release\net40\Newtonsoft.Json.dll - false - false - true - - - true - true - - - true - true - - - true - true - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - {6458a13a-30ef-45a9-9d58-e5031b17bee2} - false - true - false - true - false - - - {21bf980f-c022-4dcc-9250-7c73528e422b} - - - - - - \ No newline at end of file diff --git a/CUETools.Codecs.APE/ReadMe.txt b/CUETools.Codecs.APE/ReadMe.txt deleted file mode 100644 index 7b4d3de..0000000 --- a/CUETools.Codecs.APE/ReadMe.txt +++ /dev/null @@ -1,31 +0,0 @@ -======================================================================== - DYNAMIC LINK LIBRARY : APEDotNet Project Overview -======================================================================== - -AppWizard has created this APEDotNet DLL for you. - -This file contains a summary of what you will find in each of the files that -make up your APEDotNet application. - -APEDotNet.vcproj - This is the main project file for VC++ projects generated using an Application Wizard. - It contains information about the version of Visual C++ that generated the file, and - information about the platforms, configurations, and project features selected with the - Application Wizard. - -APEDotNet.cpp - This is the main DLL source file. - -APEDotNet.h - This file contains a class declaration. - -AssemblyInfo.cpp - Contains custom attributes for modifying assembly metadata. - -///////////////////////////////////////////////////////////////////////////// -Other notes: - -AppWizard uses "TODO:" to indicate parts of the source code you -should add to or customize. - -///////////////////////////////////////////////////////////////////////////// diff --git a/CUETools.Codecs.APE/Stdafx.cpp b/CUETools.Codecs.APE/Stdafx.cpp deleted file mode 100644 index a9bcc4f..0000000 --- a/CUETools.Codecs.APE/Stdafx.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// APEDotNet.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" diff --git a/CUETools.Codecs.APE/Stdafx.h b/CUETools.Codecs.APE/Stdafx.h deleted file mode 100644 index 2e525d4..0000000 --- a/CUETools.Codecs.APE/Stdafx.h +++ /dev/null @@ -1,7 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, -// but are changed infrequently - -#pragma once - - diff --git a/CUETools.Codecs.APE/app.ico b/CUETools.Codecs.APE/app.ico deleted file mode 100644 index 3a5525f..0000000 Binary files a/CUETools.Codecs.APE/app.ico and /dev/null differ diff --git a/CUETools.Codecs.APE/app.rc b/CUETools.Codecs.APE/app.rc deleted file mode 100644 index bb5fb6f..0000000 --- a/CUETools.Codecs.APE/app.rc +++ /dev/null @@ -1,63 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon placed first or with lowest ID value becomes application icon - -LANGUAGE 25, 1 -#pragma code_page(1251) -1 ICON "app.ico" - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" - "\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\0" -END - -#endif // APSTUDIO_INVOKED - -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/CUETools.Codecs.APE/resource.h b/CUETools.Codecs.APE/resource.h deleted file mode 100644 index 1f2251c..0000000 --- a/CUETools.Codecs.APE/resource.h +++ /dev/null @@ -1,3 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by app.rc diff --git a/CUETools.Codecs.MACLib/AudioDecoder.cs b/CUETools.Codecs.MACLib/AudioDecoder.cs new file mode 100644 index 0000000..2e4bd1c --- /dev/null +++ b/CUETools.Codecs.MACLib/AudioDecoder.cs @@ -0,0 +1,147 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace CUETools.Codecs.MACLib +{ + public unsafe class AudioDecoder : IAudioSource, IDisposable + { + public AudioDecoder(DecoderSettings settings, string path, Stream IO) + { + m_settings = settings; + + _path = path; + + m_stream = (IO != null) ? IO : new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.Read); + m_StreamIO = new StreamIO(m_stream); + + int errorCode = 0; + pAPEDecompress = MACLibDll.c_APEDecompress_CreateEx(m_StreamIO.Callbacks, out errorCode); + if (pAPEDecompress == null) { + throw new Exception("Unable to initialize the decoder: " + errorCode); + } + + pcm = new AudioPCMConfig( + MACLibDll.c_APEDecompress_GetInfo(pAPEDecompress, APE_DECOMPRESS_FIELDS.APE_INFO_BITS_PER_SAMPLE, 0, 0), + MACLibDll.c_APEDecompress_GetInfo(pAPEDecompress, APE_DECOMPRESS_FIELDS.APE_INFO_CHANNELS, 0, 0), + MACLibDll.c_APEDecompress_GetInfo(pAPEDecompress, APE_DECOMPRESS_FIELDS.APE_INFO_SAMPLE_RATE, 0, 0), + (AudioPCMConfig.SpeakerConfig)0); + _samplesBuffer = new byte[16384 * pcm.BlockAlign]; + _sampleCount = MACLibDll.c_APEDecompress_GetInfo(pAPEDecompress, APE_DECOMPRESS_FIELDS.APE_DECOMPRESS_TOTAL_BLOCKS, 0, 0); + _sampleOffset = 0; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (m_StreamIO != null) + { + m_StreamIO.Dispose(); + m_StreamIO = null; + } + if (m_stream != null) + { + m_stream.Dispose(); + m_stream = null; + } + if (_samplesBuffer != null) + { + _samplesBuffer = null; + } + } + + if (pAPEDecompress != null) MACLibDll.c_APEDecompress_Destroy(pAPEDecompress); + pAPEDecompress = IntPtr.Zero; + } + + ~AudioDecoder() + { + Dispose(false); + } + + // TODO: intn should always be 64 bit? Or should we use different interface in 32-bit mode? + + private DecoderSettings m_settings; + + public IAudioDecoderSettings Settings => m_settings; + + public AudioPCMConfig PCM => pcm; + + public string Path => _path; + + public long Length => _sampleCount; + + internal long SamplesInBuffer => _bufferLength - _bufferOffset; + + public long Position + { + get => _sampleOffset - SamplesInBuffer; + + set + { + _bufferOffset = 0; + _bufferLength = 0; + _sampleOffset = value; + int res = MACLibDll.c_APEDecompress_Seek(pAPEDecompress, (int)value); + if (0 != res) + throw new Exception("unable to seek:" + res.ToString()); + } + } + + public long Remaining => _sampleCount - _sampleOffset + SamplesInBuffer; + + public void Close() + { + Dispose(true); + } + + public int Read(AudioBuffer buff, int maxLength) + { + buff.Prepare(this, maxLength); + + long buffOffset = 0; + long samplesNeeded = buff.Length; + long _channelCount = pcm.ChannelCount; + + while (samplesNeeded != 0) + { + if (SamplesInBuffer == 0) + { + long nBlocksRetrieved; + fixed (byte* pSampleBuffer = &_samplesBuffer[0]) + { + int res = MACLibDll.c_APEDecompress_GetData(pAPEDecompress, (char*)pSampleBuffer, (IntPtr)16384, out nBlocksRetrieved); + if (res != 0) + throw new Exception("An error occurred while decoding: " + res.ToString()); + } + _bufferOffset = 0; + _bufferLength = nBlocksRetrieved; + _sampleOffset += nBlocksRetrieved; + } + long copyCount = Math.Min(samplesNeeded, SamplesInBuffer); + AudioBuffer.BytesToFLACSamples_16(_samplesBuffer, (int)(_bufferOffset * pcm.BlockAlign), buff.Samples, (int)buffOffset, (int)copyCount, (int)_channelCount); + samplesNeeded -= copyCount; + buffOffset += copyCount; + _bufferOffset += copyCount; + } + + return buff.Length; + } + + IntPtr pAPEDecompress; + long _sampleCount, _sampleOffset; + AudioPCMConfig pcm; + string _path; + Stream m_stream; + long _bufferOffset, _bufferLength; + byte[] _samplesBuffer; + StreamIO m_StreamIO; + } +} diff --git a/CUETools.Codecs.MACLib/AudioEncoder.cs b/CUETools.Codecs.MACLib/AudioEncoder.cs new file mode 100644 index 0000000..eaafb2b --- /dev/null +++ b/CUETools.Codecs.MACLib/AudioEncoder.cs @@ -0,0 +1,158 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace CUETools.Codecs.MACLib +{ + public unsafe class AudioEncoder : IAudioDest, IDisposable + { + public AudioEncoder(EncoderSettings settings, string path, Stream output = null) + { + m_settings = settings; + + m_path = path; + m_stream = output; + m_settings = settings; + m_streamGiven = output != null; + m_initialized = false; + m_finalSampleCount = 0; + m_samplesWritten = 0; + + if (m_settings.PCM.ChannelCount != 1 && m_settings.PCM.ChannelCount != 2) + throw new Exception("Only stereo and mono audio formats are allowed."); + if (m_settings.PCM.BitsPerSample != 16 && m_settings.PCM.BitsPerSample != 24) + throw new Exception("bits per sample must be 16 or 24"); + + int nRetVal; + pAPECompress = MACLibDll.c_APECompress_Create(out nRetVal); + if (pAPECompress == null) + throw new Exception("Unable to open APE compressor."); + } + + public IAudioEncoderSettings Settings => m_settings; + + public string Path { get => m_path; } + + public long FinalSampleCount + { + get => m_finalSampleCount; + set + { + if (value < 0) + throw new Exception("invalid final sample count"); + if (m_initialized) + throw new Exception("final sample count cannot be changed after encoding begins"); + m_finalSampleCount = value; + } + } + + public void Close() + { + try + { + if (pAPECompress != null) + MACLibDll.c_APECompress_Finish(pAPECompress, null, 0, 0); + } + catch (Exception) + { + } + Dispose(); + if ((m_finalSampleCount != 0) && (m_samplesWritten != m_finalSampleCount)) + throw new Exception("samples written differs from the expected sample count"); + } + + public void Delete() + { + var path = m_path; + Dispose(true); + m_initialized = false; + if (path != "") + File.Delete(path); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (m_StreamIO != null) + { + m_StreamIO.Dispose(); + m_StreamIO = null; + } + if (m_stream != null) + { + m_stream.Dispose(); + m_stream = null; + } + } + + if (pAPECompress != null) MACLibDll.c_APECompress_Destroy(pAPECompress); + pAPECompress = IntPtr.Zero; + } + + ~AudioEncoder() + { + Dispose(false); + } + + public void Write(AudioBuffer sampleBuffer) + { + if (!m_initialized) Initialize(); + + sampleBuffer.Prepare(this); + + fixed (byte* pSampleBuffer = &sampleBuffer.Bytes[0]) + if (0 != MACLibDll.c_APECompress_AddData(pAPECompress, pSampleBuffer, sampleBuffer.ByteLength)) + throw new Exception("An error occurred while encoding"); + + m_samplesWritten += sampleBuffer.Length; + } + + void Initialize() + { + if (m_stream == null) + m_stream = new FileStream(m_path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 0x10000); + m_StreamIO = new StreamIO(m_stream); + + WAVEFORMATEX* pWaveFormatEx = stackalloc WAVEFORMATEX[1]; + pWaveFormatEx->extraSize = 0; + pWaveFormatEx->sampleRate = m_settings.PCM.SampleRate; + pWaveFormatEx->bitsPerSample = (short)m_settings.PCM.BitsPerSample; + pWaveFormatEx->channels = (short)m_settings.PCM.ChannelCount; + pWaveFormatEx->waveFormatTag = 1; + pWaveFormatEx->blockAlign = (short)m_settings.PCM.BlockAlign; + pWaveFormatEx->averageBytesPerSecond = m_settings.PCM.BlockAlign * m_settings.PCM.SampleRate; + + int compressionLevel = (m_settings.GetEncoderModeIndex() + 1) * 1000; + + int res = MACLibDll.c_APECompress_StartEx( + pAPECompress, + m_StreamIO.Callbacks, + pWaveFormatEx, + (m_finalSampleCount == 0) ? -1 : (int) (m_finalSampleCount * m_settings.PCM.BlockAlign), + compressionLevel, + null, + /*CREATE_WAV_HEADER_ON_DECOMPRESSION*/-1); + if (res != 0) + throw new Exception("Unable to create the encoder."); + + m_initialized = true; + } + + + IntPtr pAPECompress; + EncoderSettings m_settings; + Stream m_stream; + bool m_streamGiven; + bool m_initialized; + string m_path; + long m_finalSampleCount, m_samplesWritten; + StreamIO m_StreamIO; + } +} diff --git a/CUETools.Codecs.MACLib/CUETools.Codecs.MACLib.csproj b/CUETools.Codecs.MACLib/CUETools.Codecs.MACLib.csproj new file mode 100644 index 0000000..e77999e --- /dev/null +++ b/CUETools.Codecs.MACLib/CUETools.Codecs.MACLib.csproj @@ -0,0 +1,29 @@ + + + + net40;net20;netstandard2.0 + 2.1.7.0 + CUETools.Codecs.MACLib + CUETools.Codecs.MACLib + CUETools + A library for encoding APE files using official encoder. + Copyright (c) 2008-2018 Grigory Chudov + Grigory Chudov + true + ..\bin\$(Configuration)\plugins + https://github.com/gchudov/cuetools.net + git + + + + + + False + + + + + + + + diff --git a/CUETools.Codecs.MACLib/DecoderSettings.cs b/CUETools.Codecs.MACLib/DecoderSettings.cs new file mode 100644 index 0000000..93640e7 --- /dev/null +++ b/CUETools.Codecs.MACLib/DecoderSettings.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace CUETools.Codecs.MACLib +{ + [JsonObject(MemberSerialization.OptIn)] + public class DecoderSettings : IAudioDecoderSettings + { + #region IAudioDecoderSettings implementation + [Browsable(false)] + public string Extension => "ape"; + + [Browsable(false)] + public string Name => "MACLib"; + + [Browsable(false)] + public Type DecoderType => typeof(AudioDecoder); + + [Browsable(false)] + public int Priority => 1; + + public IAudioDecoderSettings Clone() + { + return MemberwiseClone() as IAudioDecoderSettings; + } + #endregion + + public DecoderSettings() + { + this.Init(); + } + + [DisplayName("Version")] + [Description("Library version")] + public string Version => Marshal.PtrToStringAnsi(MACLibDll.GetVersionString()); + } +} \ No newline at end of file diff --git a/CUETools.Codecs.MACLib/EncoderSettings.cs b/CUETools.Codecs.MACLib/EncoderSettings.cs new file mode 100644 index 0000000..d608680 --- /dev/null +++ b/CUETools.Codecs.MACLib/EncoderSettings.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using CUETools.Codecs; +using Newtonsoft.Json; + +namespace CUETools.Codecs.MACLib +{ + [JsonObject(MemberSerialization.OptIn)] + public class EncoderSettings : IAudioEncoderSettings + { + #region IAudioEncoderSettings implementation + [Browsable(false)] + public string Extension => "ape"; + + [Browsable(false)] + public string Name => "MACLib"; + + [Browsable(false)] + public Type EncoderType => typeof(AudioEncoder); + + [Browsable(false)] + public bool Lossless => true; + + [Browsable(false)] + public int Priority => 1; + + [Browsable(false)] + public string SupportedModes => "fast normal high extra insane"; + + [Browsable(false)] + public string DefaultMode => "high"; + + [Browsable(false)] + [DefaultValue("")] + [JsonProperty] + public string EncoderMode { get; set; } + + [Browsable(false)] + public AudioPCMConfig PCM { get; set; } + + [Browsable(false)] + public int BlockSize { get; set; } + + [Browsable(false)] + [DefaultValue(4096)] + public int Padding { get; set; } + + public IAudioEncoderSettings Clone() + { + return MemberwiseClone() as IAudioEncoderSettings; + } + #endregion + + public EncoderSettings() + { + this.Init(); + } + + [DisplayName("Version")] + [Description("Library version")] + public string Version => Marshal.PtrToStringAnsi(MACLibDll.GetVersionString()); + }; +} diff --git a/CUETools.Codecs.MACLib/MACLib.cs b/CUETools.Codecs.MACLib/MACLib.cs new file mode 100644 index 0000000..8ad5252 --- /dev/null +++ b/CUETools.Codecs.MACLib/MACLib.cs @@ -0,0 +1,90 @@ +using System; +using System.Runtime.InteropServices; + +namespace CUETools.Codecs.MACLib +{ + internal enum APE_DECOMPRESS_FIELDS : int + { + APE_INFO_FILE_VERSION = 1000, // version of the APE file * 1000 (3.93 = 3930) [ignored, ignored] + APE_INFO_COMPRESSION_LEVEL = 1001, // compression level of the APE file [ignored, ignored] + APE_INFO_FORMAT_FLAGS = 1002, // format flags of the APE file [ignored, ignored] + APE_INFO_SAMPLE_RATE = 1003, // sample rate (Hz) [ignored, ignored] + APE_INFO_BITS_PER_SAMPLE = 1004, // bits per sample [ignored, ignored] + APE_INFO_BYTES_PER_SAMPLE = 1005, // number of bytes per sample [ignored, ignored] + APE_INFO_CHANNELS = 1006, // channels [ignored, ignored] + APE_INFO_BLOCK_ALIGN = 1007, // block alignment [ignored, ignored] + APE_INFO_BLOCKS_PER_FRAME = 1008, // number of blocks in a frame (frames are used internally) [ignored, ignored] + APE_INFO_FINAL_FRAME_BLOCKS = 1009, // blocks in the final frame (frames are used internally) [ignored, ignored] + APE_INFO_TOTAL_FRAMES = 1010, // total number frames (frames are used internally) [ignored, ignored] + APE_INFO_WAV_HEADER_BYTES = 1011, // header bytes of the decompressed WAV [ignored, ignored] + APE_INFO_WAV_TERMINATING_BYTES = 1012, // terminating bytes of the decompressed WAV [ignored, ignored] + APE_INFO_WAV_DATA_BYTES = 1013, // data bytes of the decompressed WAV [ignored, ignored] + APE_INFO_WAV_TOTAL_BYTES = 1014, // total bytes of the decompressed WAV [ignored, ignored] + APE_INFO_APE_TOTAL_BYTES = 1015, // total bytes of the APE file [ignored, ignored] + APE_INFO_TOTAL_BLOCKS = 1016, // total blocks of audio data [ignored, ignored] + APE_INFO_LENGTH_MS = 1017, // length in ms (1 sec = 1000 ms) [ignored, ignored] + APE_INFO_AVERAGE_BITRATE = 1018, // average bitrate of the APE [ignored, ignored] + APE_INFO_FRAME_BITRATE = 1019, // bitrate of specified APE frame [frame index, ignored] + APE_INFO_DECOMPRESSED_BITRATE = 1020, // bitrate of the decompressed WAV [ignored, ignored] + APE_INFO_PEAK_LEVEL = 1021, // peak audio level (obsolete) (-1 is unknown) [ignored, ignored] + APE_INFO_SEEK_BIT = 1022, // bit offset [frame index, ignored] + APE_INFO_SEEK_BYTE = 1023, // byte offset [frame index, ignored] + APE_INFO_WAV_HEADER_DATA = 1024, // error code [buffer *, max bytes] + APE_INFO_WAV_TERMINATING_DATA = 1025, // error code [buffer *, max bytes] + APE_INFO_WAVEFORMATEX = 1026, // error code [waveformatex *, ignored] + APE_INFO_IO_SOURCE = 1027, // I/O source (CIO *) [ignored, ignored] + APE_INFO_FRAME_BYTES = 1028, // bytes (compressed) of the frame [frame index, ignored] + APE_INFO_FRAME_BLOCKS = 1029, // blocks in a given frame [frame index, ignored] + APE_INFO_TAG = 1030, // point to tag (CAPETag *) [ignored, ignored] + + APE_DECOMPRESS_CURRENT_BLOCK = 2000, // current block location [ignored, ignored] + APE_DECOMPRESS_CURRENT_MS = 2001, // current millisecond location [ignored, ignored] + APE_DECOMPRESS_TOTAL_BLOCKS = 2002, // total blocks in the decompressors range [ignored, ignored] + APE_DECOMPRESS_LENGTH_MS = 2003, // length of the decompressors range in milliseconds [ignored, ignored] + APE_DECOMPRESS_CURRENT_BITRATE = 2004, // current bitrate [ignored, ignored] + APE_DECOMPRESS_AVERAGE_BITRATE = 2005, // average bitrate (works with ranges) [ignored, ignored] + APE_DECOMPRESS_CURRENT_FRAME = 2006, // current frame + + APE_INTERNAL_INFO = 3000, // for internal use -- don't use (returns APE_FILE_INFO *) [ignored, ignored] + }; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal unsafe delegate int CIO_ReadDelegate(APE_CIO_Callbacks* pCIO, void* pBuffer, int nBytesToRead, out int pBytesRead); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal unsafe delegate int CIO_WriteDelegate(APE_CIO_Callbacks* pCIO, void* pBuffer, int nBytesToWrite, out int pBytesWritten); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal unsafe delegate int CIO_GetPositionDelegate(APE_CIO_Callbacks* pCIO); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal unsafe delegate uint CIO_GetSizeDelegate(APE_CIO_Callbacks* pCIO); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal unsafe delegate int CIO_SeekDelegate(APE_CIO_Callbacks* pCIO, IntPtr delta, int mode); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)] + public unsafe struct WAVEFORMATEX + { + /// format type + internal ushort waveFormatTag; + /// number of channels + internal short channels; + /// sample rate + internal int sampleRate; + /// for buffer estimation + internal int averageBytesPerSecond; + /// block size of data + internal short blockAlign; + /// number of bits per sample of mono data + internal short bitsPerSample; + /// number of following bytes + internal short extraSize; + } + + [StructLayout(LayoutKind.Sequential), Serializable] + internal unsafe struct APE_CIO_Callbacks + { + internal IntPtr read_bytes; + internal IntPtr write_bytes; + internal IntPtr seek; + internal IntPtr get_pos; + internal IntPtr get_size; + }; +} diff --git a/CUETools.Codecs.MACLib/MACLibDll.cs b/CUETools.Codecs.MACLib/MACLibDll.cs new file mode 100644 index 0000000..7784b58 --- /dev/null +++ b/CUETools.Codecs.MACLib/MACLibDll.cs @@ -0,0 +1,74 @@ +using System; +using System.Runtime.InteropServices; + +namespace CUETools.Codecs.MACLib +{ + internal unsafe static class MACLibDll + { + internal const string DllName = "MACLibDll"; + internal const CallingConvention DllCallingConvention = CallingConvention.StdCall; + + [DllImport("kernel32.dll")] + private static extern IntPtr LoadLibrary(string dllToLoad); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern int GetVersionNumber(); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern IntPtr GetVersionString(); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern IntPtr c_APECompress_Create(out int error); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern void c_APECompress_Destroy(IntPtr hAPECompress); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern int c_APECompress_Finish(IntPtr hAPECompress, char* pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern int c_APECompress_AddData(IntPtr hAPECompress, byte* pData, int nBytes); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern int c_APECompress_StartEx( + IntPtr hAPECompress, + APE_CIO_Callbacks* pCIO, + WAVEFORMATEX* pwfeInput, + int nMaxAudioBytes, + int nCompressionLevel, + void* pHeaderData, + int nHeaderBytes); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern IntPtr c_APEDecompress_CreateEx(APE_CIO_Callbacks* pCIO, out int pErrorCode); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern int c_APEDecompress_GetInfo(IntPtr hAPEDecompress, APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern int c_APEDecompress_Seek(IntPtr hAPEDecompress, int nBlockOffset); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern int c_APEDecompress_GetData(IntPtr hAPEDecompress, char* pBuffer, IntPtr nBlocks, out long pBlocksRetrieved); + + [DllImport(DllName, CallingConvention = DllCallingConvention)] + internal static extern void c_APEDecompress_Destroy(IntPtr hAPEDecompress); + + static MACLibDll() + { + var myPath = new Uri(typeof(MACLibDll).Assembly.CodeBase).LocalPath; + var myFolder = System.IO.Path.GetDirectoryName(myPath); + var is64 = IntPtr.Size == 8; + var subfolder = is64 ? "x64" : "win32"; +#if NET40 + IntPtr Dll = LoadLibrary(System.IO.Path.Combine(myFolder, subfolder, DllName + ".dll")); +#else + IntPtr Dll = LoadLibrary(System.IO.Path.Combine(System.IO.Path.Combine(myFolder, subfolder), DllName + ".dll")); +#endif + if (Dll == IntPtr.Zero) + Dll = LoadLibrary(DllName + ".dll"); + if (Dll == IntPtr.Zero) + throw new DllNotFoundException(); + } + }; +} diff --git a/CUETools.Codecs.MACLib/StreamIO.cs b/CUETools.Codecs.MACLib/StreamIO.cs new file mode 100644 index 0000000..736a776 --- /dev/null +++ b/CUETools.Codecs.MACLib/StreamIO.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace CUETools.Codecs.MACLib +{ + internal unsafe class StreamIO : IDisposable + { + public StreamIO(Stream stream) + { + m_stream = stream; + + m_read_bytes = ReadCallback; + m_write_bytes = WriteCallback; + m_get_pos = TellCallback; + m_get_size = GetSizeCallback; + m_seek = SeekRelativeCallback; + + m_callbacks = (APE_CIO_Callbacks*)Marshal.AllocHGlobal(sizeof(APE_CIO_Callbacks)).ToPointer(); + m_callbacks->read_bytes = Marshal.GetFunctionPointerForDelegate(m_read_bytes); + m_callbacks->write_bytes = Marshal.GetFunctionPointerForDelegate(m_write_bytes); + m_callbacks->get_pos = Marshal.GetFunctionPointerForDelegate(m_get_pos); + m_callbacks->get_size = Marshal.GetFunctionPointerForDelegate(m_get_size); + m_callbacks->seek = Marshal.GetFunctionPointerForDelegate(m_seek); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + m_stream = null; + _readBuffer = null; + } + + if (m_callbacks != null) Marshal.FreeHGlobal((IntPtr)m_callbacks); + m_callbacks = null; + } + + ~StreamIO() + { + Dispose(false); + } + + private int ReadCallback(APE_CIO_Callbacks* id, void* data, int bcount, out int pBytesRead) + { + if (_readBuffer == null || _readBuffer.Length < bcount) + _readBuffer = new byte[Math.Max(bcount, 0x4000)]; + int len = m_stream.Read(_readBuffer, 0, bcount); + if (len > 0) Marshal.Copy(_readBuffer, 0, (IntPtr)data, len); + pBytesRead = len; + return 0; + } + + private int WriteCallback(APE_CIO_Callbacks* id, void* data, int bcount, out int pBytesWritten) + { + if (_readBuffer == null || _readBuffer.Length < bcount) + _readBuffer = new byte[Math.Max(bcount, 0x4000)]; + Marshal.Copy((IntPtr)data, _readBuffer, 0, bcount); + m_stream.Write(_readBuffer, 0, bcount); + pBytesWritten = bcount; + return 0; + } + + int TellCallback(APE_CIO_Callbacks* id) + { + return (int)m_stream.Position; + } + + uint GetSizeCallback(APE_CIO_Callbacks* id) + { + return (uint)m_stream.Length; + } + + int SeekRelativeCallback(APE_CIO_Callbacks* id, IntPtr delta, int mode) + { + m_stream.Seek((long)delta, (SeekOrigin)(mode)); + return 0; + } + + internal APE_CIO_Callbacks* Callbacks => m_callbacks; + + APE_CIO_Callbacks* m_callbacks; + Stream m_stream; + byte[] _readBuffer; + CIO_ReadDelegate m_read_bytes; + CIO_WriteDelegate m_write_bytes; + CIO_GetPositionDelegate m_get_pos; + CIO_GetSizeDelegate m_get_size; + CIO_SeekDelegate m_seek; + } +} diff --git a/CUETools.Converter/Program.cs b/CUETools.Converter/Program.cs index 18b8b79..9bd95b2 100644 --- a/CUETools.Converter/Program.cs +++ b/CUETools.Converter/Program.cs @@ -51,7 +51,7 @@ namespace CUETools.Converter throw new Exception("Unknown audio decoder " + chosenDecoder + " or unsupported audio type " + fmt.extension); if (decoder == null) throw new Exception("Unsupported audio type: " + path); - var settings = fmt.decoder.Settings.Clone(); + var settings = decoder.Settings.Clone(); try { object src = Activator.CreateInstance(decoder.Settings.DecoderType, settings, path, IO); diff --git a/CUETools/CUETools.sln b/CUETools/CUETools.sln index b870834..ef41f8c 100644 --- a/CUETools/CUETools.sln +++ b/CUETools/CUETools.sln @@ -55,8 +55,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{86BB EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools", "CUETools.csproj", "{EF351583-A9CD-4530-92C3-20AC02136BC2}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CUETools.Codecs.APE", "..\CUETools.Codecs.APE\CUETools.Codecs.APE.vcxproj", "{9AE965C4-301E-4C01-B90F-297AF341ACC6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUETools.ARCUE", "..\CUETools.ARCUE\CUETools.ARCUE.csproj", "{A5A8D8FA-9E32-4010-8AAF-AE580C5AF728}" ProjectSection(ProjectDependencies) = postProject {6458A13A-30EF-45A9-9D58-E5031B17BEE2} = {6458A13A-30EF-45A9-9D58-E5031B17BEE2} @@ -193,6 +191,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwavpack", "..\ThirdParty EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wavpackdll", "..\ThirdParty\WavPack\wavpackdll\wavpackdll.vcxproj", "{1A87F412-BA74-4DBB-9F77-FD55C042FB63}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MACLibDll", "..\ThirdParty\MAC_SDK\Source\Projects\VS2017\MACLibDll\MACLibDll.vcxproj", "{CEE4A179-49FC-4D51-B045-F717D3A6C13A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUETools.Codecs.MACLib", "..\CUETools.Codecs.MACLib\CUETools.Codecs.MACLib.csproj", "{8FE405A0-E837-4088-88AD-B63652E34790}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -211,16 +213,6 @@ Global {EF351583-A9CD-4530-92C3-20AC02136BC2}.Release|Any CPU.Build.0 = Release|Any CPU {EF351583-A9CD-4530-92C3-20AC02136BC2}.Release|Win32.ActiveCfg = Release|Any CPU {EF351583-A9CD-4530-92C3-20AC02136BC2}.Release|x64.ActiveCfg = Release|Any CPU - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|Any CPU.ActiveCfg = Debug|x64 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|Win32.ActiveCfg = Debug|Win32 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|Win32.Build.0 = Debug|Win32 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|x64.ActiveCfg = Debug|x64 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|x64.Build.0 = Debug|x64 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|Any CPU.ActiveCfg = Release|x64 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|Win32.ActiveCfg = Release|Win32 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|Win32.Build.0 = Release|Win32 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|x64.ActiveCfg = Release|x64 - {9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|x64.Build.0 = Release|x64 {A5A8D8FA-9E32-4010-8AAF-AE580C5AF728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A5A8D8FA-9E32-4010-8AAF-AE580C5AF728}.Debug|Any CPU.Build.0 = Debug|Any CPU {A5A8D8FA-9E32-4010-8AAF-AE580C5AF728}.Debug|Win32.ActiveCfg = Debug|Any CPU @@ -735,6 +727,24 @@ Global {1A87F412-BA74-4DBB-9F77-FD55C042FB63}.Release|Win32.Build.0 = Release|Win32 {1A87F412-BA74-4DBB-9F77-FD55C042FB63}.Release|x64.ActiveCfg = Release|x64 {1A87F412-BA74-4DBB-9F77-FD55C042FB63}.Release|x64.Build.0 = Release|x64 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Debug|Win32.ActiveCfg = Debug|Win32 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Debug|Win32.Build.0 = Debug|Win32 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Debug|x64.ActiveCfg = Debug|x64 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Debug|x64.Build.0 = Debug|x64 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Release|Any CPU.ActiveCfg = Release|Win32 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Release|Win32.ActiveCfg = Release|Win32 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Release|Win32.Build.0 = Release|Win32 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Release|x64.ActiveCfg = Release|x64 + {CEE4A179-49FC-4D51-B045-F717D3A6C13A}.Release|x64.Build.0 = Release|x64 + {8FE405A0-E837-4088-88AD-B63652E34790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FE405A0-E837-4088-88AD-B63652E34790}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FE405A0-E837-4088-88AD-B63652E34790}.Debug|Win32.ActiveCfg = Debug|Any CPU + {8FE405A0-E837-4088-88AD-B63652E34790}.Debug|x64.ActiveCfg = Debug|Any CPU + {8FE405A0-E837-4088-88AD-B63652E34790}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FE405A0-E837-4088-88AD-B63652E34790}.Release|Any CPU.Build.0 = Release|Any CPU + {8FE405A0-E837-4088-88AD-B63652E34790}.Release|Win32.ActiveCfg = Release|Any CPU + {8FE405A0-E837-4088-88AD-B63652E34790}.Release|x64.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -747,7 +757,6 @@ Global {FD1DD69E-EC51-443D-B6A7-908B8E0EF9E2} = {FD0D49DB-8F02-4A64-A9A3-A5AF54481770} {9A0D1EB8-269E-4165-971C-541C96AA506F} = {5D823ABE-D280-4800-824C-2633CBAB2EA9} {0E404B8B-FF82-427F-ADE4-77B54A29219F} = {5D823ABE-D280-4800-824C-2633CBAB2EA9} - {9AE965C4-301E-4C01-B90F-297AF341ACC6} = {39A17A65-E893-44B8-A312-DDCDD990D9D1} {A5A8D8FA-9E32-4010-8AAF-AE580C5AF728} = {4B59E09C-A51F-4B80-91BE-987904DCEF7D} {32338A04-5B6B-4C63-8EE7-C6400F73B5D7} = {FD0D49DB-8F02-4A64-A9A3-A5AF54481770} {F2EC7193-D5E5-4252-9803-5CEB407E910F} = {93B7AE1D-DEF6-4A04-A222-5CDE09DF262D} @@ -794,6 +803,8 @@ Global {4D1B3411-F4F7-4E62-B7CB-A3AC3D530443} = {93B7AE1D-DEF6-4A04-A222-5CDE09DF262D} {5CCCB9CF-0384-458F-BA08-72B73866840F} = {8B179853-B7D6-479C-B8B2-6CBCE835D040} {1A87F412-BA74-4DBB-9F77-FD55C042FB63} = {8B179853-B7D6-479C-B8B2-6CBCE835D040} + {CEE4A179-49FC-4D51-B045-F717D3A6C13A} = {8B179853-B7D6-479C-B8B2-6CBCE835D040} + {8FE405A0-E837-4088-88AD-B63652E34790} = {93B7AE1D-DEF6-4A04-A222-5CDE09DF262D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C634D169-5814-4203-94B6-6A11371DDA95} diff --git a/ThirdParty/MAC_SDK b/ThirdParty/MAC_SDK index ec5e7e8..fe94269 160000 --- a/ThirdParty/MAC_SDK +++ b/ThirdParty/MAC_SDK @@ -1 +1 @@ -Subproject commit ec5e7e8ee770037d54ab261d742fc1fe3d644153 +Subproject commit fe94269a91e6e06be0fd652d9b1855caf7ddd420 diff --git a/ThirdPartyDebug/x64/MACLib.lib b/ThirdPartyDebug/x64/MACLib.lib deleted file mode 100644 index 1e9760b..0000000 Binary files a/ThirdPartyDebug/x64/MACLib.lib and /dev/null differ diff --git a/ThirdPartyDebug/x64/MACLib.pdb b/ThirdPartyDebug/x64/MACLib.pdb deleted file mode 100644 index fe70457..0000000 Binary files a/ThirdPartyDebug/x64/MACLib.pdb and /dev/null differ