Replaced C++/CLR version of Monkey's Audio plugin with a .dll and a PInvoke plugin

This commit is contained in:
Grigory Chudov
2018-03-26 20:11:49 -04:00
parent 320e75d709
commit e7c6a9c854
24 changed files with 732 additions and 1034 deletions

2
.gitignore vendored
View File

@@ -15,5 +15,7 @@ launchSettings.json
/CUETools/TestResults
/ThirdParty/*/libFLAC_dynamic.*
/ThirdParty/*/MACLib.*
/ThirdParty/*/MACLibDll.*
/ThirdParty/*/wavpackdll.*
/ThirdParty/*/libwavpack.*
/ThirdPartyDebug/

View File

@@ -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)];

View File

@@ -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<unsigned char>(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<unsigned char> (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<unsigned char> 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<unsigned char>^ _samplesBuffer;
String^ _path;
Stream^ _IO;
array<unsigned char>^ _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<unsigned char> 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<unsigned char>^ _writeBuffer;
array<unsigned char>^ _sampleBuffer;
void Initialize() {
if (_IO == nullptr)
_IO = gcnew FileStream (_path, FileMode::Create, FileAccess::ReadWrite, FileShare::Read);
_writeBuffer = gcnew array<unsigned char>(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<unsigned char>^ buff = (array<unsigned char>^) _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<unsigned char>^ buff = (array<unsigned char>^) _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
}}}

View File

@@ -1,243 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9AE965C4-301E-4C01-B90F-297AF341ACC6}</ProjectGuid>
<RootNamespace>CUETools.Codecs.APE</RootNamespace>
<Keyword>ManagedCProj</Keyword>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<CLRSupport>true</CLRSupport>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<CLRSupport>true</CLRSupport>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<CLRSupport>true</CLRSupport>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<CLRSupport>true</CLRSupport>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\bin\$(Configuration)\plugins\$(Platform)\net40\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\obj\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalIncludeDirectories>..\ThirdParty\MAC_SDK\Source\Shared;..\ThirdParty\MAC_SDK\Source\MACLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\bin\Release\net40\Newtonsoft.Json.dll</HintPath>
<Private>false</Private>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</Reference>
<Reference Include="System">
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</Reference>
<Reference Include="System.Data">
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</Reference>
<Reference Include="System.Xml">
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</Reference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AssemblyInfo.cpp" />
<ClCompile Include="CUETools.Codecs.APE.cpp" />
<ClCompile Include="Stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CUETools.Codecs.APE.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Stdafx.h" />
</ItemGroup>
<ItemGroup>
<None Include="app.ico" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="app.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CUETools.Codecs\CUETools.Codecs.csproj">
<Project>{6458a13a-30ef-45a9-9d58-e5031b17bee2}</Project>
<Private>false</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
<ProjectReference Include="..\ThirdParty\MAC_SDK\Source\Projects\VS2017\MACLib\MACLib.vcxproj">
<Project>{21bf980f-c022-4dcc-9250-7c73528e422b}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -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.
/////////////////////////////////////////////////////////////////////////////

View File

@@ -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"

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

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

View File

@@ -1,3 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by app.rc

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net40;net20;netstandard2.0</TargetFrameworks>
<Version>2.1.7.0</Version>
<AssemblyName>CUETools.Codecs.MACLib</AssemblyName>
<RootNamespace>CUETools.Codecs.MACLib</RootNamespace>
<Product>CUETools</Product>
<Description>A library for encoding APE files using official encoder.</Description>
<Copyright>Copyright (c) 2008-2018 Grigory Chudov</Copyright>
<Authors>Grigory Chudov</Authors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputPath>..\bin\$(Configuration)\plugins</OutputPath>
<RepositoryUrl>https://github.com/gchudov/cuetools.net</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Company />
</PropertyGroup>
<ItemDefinitionGroup>
<ProjectReference>
<Private>False</Private>
</ProjectReference>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\CUETools.Codecs\CUETools.Codecs.csproj" />
</ItemGroup>
</Project>

View File

@@ -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());
}
}

View File

@@ -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());
};
}

View File

@@ -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
{
/// <summary>format type</summary>
internal ushort waveFormatTag;
/// <summary>number of channels</summary>
internal short channels;
/// <summary>sample rate</summary>
internal int sampleRate;
/// <summary>for buffer estimation</summary>
internal int averageBytesPerSecond;
/// <summary>block size of data</summary>
internal short blockAlign;
/// <summary>number of bits per sample of mono data</summary>
internal short bitsPerSample;
/// <summary>number of following bytes</summary>
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;
};
}

View File

@@ -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();
}
};
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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}

Binary file not shown.

Binary file not shown.