mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
Codecs cleanup
This commit is contained in:
@@ -337,6 +337,10 @@
|
|||||||
ReferencedProjectIdentifier="{CA200BCB-DFC6-4153-9BD4-785BC768B26B}"
|
ReferencedProjectIdentifier="{CA200BCB-DFC6-4153-9BD4-785BC768B26B}"
|
||||||
RelativePathToProject="..\APETagDotNet\APETagDotNet.csproj"
|
RelativePathToProject="..\APETagDotNet\APETagDotNet.csproj"
|
||||||
/>
|
/>
|
||||||
|
<ProjectReference
|
||||||
|
ReferencedProjectIdentifier="{6458A13A-30EF-45A9-9D58-E5031B17BEE2}"
|
||||||
|
RelativePathToProject="..\AudioCodecsDotNet\AudioCodecsDotNet.csproj"
|
||||||
|
/>
|
||||||
</References>
|
</References>
|
||||||
<Files>
|
<Files>
|
||||||
<Filter
|
<Filter
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using namespace System::Collections::Specialized;
|
|||||||
using namespace System::Runtime::InteropServices;
|
using namespace System::Runtime::InteropServices;
|
||||||
using namespace System::IO;
|
using namespace System::IO;
|
||||||
using namespace APETagsDotNet;
|
using namespace APETagsDotNet;
|
||||||
|
using namespace AudioCodecsDotNet;
|
||||||
|
|
||||||
#ifndef _WAVEFORMATEX_
|
#ifndef _WAVEFORMATEX_
|
||||||
#define _WAVEFORMATEX_
|
#define _WAVEFORMATEX_
|
||||||
@@ -102,14 +103,16 @@ namespace APEDotNet {
|
|||||||
GCHandle _gchBuffer;
|
GCHandle _gchBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
public ref class APEReader {
|
public ref class APEReader : public IAudioSource
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
APEReader(String^ path, Stream^ IO) {
|
APEReader(String^ path, Stream^ IO)
|
||||||
|
{
|
||||||
pAPEDecompress = NULL;
|
pAPEDecompress = NULL;
|
||||||
_sampleOffset = 0;
|
_sampleOffset = 0;
|
||||||
|
_bufferOffset = 0;
|
||||||
|
_bufferLength = 0;
|
||||||
_path = path;
|
_path = path;
|
||||||
pBuffer = NULL;
|
|
||||||
|
|
||||||
int nRetVal = 0;
|
int nRetVal = 0;
|
||||||
|
|
||||||
@@ -129,7 +132,7 @@ namespace APEDotNet {
|
|||||||
|
|
||||||
// make a buffer to hold 16384 blocks of audio data
|
// make a buffer to hold 16384 blocks of audio data
|
||||||
nBlockAlign = pAPEDecompress->GetInfo (APE_INFO_BLOCK_ALIGN, 0, 0);
|
nBlockAlign = pAPEDecompress->GetInfo (APE_INFO_BLOCK_ALIGN, 0, 0);
|
||||||
pBuffer = new unsigned char [16384 * nBlockAlign];
|
_samplesBuffer = gcnew array<unsigned char> (16384 * nBlockAlign);
|
||||||
|
|
||||||
// loop through the whole file
|
// loop through the whole file
|
||||||
_sampleCount = pAPEDecompress->GetInfo (APE_DECOMPRESS_TOTAL_BLOCKS, 0, 0); // * ?
|
_sampleCount = pAPEDecompress->GetInfo (APE_DECOMPRESS_TOTAL_BLOCKS, 0, 0); // * ?
|
||||||
@@ -137,7 +140,6 @@ namespace APEDotNet {
|
|||||||
|
|
||||||
~APEReader ()
|
~APEReader ()
|
||||||
{
|
{
|
||||||
if (pBuffer) delete [] pBuffer;
|
|
||||||
if (_winFileIO)
|
if (_winFileIO)
|
||||||
delete _winFileIO;
|
delete _winFileIO;
|
||||||
if (_gchIO.IsAllocated)
|
if (_gchIO.IsAllocated)
|
||||||
@@ -146,50 +148,57 @@ namespace APEDotNet {
|
|||||||
_gchReadBuffer.Free();
|
_gchReadBuffer.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 BitsPerSample {
|
virtual property Int32 BitsPerSample {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _bitsPerSample;
|
return _bitsPerSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 ChannelCount {
|
virtual property Int32 ChannelCount {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _channelCount;
|
return _channelCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 SampleRate {
|
virtual property Int32 SampleRate {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _sampleRate;
|
return _sampleRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int64 Length {
|
virtual property UInt64 Length {
|
||||||
Int64 get() {
|
UInt64 get() {
|
||||||
return _sampleCount;
|
return _sampleCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int64 Position {
|
virtual property UInt64 Position
|
||||||
Int64 get() {
|
{
|
||||||
return _sampleOffset;
|
UInt64 get() {
|
||||||
|
return _sampleOffset - SamplesInBuffer;
|
||||||
}
|
}
|
||||||
void set(Int64 offset) {
|
void set(UInt64 offset) {
|
||||||
_sampleOffset = offset;
|
_sampleOffset = offset;
|
||||||
|
_bufferOffset = 0;
|
||||||
|
_bufferLength = 0;
|
||||||
if (pAPEDecompress->Seek ((int) offset /*? */))
|
if (pAPEDecompress->Seek ((int) offset /*? */))
|
||||||
throw gcnew Exception("Unable to seek.");
|
throw gcnew Exception("Unable to seek.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int64 Remaining {
|
virtual property UInt64 Remaining {
|
||||||
Int64 get() {
|
UInt64 get() {
|
||||||
return _sampleCount - _sampleOffset;
|
return _sampleCount - _sampleOffset + SamplesInBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Close() {
|
virtual void Close()
|
||||||
if (pAPEDecompress) delete pAPEDecompress;
|
{
|
||||||
|
if (pAPEDecompress)
|
||||||
|
{
|
||||||
|
delete pAPEDecompress;
|
||||||
pAPEDecompress = NULL;
|
pAPEDecompress = NULL;
|
||||||
|
}
|
||||||
if (_IO != nullptr)
|
if (_IO != nullptr)
|
||||||
{
|
{
|
||||||
_IO->Close ();
|
_IO->Close ();
|
||||||
@@ -197,14 +206,15 @@ namespace APEDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property String^ Path {
|
virtual property String^ Path {
|
||||||
String^ get() {
|
String^ get() {
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property NameValueCollection^ Tags {
|
virtual property NameValueCollection^ Tags {
|
||||||
NameValueCollection^ get () {
|
NameValueCollection^ get ()
|
||||||
|
{
|
||||||
if (!_tags)
|
if (!_tags)
|
||||||
{
|
{
|
||||||
APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true);
|
APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true);
|
||||||
@@ -213,33 +223,35 @@ namespace APEDotNet {
|
|||||||
}
|
}
|
||||||
return _tags;
|
return _tags;
|
||||||
}
|
}
|
||||||
void set (NameValueCollection ^tags) {
|
void set (NameValueCollection ^tags)
|
||||||
|
{
|
||||||
_tags = tags;
|
_tags = tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int32 Read([Out] array<Int32, 2>^% sampleBuffer) {
|
virtual UInt32 Read([Out] array<Int32, 2>^ buff, UInt32 sampleCount)
|
||||||
int sampleCount;
|
{
|
||||||
|
UInt32 buffOffset = 0;
|
||||||
|
UInt32 samplesNeeded = sampleCount;
|
||||||
|
|
||||||
|
while (samplesNeeded != 0)
|
||||||
|
{
|
||||||
|
if (SamplesInBuffer == 0)
|
||||||
|
{
|
||||||
int nBlocksRetrieved;
|
int nBlocksRetrieved;
|
||||||
if (pAPEDecompress->GetData ((char *) pBuffer, 16384, &nBlocksRetrieved))
|
pin_ptr<unsigned char> pSampleBuffer = &_samplesBuffer[0];
|
||||||
|
if (pAPEDecompress->GetData ((char *) pSampleBuffer, 16384, &nBlocksRetrieved))
|
||||||
throw gcnew Exception("An error occurred while decoding.");
|
throw gcnew Exception("An error occurred while decoding.");
|
||||||
|
_bufferOffset = 0;
|
||||||
sampleCount = nBlocksRetrieved;
|
_bufferLength = nBlocksRetrieved;
|
||||||
array<Int32,2>^ _sampleBuffer = gcnew array<Int32,2> (nBlocksRetrieved, 2);
|
|
||||||
interior_ptr<Int32> pMyBuffer = &_sampleBuffer[0, 0];
|
|
||||||
|
|
||||||
short * pAPEBuffer = (short *) pBuffer;
|
|
||||||
short * pAPEBufferEnd = (short *) pBuffer + 2 * nBlocksRetrieved;
|
|
||||||
|
|
||||||
while (pAPEBuffer < pAPEBufferEnd) {
|
|
||||||
*(pMyBuffer++) = *(pAPEBuffer++);
|
|
||||||
*(pMyBuffer++) = *(pAPEBuffer++);
|
|
||||||
}
|
|
||||||
|
|
||||||
sampleBuffer = _sampleBuffer;
|
|
||||||
_sampleOffset += nBlocksRetrieved;
|
_sampleOffset += nBlocksRetrieved;
|
||||||
|
}
|
||||||
|
UInt32 copyCount = Math::Min(samplesNeeded, SamplesInBuffer);
|
||||||
|
AudioSamples::BytesToFLACSamples_16(_samplesBuffer, _bufferOffset*nBlockAlign, buff, buffOffset, copyCount, _channelCount);
|
||||||
|
samplesNeeded -= copyCount;
|
||||||
|
buffOffset += copyCount;
|
||||||
|
_bufferOffset += copyCount;
|
||||||
|
}
|
||||||
return sampleCount;
|
return sampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,22 +261,33 @@ namespace APEDotNet {
|
|||||||
NameValueCollection^ _tags;
|
NameValueCollection^ _tags;
|
||||||
Int64 _sampleCount, _sampleOffset;
|
Int64 _sampleCount, _sampleOffset;
|
||||||
Int32 _bitsPerSample, _channelCount, _sampleRate;
|
Int32 _bitsPerSample, _channelCount, _sampleRate;
|
||||||
|
UInt32 _bufferOffset, _bufferLength;
|
||||||
int nBlockAlign;
|
int nBlockAlign;
|
||||||
unsigned char * pBuffer;
|
array<unsigned char>^ _samplesBuffer;
|
||||||
String^ _path;
|
String^ _path;
|
||||||
Stream^ _IO;
|
Stream^ _IO;
|
||||||
array<unsigned char>^ _readBuffer;
|
array<unsigned char>^ _readBuffer;
|
||||||
CWinFileIO* _winFileIO;
|
CWinFileIO* _winFileIO;
|
||||||
GCHandle _gchIO, _gchReadBuffer;
|
GCHandle _gchIO, _gchReadBuffer;
|
||||||
|
|
||||||
|
property UInt32 SamplesInBuffer
|
||||||
|
{
|
||||||
|
UInt32 get ()
|
||||||
|
{
|
||||||
|
return (UInt32) (_bufferLength - _bufferOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public ref class APEWriter {
|
public ref class APEWriter : IAudioDest
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
APEWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) {
|
APEWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate)
|
||||||
|
{
|
||||||
if ((channelCount != 1) && (channelCount != 2)) {
|
if (bitsPerSample != 16 && bitsPerSample != 24)
|
||||||
|
throw gcnew Exception("Bits per sample must be 16 or 24.");
|
||||||
|
if (channelCount != 1 && channelCount != 2)
|
||||||
throw gcnew Exception("Only stereo and mono audio formats are allowed.");
|
throw gcnew Exception("Only stereo and mono audio formats are allowed.");
|
||||||
}
|
|
||||||
|
|
||||||
_path = path;
|
_path = path;
|
||||||
_tags = gcnew NameValueCollection();
|
_tags = gcnew NameValueCollection();
|
||||||
@@ -279,9 +302,8 @@ namespace APEDotNet {
|
|||||||
|
|
||||||
int nRetVal;
|
int nRetVal;
|
||||||
pAPECompress = CreateIAPECompress (&nRetVal);
|
pAPECompress = CreateIAPECompress (&nRetVal);
|
||||||
if (!pAPECompress) {
|
if (!pAPECompress)
|
||||||
throw gcnew Exception("Unable to open file.");
|
throw gcnew Exception("Unable to open APE compressor.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~APEWriter()
|
~APEWriter()
|
||||||
@@ -294,7 +316,8 @@ namespace APEDotNet {
|
|||||||
_gchBuffer.Free();
|
_gchBuffer.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Close() {
|
virtual void Close()
|
||||||
|
{
|
||||||
if (pAPECompress)
|
if (pAPECompress)
|
||||||
{
|
{
|
||||||
pAPECompress->Finish (NULL, 0, 0);
|
pAPECompress->Finish (NULL, 0, 0);
|
||||||
@@ -322,21 +345,47 @@ namespace APEDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 FinalSampleCount {
|
virtual property Int64 FinalSampleCount
|
||||||
Int32 get() {
|
{
|
||||||
|
Int64 get()
|
||||||
|
{
|
||||||
return _finalSampleCount;
|
return _finalSampleCount;
|
||||||
}
|
}
|
||||||
void set(Int32 value) {
|
void set(Int64 value)
|
||||||
if (value < 0) {
|
{
|
||||||
|
if (value < 0)
|
||||||
throw gcnew Exception("Invalid final sample count.");
|
throw gcnew Exception("Invalid final sample count.");
|
||||||
}
|
if (_initialized)
|
||||||
if (_initialized) {
|
|
||||||
throw gcnew Exception("Final sample count cannot be changed after encoding begins.");
|
throw gcnew Exception("Final sample count cannot be changed after encoding begins.");
|
||||||
}
|
|
||||||
_finalSampleCount = value;
|
_finalSampleCount = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Write(array<Int32,2>^ buff, UInt32 sampleCount)
|
||||||
|
{
|
||||||
|
if (_sampleBuffer == nullptr || _sampleBuffer.Length < sampleCount * _blockAlign)
|
||||||
|
_sampleBuffer = gcnew array<unsigned char>(sampleCount * _blockAlign);
|
||||||
|
AudioSamples::FLACSamplesToBytes(buff, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample);
|
||||||
|
if (!_initialized) Initialize();
|
||||||
|
pin_ptr<unsigned char> pSampleBuffer = &_sampleBuffer[0];
|
||||||
|
if (pAPECompress->AddData (pSampleBuffer, sampleCount * _blockAlign))
|
||||||
|
throw gcnew Exception("An error occurred while encoding.");
|
||||||
|
_samplesWritten += sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual property String^ Path
|
||||||
|
{
|
||||||
|
String^ get() {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool SetTags (NameValueCollection^ tags)
|
||||||
|
{
|
||||||
|
_tags = tags;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
property Int32 CompressionLevel {
|
property Int32 CompressionLevel {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _compressionLevel;
|
return _compressionLevel;
|
||||||
@@ -349,24 +398,6 @@ namespace APEDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(array<unsigned char>^ sampleBuffer, UInt32 sampleCount) {
|
|
||||||
if (!_initialized) Initialize();
|
|
||||||
pin_ptr<unsigned char> pSampleBuffer = &sampleBuffer[0];
|
|
||||||
if (pAPECompress->AddData (pSampleBuffer, sampleCount * _blockAlign))
|
|
||||||
throw gcnew Exception("An error occurred while encoding.");
|
|
||||||
_samplesWritten += sampleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
property String^ Path {
|
|
||||||
String^ get() {
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTags (NameValueCollection^ tags) {
|
|
||||||
_tags = tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IAPECompress * pAPECompress;
|
IAPECompress * pAPECompress;
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
@@ -379,6 +410,7 @@ namespace APEDotNet {
|
|||||||
GCHandle _gchIO, _gchBuffer;
|
GCHandle _gchIO, _gchBuffer;
|
||||||
CWinFileIO* _winFileIO;
|
CWinFileIO* _winFileIO;
|
||||||
array<unsigned char>^ _writeBuffer;
|
array<unsigned char>^ _writeBuffer;
|
||||||
|
array<unsigned char>^ _sampleBuffer;
|
||||||
|
|
||||||
void Initialize() {
|
void Initialize() {
|
||||||
_IO = gcnew FileStream (_path, FileMode::Create, FileAccess::ReadWrite, FileShare::Read);
|
_IO = gcnew FileStream (_path, FileMode::Create, FileAccess::ReadWrite, FileShare::Read);
|
||||||
@@ -408,7 +440,10 @@ namespace APEDotNet {
|
|||||||
{
|
{
|
||||||
array<unsigned char>^ buff = (array<unsigned char>^) _gchBuffer.Target;
|
array<unsigned char>^ buff = (array<unsigned char>^) _gchBuffer.Target;
|
||||||
if (buff->Length < nBytesToRead)
|
if (buff->Length < nBytesToRead)
|
||||||
|
{
|
||||||
Array::Resize (buff, nBytesToRead);
|
Array::Resize (buff, nBytesToRead);
|
||||||
|
_gchBuffer.Target = buff;
|
||||||
|
}
|
||||||
int len = ((Stream^)_gchIO.Target)->Read (buff, 0, nBytesToRead);
|
int len = ((Stream^)_gchIO.Target)->Read (buff, 0, nBytesToRead);
|
||||||
if (len) Marshal::Copy (buff, 0, (IntPtr)pBuffer, len);
|
if (len) Marshal::Copy (buff, 0, (IntPtr)pBuffer, len);
|
||||||
*pBytesRead = len;
|
*pBytesRead = len;
|
||||||
@@ -419,7 +454,10 @@ namespace APEDotNet {
|
|||||||
{
|
{
|
||||||
array<unsigned char>^ buff = (array<unsigned char>^) _gchBuffer.Target;
|
array<unsigned char>^ buff = (array<unsigned char>^) _gchBuffer.Target;
|
||||||
if (buff->Length < nBytesToWrite)
|
if (buff->Length < nBytesToWrite)
|
||||||
|
{
|
||||||
Array::Resize (buff, nBytesToWrite);
|
Array::Resize (buff, nBytesToWrite);
|
||||||
|
_gchBuffer.Target = buff;
|
||||||
|
}
|
||||||
Marshal::Copy ((IntPtr)(void*)pBuffer, buff, 0, nBytesToWrite);
|
Marshal::Copy ((IntPtr)(void*)pBuffer, buff, 0, nBytesToWrite);
|
||||||
((Stream^)_gchIO.Target)->Write (buff, 0, nBytesToWrite);
|
((Stream^)_gchIO.Target)->Write (buff, 0, nBytesToWrite);
|
||||||
*pBytesWritten = nBytesToWrite;
|
*pBytesWritten = nBytesToWrite;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace AudioCodecsDotNet
|
|||||||
string Path { get; }
|
string Path { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AudioCodecsDotNet
|
public class AudioSamples
|
||||||
{
|
{
|
||||||
public static unsafe void FLACSamplesToBytes_16(int[,] inSamples, uint inSampleOffset,
|
public static unsafe void FLACSamplesToBytes_16(int[,] inSamples, uint inSampleOffset,
|
||||||
byte[] outSamples, uint outByteOffset, uint sampleCount, int channelCount)
|
byte[] outSamples, uint outByteOffset, uint sampleCount, int channelCount)
|
||||||
@@ -92,9 +92,9 @@ namespace AudioCodecsDotNet
|
|||||||
byte[] outSamples, uint outByteOffset, uint sampleCount, int channelCount, int bitsPerSample)
|
byte[] outSamples, uint outByteOffset, uint sampleCount, int channelCount, int bitsPerSample)
|
||||||
{
|
{
|
||||||
if (bitsPerSample == 16)
|
if (bitsPerSample == 16)
|
||||||
AudioCodecsDotNet.FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount);
|
AudioSamples.FLACSamplesToBytes_16(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount);
|
||||||
else if (bitsPerSample == 24)
|
else if (bitsPerSample == 24)
|
||||||
AudioCodecsDotNet.FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount);
|
AudioSamples.FLACSamplesToBytes_24(inSamples, inSampleOffset, outSamples, outByteOffset, sampleCount, channelCount);
|
||||||
else
|
else
|
||||||
throw new Exception("Unsupported bitsPerSample value");
|
throw new Exception("Unsupported bitsPerSample value");
|
||||||
}
|
}
|
||||||
@@ -483,7 +483,7 @@ namespace AudioCodecsDotNet
|
|||||||
_sampleBuffer = new byte[byteCount];
|
_sampleBuffer = new byte[byteCount];
|
||||||
if (_IO.Read(_sampleBuffer, 0, (int)byteCount) != byteCount)
|
if (_IO.Read(_sampleBuffer, 0, (int)byteCount) != byteCount)
|
||||||
throw new Exception("Incomplete file read.");
|
throw new Exception("Incomplete file read.");
|
||||||
AudioCodecsDotNet.BytesToFLACSamples_16 (_sampleBuffer, 0, buff, 0,
|
AudioSamples.BytesToFLACSamples_16(_sampleBuffer, 0, buff, 0,
|
||||||
sampleCount, _channelCount);
|
sampleCount, _channelCount);
|
||||||
_samplePos += sampleCount;
|
_samplePos += sampleCount;
|
||||||
return sampleCount;
|
return sampleCount;
|
||||||
@@ -596,7 +596,7 @@ namespace AudioCodecsDotNet
|
|||||||
return;
|
return;
|
||||||
if (_sampleBuffer == null || _sampleBuffer.Length < sampleCount * _blockAlign)
|
if (_sampleBuffer == null || _sampleBuffer.Length < sampleCount * _blockAlign)
|
||||||
_sampleBuffer = new byte[sampleCount * _blockAlign];
|
_sampleBuffer = new byte[sampleCount * _blockAlign];
|
||||||
AudioCodecsDotNet.FLACSamplesToBytes(buff, 0, _sampleBuffer, 0,
|
AudioSamples.FLACSamplesToBytes(buff, 0, _sampleBuffer, 0,
|
||||||
sampleCount, _channelCount, _bitsPerSample);
|
sampleCount, _channelCount, _bitsPerSample);
|
||||||
_IO.Write(_sampleBuffer, 0, (int)sampleCount * _blockAlign);
|
_IO.Write(_sampleBuffer, 0, (int)sampleCount * _blockAlign);
|
||||||
_sampleLen += sampleCount;
|
_sampleLen += sampleCount;
|
||||||
|
|||||||
@@ -53,500 +53,4 @@ namespace CUEToolsLib {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !MONO
|
|
||||||
class FLACReader : IAudioSource {
|
|
||||||
FLACDotNet.FLACReader _flacReader;
|
|
||||||
int[,] _sampleBuffer;
|
|
||||||
uint _bufferOffset, _bufferLength;
|
|
||||||
|
|
||||||
public FLACReader(string path, Stream IO)
|
|
||||||
{
|
|
||||||
_flacReader = new FLACDotNet.FLACReader(path, IO);
|
|
||||||
_bufferOffset = 0;
|
|
||||||
_bufferLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close() {
|
|
||||||
_flacReader.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameValueCollection Tags
|
|
||||||
{
|
|
||||||
get { return _flacReader.Tags; }
|
|
||||||
set { _flacReader.Tags = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UpdateTags(bool preserveTime)
|
|
||||||
{
|
|
||||||
return _flacReader.UpdateTags(preserveTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Length {
|
|
||||||
get {
|
|
||||||
return (ulong) _flacReader.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Remaining {
|
|
||||||
get {
|
|
||||||
return (ulong) _flacReader.Remaining + SamplesInBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Position {
|
|
||||||
get {
|
|
||||||
return (ulong) _flacReader.Position - SamplesInBuffer;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_flacReader.Position = (long) value;
|
|
||||||
_bufferOffset = 0;
|
|
||||||
_bufferLength = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint SamplesInBuffer {
|
|
||||||
get {
|
|
||||||
return (uint) (_bufferLength - _bufferOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BitsPerSample {
|
|
||||||
get {
|
|
||||||
return _flacReader.BitsPerSample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ChannelCount {
|
|
||||||
get {
|
|
||||||
return _flacReader.ChannelCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SampleRate {
|
|
||||||
get {
|
|
||||||
return _flacReader.SampleRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint Read(int [,] buff, uint sampleCount) {
|
|
||||||
if (_flacReader.BitsPerSample != 16) {
|
|
||||||
throw new Exception("Reading is only supported for 16 bit sample depth.");
|
|
||||||
}
|
|
||||||
int chanCount = _flacReader.ChannelCount;
|
|
||||||
uint copyCount;
|
|
||||||
uint buffOffset = 0;
|
|
||||||
uint samplesNeeded = sampleCount;
|
|
||||||
|
|
||||||
while (samplesNeeded != 0) {
|
|
||||||
if (SamplesInBuffer == 0) {
|
|
||||||
_bufferOffset = 0;
|
|
||||||
_bufferLength = (uint) _flacReader.Read(out _sampleBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
copyCount = Math.Min(samplesNeeded, SamplesInBuffer);
|
|
||||||
Array.Copy(_sampleBuffer, _bufferOffset * chanCount, buff, buffOffset * chanCount, copyCount * chanCount);
|
|
||||||
|
|
||||||
samplesNeeded -= copyCount;
|
|
||||||
buffOffset += copyCount;
|
|
||||||
_bufferOffset += copyCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sampleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get { return _flacReader.Path; } }
|
|
||||||
}
|
|
||||||
|
|
||||||
class FLACWriter : IAudioDest {
|
|
||||||
FLACDotNet.FLACWriter _flacWriter;
|
|
||||||
int _bitsPerSample;
|
|
||||||
int _channelCount;
|
|
||||||
int _sampleRate;
|
|
||||||
|
|
||||||
public FLACWriter(string path, int bitsPerSample, int channelCount, int sampleRate) {
|
|
||||||
if (bitsPerSample != 16 && bitsPerSample != 24) {
|
|
||||||
throw new Exception("Bits per sample must be 16 or 24.");
|
|
||||||
}
|
|
||||||
_bitsPerSample = bitsPerSample;
|
|
||||||
_channelCount = channelCount;
|
|
||||||
_sampleRate = sampleRate;
|
|
||||||
_flacWriter = new FLACDotNet.FLACWriter(path, bitsPerSample, channelCount, sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long FinalSampleCount {
|
|
||||||
get {
|
|
||||||
return _flacWriter.FinalSampleCount;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_flacWriter.FinalSampleCount = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompressionLevel {
|
|
||||||
get {
|
|
||||||
return _flacWriter.CompressionLevel;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_flacWriter.CompressionLevel = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Verify {
|
|
||||||
get {
|
|
||||||
return _flacWriter.Verify;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_flacWriter.Verify = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetTags(NameValueCollection tags)
|
|
||||||
{
|
|
||||||
_flacWriter.SetTags (tags);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close() {
|
|
||||||
_flacWriter.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(int[,] buff, uint sampleCount)
|
|
||||||
{
|
|
||||||
_flacWriter.Write(buff, (int) sampleCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get { return _flacWriter.Path; } }
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !MONO
|
|
||||||
class APEReader : IAudioSource {
|
|
||||||
APEDotNet.APEReader _apeReader;
|
|
||||||
int[,] _sampleBuffer;
|
|
||||||
uint _bufferOffset, _bufferLength;
|
|
||||||
|
|
||||||
public APEReader(string path, Stream IO) {
|
|
||||||
_apeReader = new APEDotNet.APEReader(path, IO);
|
|
||||||
_bufferOffset = 0;
|
|
||||||
_bufferLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close() {
|
|
||||||
_apeReader.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Length {
|
|
||||||
get {
|
|
||||||
return (ulong) _apeReader.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Remaining {
|
|
||||||
get {
|
|
||||||
return (ulong) _apeReader.Remaining + SamplesInBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Position {
|
|
||||||
get {
|
|
||||||
return (ulong) _apeReader.Position - SamplesInBuffer;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_apeReader.Position = (long) value;
|
|
||||||
_bufferOffset = 0;
|
|
||||||
_bufferLength = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint SamplesInBuffer {
|
|
||||||
get {
|
|
||||||
return (uint) (_bufferLength - _bufferOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BitsPerSample {
|
|
||||||
get {
|
|
||||||
return _apeReader.BitsPerSample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ChannelCount {
|
|
||||||
get {
|
|
||||||
return _apeReader.ChannelCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SampleRate {
|
|
||||||
get {
|
|
||||||
return _apeReader.SampleRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameValueCollection Tags
|
|
||||||
{
|
|
||||||
get { return _apeReader.Tags; }
|
|
||||||
set { _apeReader.Tags = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe void APESamplesToFLACSamples(int[,] inSamples, uint inSampleOffset,
|
|
||||||
int[,] outSamples, uint outSampleOffset, uint sampleCount, int channelCount)
|
|
||||||
{
|
|
||||||
uint loopCount = sampleCount * (uint) channelCount;
|
|
||||||
|
|
||||||
if ((inSamples.GetLength(0) - inSampleOffset < sampleCount) ||
|
|
||||||
(outSamples.GetLength(0) - outSampleOffset < sampleCount))
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed (int* pInSamplesFixed = &inSamples[inSampleOffset, 0]) {
|
|
||||||
fixed (int * pOutSamplesFixed = &outSamples[outSampleOffset, 0]) {
|
|
||||||
int* pInSamples = pInSamplesFixed;
|
|
||||||
int* pOutSamples = pOutSamplesFixed;
|
|
||||||
|
|
||||||
for (int i = 0; i < loopCount; i++) {
|
|
||||||
*(pOutSamples++) = *(pInSamples++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint Read(int[,] buff, uint sampleCount) {
|
|
||||||
if (_apeReader.BitsPerSample != 16) {
|
|
||||||
throw new Exception("Reading is only supported for 16 bit sample depth.");
|
|
||||||
}
|
|
||||||
int chanCount = _apeReader.ChannelCount;
|
|
||||||
uint samplesNeeded, copyCount, buffOffset;
|
|
||||||
|
|
||||||
buffOffset = 0;
|
|
||||||
samplesNeeded = sampleCount;
|
|
||||||
|
|
||||||
while (samplesNeeded != 0) {
|
|
||||||
if (SamplesInBuffer == 0) {
|
|
||||||
_bufferOffset = 0;
|
|
||||||
_bufferLength = (uint) _apeReader.Read(out _sampleBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
copyCount = Math.Min(samplesNeeded, SamplesInBuffer);
|
|
||||||
|
|
||||||
|
|
||||||
Array.Copy(_sampleBuffer, _bufferOffset * chanCount, buff, buffOffset * chanCount, copyCount * chanCount);
|
|
||||||
//APESamplesToFLACSamples(_sampleBuffer, _bufferOffset, buff, buffOffset,
|
|
||||||
// copyCount, chanCount);
|
|
||||||
|
|
||||||
samplesNeeded -= copyCount;
|
|
||||||
buffOffset += copyCount;
|
|
||||||
_bufferOffset += copyCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sampleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get { return _apeReader.Path; } }
|
|
||||||
}
|
|
||||||
|
|
||||||
class APEWriter : IAudioDest
|
|
||||||
{
|
|
||||||
APEDotNet.APEWriter _apeWriter;
|
|
||||||
byte[] _sampleBuffer;
|
|
||||||
int _bitsPerSample;
|
|
||||||
int _channelCount;
|
|
||||||
int _sampleRate;
|
|
||||||
int _blockAlign;
|
|
||||||
|
|
||||||
public APEWriter(string path, int bitsPerSample, int channelCount, int sampleRate)
|
|
||||||
{
|
|
||||||
if (bitsPerSample != 16 && bitsPerSample != 24)
|
|
||||||
{
|
|
||||||
throw new Exception("Bits per sample must be 16 or 24.");
|
|
||||||
}
|
|
||||||
_bitsPerSample = bitsPerSample;
|
|
||||||
_channelCount = channelCount;
|
|
||||||
_sampleRate = sampleRate;
|
|
||||||
_blockAlign = _channelCount * ((_bitsPerSample + 7) / 8);
|
|
||||||
_apeWriter = new APEDotNet.APEWriter(path, bitsPerSample, channelCount, sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long FinalSampleCount
|
|
||||||
{
|
|
||||||
get { return _apeWriter.FinalSampleCount; }
|
|
||||||
set { _apeWriter.FinalSampleCount = (int) value; }
|
|
||||||
}
|
|
||||||
public int CompressionLevel
|
|
||||||
{
|
|
||||||
get { return _apeWriter.CompressionLevel; }
|
|
||||||
set { _apeWriter.CompressionLevel = value; }
|
|
||||||
}
|
|
||||||
public bool SetTags(NameValueCollection tags)
|
|
||||||
{
|
|
||||||
_apeWriter.SetTags(tags);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
_apeWriter.Close();
|
|
||||||
}
|
|
||||||
public void Write(int [,] buff, uint sampleCount)
|
|
||||||
{
|
|
||||||
if (_sampleBuffer == null || _sampleBuffer.Length < sampleCount * _blockAlign)
|
|
||||||
_sampleBuffer = new byte[sampleCount * _blockAlign];
|
|
||||||
AudioCodecsDotNet.AudioCodecsDotNet.FLACSamplesToBytes (buff, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample);
|
|
||||||
_apeWriter.Write(_sampleBuffer, sampleCount);
|
|
||||||
}
|
|
||||||
public string Path { get { return _apeWriter.Path; } }
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !MONO
|
|
||||||
class WavPackReader : IAudioSource {
|
|
||||||
WavPackDotNet.WavPackReader _wavPackReader;
|
|
||||||
|
|
||||||
public WavPackReader(string path, Stream IO, Stream IO_WVC) {
|
|
||||||
_wavPackReader = new WavPackDotNet.WavPackReader(path, IO, IO_WVC);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close() {
|
|
||||||
_wavPackReader.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Length {
|
|
||||||
get {
|
|
||||||
return (ulong) _wavPackReader.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Remaining {
|
|
||||||
get {
|
|
||||||
return (ulong) _wavPackReader.Remaining;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong Position {
|
|
||||||
get {
|
|
||||||
return (ulong) _wavPackReader.Position;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_wavPackReader.Position = (int) value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BitsPerSample {
|
|
||||||
get {
|
|
||||||
return _wavPackReader.BitsPerSample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ChannelCount {
|
|
||||||
get {
|
|
||||||
return _wavPackReader.ChannelCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SampleRate {
|
|
||||||
get {
|
|
||||||
return _wavPackReader.SampleRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameValueCollection Tags
|
|
||||||
{
|
|
||||||
get { return _wavPackReader.Tags; }
|
|
||||||
set { _wavPackReader.Tags = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint Read(int[,] buff, uint sampleCount) {
|
|
||||||
if (_wavPackReader.BitsPerSample != 16) {
|
|
||||||
throw new Exception("Reading is only supported for 16 bit sample depth.");
|
|
||||||
}
|
|
||||||
_wavPackReader.Read(buff, (int) sampleCount);
|
|
||||||
return sampleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get { return _wavPackReader.Path; } }
|
|
||||||
}
|
|
||||||
|
|
||||||
class WavPackWriter : IAudioDest {
|
|
||||||
WavPackDotNet.WavPackWriter _wavPackWriter;
|
|
||||||
int _bitsPerSample;
|
|
||||||
int _channelCount;
|
|
||||||
int _sampleRate;
|
|
||||||
int _blockAlign;
|
|
||||||
byte[] _sampleBuffer;
|
|
||||||
|
|
||||||
public WavPackWriter(string path, int bitsPerSample, int channelCount, int sampleRate) {
|
|
||||||
if (bitsPerSample != 16 && bitsPerSample != 24)
|
|
||||||
{
|
|
||||||
throw new Exception("Bits per sample must be 16 or 24.");
|
|
||||||
}
|
|
||||||
_bitsPerSample = bitsPerSample;
|
|
||||||
_channelCount = channelCount;
|
|
||||||
_sampleRate = sampleRate;
|
|
||||||
_blockAlign = _channelCount * ((_bitsPerSample + 7) / 8);
|
|
||||||
_wavPackWriter = new WavPackDotNet.WavPackWriter(path, bitsPerSample, channelCount, sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetTags(NameValueCollection tags)
|
|
||||||
{
|
|
||||||
_wavPackWriter.SetTags(tags);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long FinalSampleCount {
|
|
||||||
get {
|
|
||||||
return _wavPackWriter.FinalSampleCount;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_wavPackWriter.FinalSampleCount = (int)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompressionMode {
|
|
||||||
get {
|
|
||||||
return _wavPackWriter.CompressionMode;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_wavPackWriter.CompressionMode = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ExtraMode {
|
|
||||||
get {
|
|
||||||
return _wavPackWriter.ExtraMode;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_wavPackWriter.ExtraMode = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MD5Sum
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _wavPackWriter.MD5Sum;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_wavPackWriter.MD5Sum = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close() {
|
|
||||||
_wavPackWriter.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(int[,] sampleBuffer, uint sampleCount) {
|
|
||||||
if (MD5Sum)
|
|
||||||
{
|
|
||||||
if (_sampleBuffer == null || _sampleBuffer.Length < sampleCount * _blockAlign)
|
|
||||||
_sampleBuffer = new byte[sampleCount * _blockAlign];
|
|
||||||
AudioCodecsDotNet.AudioCodecsDotNet.FLACSamplesToBytes(sampleBuffer, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample);
|
|
||||||
_wavPackWriter.UpdateHash(_sampleBuffer, (int) sampleCount * _blockAlign);
|
|
||||||
}
|
|
||||||
_wavPackWriter.Write(sampleBuffer, (int) sampleCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get { return _wavPackWriter.Path; } }
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
@@ -31,6 +31,9 @@ using AudioCodecsDotNet;
|
|||||||
using HDCDDotNet;
|
using HDCDDotNet;
|
||||||
#if !MONO
|
#if !MONO
|
||||||
using UnRarDotNet;
|
using UnRarDotNet;
|
||||||
|
using FLACDotNet;
|
||||||
|
using APEDotNet;
|
||||||
|
using WavPackDotNet;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace CUEToolsLib
|
namespace CUEToolsLib
|
||||||
|
|||||||
@@ -328,6 +328,10 @@
|
|||||||
RelativePath="System.XML.dll"
|
RelativePath="System.XML.dll"
|
||||||
AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
|
AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
|
||||||
/>
|
/>
|
||||||
|
<ProjectReference
|
||||||
|
ReferencedProjectIdentifier="{6458A13A-30EF-45A9-9D58-E5031B17BEE2}"
|
||||||
|
RelativePathToProject="..\AudioCodecsDotNet\AudioCodecsDotNet.csproj"
|
||||||
|
/>
|
||||||
</References>
|
</References>
|
||||||
<Files>
|
<Files>
|
||||||
<Filter
|
<Filter
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ using namespace System::IO;
|
|||||||
using namespace System::Collections::Generic;
|
using namespace System::Collections::Generic;
|
||||||
using namespace System::Collections::Specialized;
|
using namespace System::Collections::Specialized;
|
||||||
using namespace System::Runtime::InteropServices;
|
using namespace System::Runtime::InteropServices;
|
||||||
|
using namespace AudioCodecsDotNet;
|
||||||
|
|
||||||
#include "FLAC\all.h"
|
#include "FLAC\all.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -67,9 +68,11 @@ namespace FLACDotNet {
|
|||||||
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
|
||||||
public delegate FLAC__bool DecoderEofDelegate (const FLAC__StreamDecoder *decoder, void *client_data);
|
public delegate FLAC__bool DecoderEofDelegate (const FLAC__StreamDecoder *decoder, void *client_data);
|
||||||
|
|
||||||
public ref class FLACReader {
|
public ref class FLACReader : public IAudioSource
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
FLACReader(String^ path, Stream^ IO) {
|
FLACReader(String^ path, Stream^ IO)
|
||||||
|
{
|
||||||
_tags = gcnew NameValueCollection();
|
_tags = gcnew NameValueCollection();
|
||||||
|
|
||||||
_writeDel = gcnew DecoderWriteDelegate(this, &FLACReader::WriteCallback);
|
_writeDel = gcnew DecoderWriteDelegate(this, &FLACReader::WriteCallback);
|
||||||
@@ -84,9 +87,10 @@ namespace FLACDotNet {
|
|||||||
_decoderActive = false;
|
_decoderActive = false;
|
||||||
|
|
||||||
_sampleOffset = 0;
|
_sampleOffset = 0;
|
||||||
_samplesWaiting = 0;
|
|
||||||
_sampleBuffer = nullptr;
|
_sampleBuffer = nullptr;
|
||||||
_path = path;
|
_path = path;
|
||||||
|
_bufferOffset = 0;
|
||||||
|
_bufferLength = 0;
|
||||||
|
|
||||||
_IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read);
|
_IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read);
|
||||||
|
|
||||||
@@ -122,50 +126,53 @@ namespace FLACDotNet {
|
|||||||
Close ();
|
Close ();
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 BitsPerSample {
|
virtual property Int32 BitsPerSample {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _bitsPerSample;
|
return _bitsPerSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 ChannelCount {
|
virtual property Int32 ChannelCount {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _channelCount;
|
return _channelCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 SampleRate {
|
virtual property Int32 SampleRate {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _sampleRate;
|
return _sampleRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int64 Length {
|
virtual property UInt64 Length {
|
||||||
Int64 get() {
|
UInt64 get() {
|
||||||
return _sampleCount;
|
return _sampleCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int64 Position {
|
virtual property UInt64 Position {
|
||||||
Int64 get() {
|
UInt64 get()
|
||||||
return _sampleOffset;
|
{
|
||||||
|
return _sampleOffset - SamplesInBuffer;
|
||||||
}
|
}
|
||||||
void set(Int64 offset) {
|
void set(UInt64 offset)
|
||||||
|
{
|
||||||
_sampleOffset = offset;
|
_sampleOffset = offset;
|
||||||
_samplesWaiting = 0;
|
_bufferOffset = 0;
|
||||||
|
_bufferLength = 0;
|
||||||
if (!FLAC__stream_decoder_seek_absolute(_decoder, offset)) {
|
if (!FLAC__stream_decoder_seek_absolute(_decoder, offset)) {
|
||||||
throw gcnew Exception("Unable to seek.");
|
throw gcnew Exception("Unable to seek.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property String^ Path {
|
virtual property String^ Path {
|
||||||
String^ get() {
|
String^ get() {
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property NameValueCollection^ Tags {
|
virtual property NameValueCollection^ Tags {
|
||||||
NameValueCollection^ get () {
|
NameValueCollection^ get () {
|
||||||
return _tags;
|
return _tags;
|
||||||
}
|
}
|
||||||
@@ -238,13 +245,13 @@ namespace FLACDotNet {
|
|||||||
return 0 != res;
|
return 0 != res;
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int64 Remaining {
|
virtual property UInt64 Remaining {
|
||||||
Int64 get() {
|
UInt64 get() {
|
||||||
return _sampleCount - _sampleOffset;
|
return _sampleCount - _sampleOffset + SamplesInBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Close() {
|
virtual void Close() {
|
||||||
if (_decoderActive)
|
if (_decoderActive)
|
||||||
{
|
{
|
||||||
FLAC__stream_decoder_finish(_decoder);
|
FLAC__stream_decoder_finish(_decoder);
|
||||||
@@ -258,18 +265,30 @@ namespace FLACDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Int32 Read([Out] array<Int32, 2>^% sampleBuffer)
|
virtual UInt32 Read([Out] array<Int32, 2>^ buff, UInt32 sampleCount)
|
||||||
{
|
{
|
||||||
while (_samplesWaiting == 0) {
|
UInt32 buffOffset = 0;
|
||||||
if (!FLAC__stream_decoder_process_single(_decoder)) {
|
UInt32 samplesNeeded = sampleCount;
|
||||||
throw gcnew Exception("An error occurred while decoding.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int sampleCount = _samplesWaiting;
|
while (samplesNeeded != 0)
|
||||||
sampleBuffer = _sampleBuffer;
|
{
|
||||||
_sampleOffset += sampleCount;
|
if (SamplesInBuffer == 0)
|
||||||
_samplesWaiting = 0;
|
{
|
||||||
|
_bufferOffset = 0;
|
||||||
|
_bufferLength = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!FLAC__stream_decoder_process_single(_decoder))
|
||||||
|
throw gcnew Exception("An error occurred while decoding.");
|
||||||
|
} while (_bufferLength == 0);
|
||||||
|
_sampleOffset += _bufferLength;
|
||||||
|
}
|
||||||
|
UInt32 copyCount = Math::Min(samplesNeeded, SamplesInBuffer);
|
||||||
|
Array::Copy(_sampleBuffer, _bufferOffset * _channelCount, buff, buffOffset * _channelCount, copyCount * _channelCount);
|
||||||
|
samplesNeeded -= copyCount;
|
||||||
|
buffOffset += copyCount;
|
||||||
|
_bufferOffset += copyCount;
|
||||||
|
}
|
||||||
return sampleCount;
|
return sampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,18 +306,25 @@ namespace FLACDotNet {
|
|||||||
Int32 _bitsPerSample, _channelCount, _sampleRate;
|
Int32 _bitsPerSample, _channelCount, _sampleRate;
|
||||||
array<Int32, 2>^ _sampleBuffer;
|
array<Int32, 2>^ _sampleBuffer;
|
||||||
array<unsigned char>^ _readBuffer;
|
array<unsigned char>^ _readBuffer;
|
||||||
int _samplesWaiting;
|
|
||||||
NameValueCollection^ _tags;
|
NameValueCollection^ _tags;
|
||||||
String^ _path;
|
String^ _path;
|
||||||
bool _decoderActive;
|
bool _decoderActive;
|
||||||
Stream^ _IO;
|
Stream^ _IO;
|
||||||
|
UInt32 _bufferOffset, _bufferLength;
|
||||||
|
|
||||||
|
property UInt32 SamplesInBuffer {
|
||||||
|
UInt32 get ()
|
||||||
|
{
|
||||||
|
return (UInt32) (_bufferLength - _bufferOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder,
|
FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder,
|
||||||
const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
||||||
{
|
{
|
||||||
Int32 sampleCount = frame->header.blocksize;
|
Int32 sampleCount = frame->header.blocksize;
|
||||||
|
|
||||||
if (_samplesWaiting > 0) {
|
if (_bufferLength > 0) {
|
||||||
throw gcnew Exception("Received unrequested samples.");
|
throw gcnew Exception("Received unrequested samples.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,8 +351,7 @@ namespace FLACDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_samplesWaiting = sampleCount;
|
_bufferLength = sampleCount;
|
||||||
|
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,9 +450,14 @@ namespace FLACDotNet {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public ref class FLACWriter {
|
public ref class FLACWriter : IAudioDest
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
FLACWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) {
|
FLACWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate)
|
||||||
|
{
|
||||||
|
if (bitsPerSample != 16 && bitsPerSample != 24)
|
||||||
|
throw gcnew Exception("Bits per sample must be 16 or 24.");
|
||||||
|
|
||||||
_initialized = false;
|
_initialized = false;
|
||||||
_path = path;
|
_path = path;
|
||||||
_finalSampleCount = 0;
|
_finalSampleCount = 0;
|
||||||
@@ -447,7 +477,7 @@ namespace FLACDotNet {
|
|||||||
FLAC__stream_encoder_set_sample_rate(_encoder, sampleRate);
|
FLAC__stream_encoder_set_sample_rate(_encoder, sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Close() {
|
virtual void Close() {
|
||||||
FLAC__stream_encoder_finish(_encoder);
|
FLAC__stream_encoder_finish(_encoder);
|
||||||
|
|
||||||
for (int i = 0; i < _metadataCount; i++) {
|
for (int i = 0; i < _metadataCount; i++) {
|
||||||
@@ -466,7 +496,7 @@ namespace FLACDotNet {
|
|||||||
_tags->Clear ();
|
_tags->Clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int64 FinalSampleCount {
|
virtual property Int64 FinalSampleCount {
|
||||||
Int64 get() {
|
Int64 get() {
|
||||||
return _finalSampleCount;
|
return _finalSampleCount;
|
||||||
}
|
}
|
||||||
@@ -481,6 +511,32 @@ namespace FLACDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool SetTags (NameValueCollection^ tags)
|
||||||
|
{
|
||||||
|
_tags = tags;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual property String^ Path {
|
||||||
|
String^ get() {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Write(array<Int32, 2>^ sampleBuffer, UInt32 sampleCount) {
|
||||||
|
if (!_initialized) Initialize();
|
||||||
|
|
||||||
|
pin_ptr<Int32> pSampleBuffer = &sampleBuffer[0, 0];
|
||||||
|
|
||||||
|
if (!FLAC__stream_encoder_process_interleaved(_encoder,
|
||||||
|
(const FLAC__int32*)pSampleBuffer, sampleCount))
|
||||||
|
{
|
||||||
|
throw gcnew Exception("An error occurred while encoding.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_samplesWritten += sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
property Int32 CompressionLevel {
|
property Int32 CompressionLevel {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _compressionLevel;
|
return _compressionLevel;
|
||||||
@@ -514,30 +570,6 @@ namespace FLACDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTags (NameValueCollection^ tags) {
|
|
||||||
_tags = tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
property String^ Path {
|
|
||||||
String^ get() {
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Write(array<Int32, 2>^ sampleBuffer, Int32 sampleCount) {
|
|
||||||
if (!_initialized) Initialize();
|
|
||||||
|
|
||||||
pin_ptr<Int32> pSampleBuffer = &sampleBuffer[0, 0];
|
|
||||||
|
|
||||||
if (!FLAC__stream_encoder_process_interleaved(_encoder,
|
|
||||||
(const FLAC__int32*)pSampleBuffer, sampleCount))
|
|
||||||
{
|
|
||||||
throw gcnew Exception("An error occurred while encoding.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_samplesWritten += sampleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FLAC__StreamEncoder *_encoder;
|
FLAC__StreamEncoder *_encoder;
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ namespace HDCDDotNet
|
|||||||
{
|
{
|
||||||
if (_inSampleBuffer == null || _inSampleBuffer.GetLength(0) < sampleCount)
|
if (_inSampleBuffer == null || _inSampleBuffer.GetLength(0) < sampleCount)
|
||||||
_inSampleBuffer = new int[sampleCount, _channelCount];
|
_inSampleBuffer = new int[sampleCount, _channelCount];
|
||||||
AudioCodecsDotNet.AudioCodecsDotNet.BytesToFLACSamples_16(buff, 0, _inSampleBuffer, 0, sampleCount, _channelCount);
|
AudioSamples.BytesToFLACSamples_16(buff, 0, _inSampleBuffer, 0, sampleCount, _channelCount);
|
||||||
Process(_inSampleBuffer, sampleCount);
|
Process(_inSampleBuffer, sampleCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -35,6 +35,7 @@ using namespace System::Collections::Specialized;
|
|||||||
using namespace System::Security::Cryptography;
|
using namespace System::Security::Cryptography;
|
||||||
using namespace System::IO;
|
using namespace System::IO;
|
||||||
using namespace APETagsDotNet;
|
using namespace APETagsDotNet;
|
||||||
|
using namespace AudioCodecsDotNet;
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
@@ -59,9 +60,11 @@ namespace WavPackDotNet {
|
|||||||
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
|
||||||
public delegate int DecoderCanSeekDelegate(void *id);
|
public delegate int DecoderCanSeekDelegate(void *id);
|
||||||
|
|
||||||
public ref class WavPackReader {
|
public ref class WavPackReader : public IAudioSource
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
WavPackReader(String^ path, Stream^ IO, Stream^ IO_WVC) {
|
WavPackReader(String^ path, Stream^ IO, Stream^ IO_WVC)
|
||||||
|
{
|
||||||
char errorMessage[256];
|
char errorMessage[256];
|
||||||
|
|
||||||
_readDel = gcnew DecoderReadDelegate (this, &WavPackReader::ReadCallback);
|
_readDel = gcnew DecoderReadDelegate (this, &WavPackReader::ReadCallback);
|
||||||
@@ -89,14 +92,6 @@ namespace WavPackDotNet {
|
|||||||
_IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read);
|
_IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read);
|
||||||
_IO_WVC = (IO != nullptr) ? IO_WVC : System::IO::File::Exists (path+"c") ? gcnew FileStream (path+"c", FileMode::Open, FileAccess::Read, FileShare::Read) : nullptr;
|
_IO_WVC = (IO != nullptr) ? IO_WVC : System::IO::File::Exists (path+"c") ? gcnew FileStream (path+"c", FileMode::Open, FileAccess::Read, FileShare::Read) : nullptr;
|
||||||
|
|
||||||
//IntPtr pathChars;
|
|
||||||
//pathChars = Marshal::StringToHGlobalUni(path);
|
|
||||||
//size_t pathLen = wcslen ((const wchar_t*)pathChars.ToPointer())+1;
|
|
||||||
//wchar_t * pPath = new wchar_t[pathLen];
|
|
||||||
//memcpy ((void*) pPath, (const wchar_t*)pathChars.ToPointer(), pathLen*sizeof(wchar_t));
|
|
||||||
//Marshal::FreeHGlobal(pathChars);
|
|
||||||
//_wpc = WavpackOpenFileInput (pPath, errorMessage, OPEN_WVC, 0);
|
|
||||||
|
|
||||||
_wpc = WavpackOpenFileInputEx (ioReader, "v", _IO_WVC != nullptr ? "c" : NULL, errorMessage, OPEN_WVC, 0);
|
_wpc = WavpackOpenFileInputEx (ioReader, "v", _IO_WVC != nullptr ? "c" : NULL, errorMessage, OPEN_WVC, 0);
|
||||||
if (_wpc == NULL) {
|
if (_wpc == NULL) {
|
||||||
throw gcnew Exception("Unable to initialize the decoder.");
|
throw gcnew Exception("Unable to initialize the decoder.");
|
||||||
@@ -114,35 +109,35 @@ namespace WavPackDotNet {
|
|||||||
delete ioReader;
|
delete ioReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 BitsPerSample {
|
virtual property Int32 BitsPerSample {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _bitsPerSample;
|
return _bitsPerSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 ChannelCount {
|
virtual property Int32 ChannelCount {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _channelCount;
|
return _channelCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 SampleRate {
|
virtual property Int32 SampleRate {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _sampleRate;
|
return _sampleRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 Length {
|
virtual property UInt64 Length {
|
||||||
Int32 get() {
|
UInt64 get() {
|
||||||
return _sampleCount;
|
return _sampleCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 Position {
|
virtual property UInt64 Position {
|
||||||
Int32 get() {
|
UInt64 get() {
|
||||||
return _sampleOffset;
|
return _sampleOffset;
|
||||||
}
|
}
|
||||||
void set(Int32 offset) {
|
void set(UInt64 offset) {
|
||||||
_sampleOffset = offset;
|
_sampleOffset = offset;
|
||||||
if (!WavpackSeekSample(_wpc, offset)) {
|
if (!WavpackSeekSample(_wpc, offset)) {
|
||||||
throw gcnew Exception("Unable to seek.");
|
throw gcnew Exception("Unable to seek.");
|
||||||
@@ -150,19 +145,19 @@ namespace WavPackDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 Remaining {
|
virtual property UInt64 Remaining {
|
||||||
Int32 get() {
|
UInt64 get() {
|
||||||
return _sampleCount - _sampleOffset;
|
return _sampleCount - _sampleOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property String^ Path {
|
virtual property String^ Path {
|
||||||
String^ get() {
|
String^ get() {
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property NameValueCollection^ Tags {
|
virtual property NameValueCollection^ Tags {
|
||||||
NameValueCollection^ get () {
|
NameValueCollection^ get () {
|
||||||
if (!_tags)
|
if (!_tags)
|
||||||
{
|
{
|
||||||
@@ -177,7 +172,7 @@ namespace WavPackDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Close()
|
virtual void Close()
|
||||||
{
|
{
|
||||||
_wpc = WavpackCloseFile(_wpc);
|
_wpc = WavpackCloseFile(_wpc);
|
||||||
if (_IO != nullptr)
|
if (_IO != nullptr)
|
||||||
@@ -192,16 +187,14 @@ namespace WavPackDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Read(array<Int32, 2>^ sampleBuffer, Int32 sampleCount) {
|
virtual UInt32 Read(array<Int32, 2>^ sampleBuffer, UInt32 sampleCount)
|
||||||
|
{
|
||||||
pin_ptr<Int32> pSampleBuffer = &sampleBuffer[0, 0];
|
pin_ptr<Int32> pSampleBuffer = &sampleBuffer[0, 0];
|
||||||
int samplesRead;
|
int samplesRead = WavpackUnpackSamples(_wpc, pSampleBuffer, sampleCount);
|
||||||
|
|
||||||
samplesRead = WavpackUnpackSamples(_wpc, pSampleBuffer, sampleCount);
|
|
||||||
_sampleOffset += samplesRead;
|
_sampleOffset += samplesRead;
|
||||||
|
if (samplesRead != sampleCount)
|
||||||
if (samplesRead != sampleCount) {
|
|
||||||
throw gcnew Exception("Decoder returned a different number of samples than requested.");
|
throw gcnew Exception("Decoder returned a different number of samples than requested.");
|
||||||
}
|
return sampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -312,14 +305,17 @@ namespace WavPackDotNet {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public ref class WavPackWriter {
|
public ref class WavPackWriter : IAudioDest
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
WavPackWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) {
|
WavPackWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate)
|
||||||
|
{
|
||||||
IntPtr pathChars;
|
IntPtr pathChars;
|
||||||
|
|
||||||
if ((channelCount != 1) && (channelCount != 2)) {
|
if (channelCount != 1 && channelCount != 2)
|
||||||
throw gcnew Exception("Only stereo and mono audio formats are allowed.");
|
throw gcnew Exception("Only stereo and mono audio formats are allowed.");
|
||||||
}
|
if (bitsPerSample != 16 && bitsPerSample != 24)
|
||||||
|
throw gcnew Exception("Bits per sample must be 16 or 24.");
|
||||||
|
|
||||||
_path = path;
|
_path = path;
|
||||||
_tags = gcnew NameValueCollection();
|
_tags = gcnew NameValueCollection();
|
||||||
@@ -330,6 +326,7 @@ namespace WavPackDotNet {
|
|||||||
_bitsPerSample = bitsPerSample;
|
_bitsPerSample = bitsPerSample;
|
||||||
_channelCount = channelCount;
|
_channelCount = channelCount;
|
||||||
_sampleRate = sampleRate;
|
_sampleRate = sampleRate;
|
||||||
|
_blockAlign = _channelCount * ((_bitsPerSample + 7) / 8);
|
||||||
|
|
||||||
pathChars = Marshal::StringToHGlobalUni(path);
|
pathChars = Marshal::StringToHGlobalUni(path);
|
||||||
_hFile = _wfopen((const wchar_t*)pathChars.ToPointer(), L"w+b");
|
_hFile = _wfopen((const wchar_t*)pathChars.ToPointer(), L"w+b");
|
||||||
@@ -339,7 +336,8 @@ namespace WavPackDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Close() {
|
virtual void Close()
|
||||||
|
{
|
||||||
if (_md5Sum)
|
if (_md5Sum)
|
||||||
{
|
{
|
||||||
_md5hasher->TransformFinalBlock (gcnew array<unsigned char>(1), 0, 0);
|
_md5hasher->TransformFinalBlock (gcnew array<unsigned char>(1), 0, 0);
|
||||||
@@ -365,21 +363,56 @@ namespace WavPackDotNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Int32 FinalSampleCount {
|
virtual property Int64 FinalSampleCount
|
||||||
Int32 get() {
|
{
|
||||||
|
Int64 get()
|
||||||
|
{
|
||||||
return _finalSampleCount;
|
return _finalSampleCount;
|
||||||
}
|
}
|
||||||
void set(Int32 value) {
|
void set(Int64 value)
|
||||||
if (value < 0) {
|
{
|
||||||
|
if (value < 0)
|
||||||
throw gcnew Exception("Invalid final sample count.");
|
throw gcnew Exception("Invalid final sample count.");
|
||||||
}
|
if (_initialized)
|
||||||
if (_initialized) {
|
|
||||||
throw gcnew Exception("Final sample count cannot be changed after encoding begins.");
|
throw gcnew Exception("Final sample count cannot be changed after encoding begins.");
|
||||||
}
|
|
||||||
_finalSampleCount = value;
|
_finalSampleCount = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Write(array<Int32, 2>^ sampleBuffer, UInt32 sampleCount)
|
||||||
|
{
|
||||||
|
if (!_initialized)
|
||||||
|
Initialize();
|
||||||
|
|
||||||
|
if (MD5Sum)
|
||||||
|
{
|
||||||
|
if (_sampleBuffer == nullptr || _sampleBuffer.Length < sampleCount * _blockAlign)
|
||||||
|
_sampleBuffer = gcnew array<unsigned char>(sampleCount * _blockAlign);
|
||||||
|
AudioSamples::FLACSamplesToBytes(sampleBuffer, 0, _sampleBuffer, 0, sampleCount, _channelCount, _bitsPerSample);
|
||||||
|
UpdateHash(_sampleBuffer, (int) sampleCount * _blockAlign);
|
||||||
|
}
|
||||||
|
|
||||||
|
pin_ptr<Int32> pSampleBuffer = &sampleBuffer[0, 0];
|
||||||
|
if (!WavpackPackSamples(_wpc, (int32_t*)pSampleBuffer, sampleCount)) {
|
||||||
|
throw gcnew Exception("An error occurred while encoding.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_samplesWritten += sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual property String^ Path
|
||||||
|
{
|
||||||
|
String^ get() {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool SetTags (NameValueCollection^ tags)
|
||||||
|
{
|
||||||
|
_tags = tags;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
property Int32 CompressionMode {
|
property Int32 CompressionMode {
|
||||||
Int32 get() {
|
Int32 get() {
|
||||||
return _compressionMode;
|
return _compressionMode;
|
||||||
@@ -422,38 +455,18 @@ namespace WavPackDotNet {
|
|||||||
_md5hasher->TransformBlock (buff, 0, len, buff, 0);
|
_md5hasher->TransformBlock (buff, 0, len, buff, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write(array<Int32, 2>^ sampleBuffer, Int32 sampleCount) {
|
|
||||||
if (!_initialized) Initialize();
|
|
||||||
|
|
||||||
pin_ptr<Int32> pSampleBuffer = &sampleBuffer[0, 0];
|
|
||||||
if (!WavpackPackSamples(_wpc, (int32_t*)pSampleBuffer, sampleCount)) {
|
|
||||||
throw gcnew Exception("An error occurred while encoding.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_samplesWritten += sampleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
property String^ Path {
|
|
||||||
String^ get() {
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTags (NameValueCollection^ tags) {
|
|
||||||
_tags = tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FILE *_hFile;
|
FILE *_hFile;
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
WavpackContext *_wpc;
|
WavpackContext *_wpc;
|
||||||
Int32 _finalSampleCount, _samplesWritten;
|
Int32 _finalSampleCount, _samplesWritten;
|
||||||
Int32 _bitsPerSample, _channelCount, _sampleRate;
|
Int32 _bitsPerSample, _channelCount, _sampleRate, _blockAlign;
|
||||||
Int32 _compressionMode, _extraMode;
|
Int32 _compressionMode, _extraMode;
|
||||||
NameValueCollection^ _tags;
|
NameValueCollection^ _tags;
|
||||||
String^ _path;
|
String^ _path;
|
||||||
bool _md5Sum;
|
bool _md5Sum;
|
||||||
MD5^ _md5hasher;
|
MD5^ _md5hasher;
|
||||||
|
array<unsigned char>^ _sampleBuffer;
|
||||||
|
|
||||||
void Initialize() {
|
void Initialize() {
|
||||||
WavpackConfig config;
|
WavpackConfig config;
|
||||||
|
|||||||
@@ -92,81 +92,6 @@
|
|||||||
Name="VCPostBuildEventTool"
|
Name="VCPostBuildEventTool"
|
||||||
/>
|
/>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(SolutionDir)..\obj\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="1"
|
|
||||||
ManagedExtensions="1"
|
|
||||||
WholeProgramOptimization="1"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalIncludeDirectories="../wavpack-4.5.0/include"
|
|
||||||
AdditionalUsingDirectories=""
|
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories=""
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
TargetMachine="1"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Debug|x64"
|
Name="Debug|x64"
|
||||||
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
||||||
@@ -242,6 +167,81 @@
|
|||||||
Name="VCPostBuildEventTool"
|
Name="VCPostBuildEventTool"
|
||||||
/>
|
/>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(SolutionDir)..\obj\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||||
|
ConfigurationType="2"
|
||||||
|
CharacterSet="1"
|
||||||
|
ManagedExtensions="1"
|
||||||
|
WholeProgramOptimization="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
AdditionalIncludeDirectories="../wavpack-4.5.0/include"
|
||||||
|
AdditionalUsingDirectories=""
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||||
|
RuntimeLibrary="2"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
LinkIncremental="1"
|
||||||
|
AdditionalLibraryDirectories=""
|
||||||
|
GenerateDebugInformation="true"
|
||||||
|
TargetMachine="1"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManifestTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAppVerifierTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebDeploymentTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Release|x64"
|
Name="Release|x64"
|
||||||
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
||||||
@@ -336,6 +336,10 @@
|
|||||||
ReferencedProjectIdentifier="{CA200BCB-DFC6-4153-9BD4-785BC768B26B}"
|
ReferencedProjectIdentifier="{CA200BCB-DFC6-4153-9BD4-785BC768B26B}"
|
||||||
RelativePathToProject="..\APETagDotNet\APETagDotNet.csproj"
|
RelativePathToProject="..\APETagDotNet\APETagDotNet.csproj"
|
||||||
/>
|
/>
|
||||||
|
<ProjectReference
|
||||||
|
ReferencedProjectIdentifier="{6458A13A-30EF-45A9-9D58-E5031B17BEE2}"
|
||||||
|
RelativePathToProject="..\AudioCodecsDotNet\AudioCodecsDotNet.csproj"
|
||||||
|
/>
|
||||||
</References>
|
</References>
|
||||||
<Files>
|
<Files>
|
||||||
<Filter
|
<Filter
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user