This commit is contained in:
chudov
2008-12-09 07:25:48 +00:00
parent b5180b8e61
commit e3f461e43c
16 changed files with 1870 additions and 580 deletions

View File

@@ -29,8 +29,8 @@ namespace ArCueDotNet
try
{
CUESheet cueSheet = new CUESheet(config);
cueSheet.Open(pathIn, false);
cueSheet.GenerateFilenames(OutputAudioFormat.NoAudio, pathIn);
cueSheet.Open(pathIn);
cueSheet.GenerateFilenames(OutputAudioFormat.NoAudio, false, pathIn);
cueSheet.AccurateRip = AccurateRipMode.Verify;
cueSheet.WriteAudioFiles(Path.GetDirectoryName(pathIn), CUEStyle.SingleFile);
cueSheet.GenerateAccurateRipLog(sw);

View File

@@ -125,6 +125,10 @@
<Project>{6458A13A-30EF-45A9-9D58-E5031B17BEE2}</Project>
<Name>CUETools.Codecs</Name>
</ProjectReference>
<ProjectReference Include="..\CUETools.Processor\CUETools.Processor.csproj">
<Project>{4911BD82-49EF-4858-8B51-5394F86739A4}</Project>
<Name>CUETools.Processor</Name>
</ProjectReference>
<ProjectReference Include="..\CUETools.Ripper.SCSI\CUETools.Ripper.SCSI.csproj">
<Project>{8CF07381-BEA2-4AFC-B3DD-9B2F21C65A3A}</Project>
<Name>CUETools.Ripper.SCSI</Name>

View File

@@ -136,34 +136,34 @@ namespace CUERipper
// comboLossless
//
this.comboLossless.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
resources.ApplyResources(this.comboLossless, "comboLossless");
this.comboLossless.FormattingEnabled = true;
this.comboLossless.Items.AddRange(new object[] {
resources.GetString("comboLossless.Items"),
resources.GetString("comboLossless.Items1"),
resources.GetString("comboLossless.Items2")});
resources.ApplyResources(this.comboLossless, "comboLossless");
this.comboLossless.Name = "comboLossless";
//
// comboCodec
//
this.comboCodec.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
resources.ApplyResources(this.comboCodec, "comboCodec");
this.comboCodec.FormattingEnabled = true;
this.comboCodec.Items.AddRange(new object[] {
resources.GetString("comboCodec.Items"),
resources.GetString("comboCodec.Items1"),
resources.GetString("comboCodec.Items2"),
resources.GetString("comboCodec.Items3")});
resources.ApplyResources(this.comboCodec, "comboCodec");
this.comboCodec.Name = "comboCodec";
//
// comboImage
//
this.comboImage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
resources.ApplyResources(this.comboImage, "comboImage");
this.comboImage.FormattingEnabled = true;
this.comboImage.Items.AddRange(new object[] {
resources.GetString("comboImage.Items"),
resources.GetString("comboImage.Items1")});
resources.ApplyResources(this.comboImage, "comboImage");
this.comboImage.Name = "comboImage";
//
// buttonAbort

View File

@@ -7,21 +7,29 @@ using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CUETools.Ripper.SCSI;
using CUETools.AccurateRip;
using CUETools.CDImage;
using CUETools.Codecs;
using CUETools.Processor;
using CUETools.Ripper.SCSI;
using MusicBrainz;
namespace CUERipper
{
public partial class frmCUERipper : Form
{
private CDDriveReader _reader = null;
private Thread _workThread = null;
private CDDriveReader _reader = null;
private StartStop _startStop;
private CUEConfig _config;
private OutputAudioFormat _format;
private CUEStyle _style;
private CUESheet _cueSheet;
public frmCUERipper()
{
InitializeComponent();
_config = new CUEConfig();
_startStop = new StartStop();
}
@@ -44,9 +52,12 @@ namespace CUERipper
private void SetupControls ()
{
bool running = _workThread != null;
listTracks.Enabled = !running;
comboDrives.Enabled = !running;
comboRelease.Enabled = !running;
listTracks.Enabled =
comboDrives.Enabled =
comboRelease.Enabled =
comboCodec.Enabled =
comboImage.Enabled =
comboLossless.Enabled = !running;
buttonPause.Visible = buttonPause.Enabled = buttonAbort.Visible = buttonAbort.Enabled = running;
buttonGo.Visible = buttonGo.Enabled = !running;
toolStripStatusLabel1.Text = String.Empty;
@@ -95,26 +106,57 @@ namespace CUERipper
CDDriveReader audioSource = (CDDriveReader)o;
audioSource.ReadProgress += new EventHandler<ReadProgressArgs>(CDReadProgress);
int[,] buff = new int[audioSource.BestBlockSize, audioSource.ChannelCount];
AccurateRipVerify arVerify = new AccurateRipVerify(audioSource.TOC);
string ArId = AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC);
arVerify.ContactAccurateRip(ArId);
IAudioDest audioDest = null;
try
{
audioSource.Position = 0;
do
if (_style == CUEStyle.SingleFile || _style == CUEStyle.SingleFileWithCUE)
audioDest = AudioReadWrite.GetAudioDest(_cueSheet.SingleFilename, (long)audioSource.Length, _config);
for (int iTrack = 0; iTrack <= audioSource.TOC.AudioTracks; iTrack++)
{
uint toRead = Math.Min((uint)buff.GetLength(0), (uint)audioSource.Remaining);
uint samplesRemTrack = (iTrack > 0 ? audioSource.TOC[iTrack].Length : audioSource.TOC.Pregap) * 588;
if (_style == CUEStyle.GapsAppended)
{
if (audioDest != null)
audioDest.Close();
audioDest = AudioReadWrite.GetAudioDest(iTrack > 0 ? _cueSheet.TrackFilenames[iTrack - 1] : _cueSheet.HTOAFilename, (long)samplesRemTrack, _config);
}
while (samplesRemTrack > 0)
{
uint toRead = Math.Min((uint)buff.GetLength(0), (uint)samplesRemTrack);
uint samplesRead = audioSource.Read(buff, toRead);
if (samplesRead == 0) break;
if (samplesRead != toRead)
throw new Exception("samples read != samples requested");
//arVerify.Write(buff, samplesRead);
//audioDest.Write(buff, samplesRead);
} while (true);
arVerify.Write(buff, samplesRead);
audioDest.Write(buff, samplesRead);
samplesRemTrack -= samplesRead;
}
}
if (audioDest != null)
audioDest.Close();
audioDest = null;
}
catch (StopException)
{
if (audioDest != null)
try { audioDest.Close(); }
catch { };
audioDest = null;
}
catch (Exception ex)
{
if (audioDest != null)
try { audioDest.Close(); }
catch { };
audioDest = null;
this.Invoke((MethodInvoker)delegate()
{
string message = "Exception";
@@ -134,6 +176,18 @@ namespace CUERipper
{
if (_reader == null)
return;
_config.lossyWAVHybrid = comboLossless.SelectedIndex == 1; // _cueSheet.Config?
_config.singleFilenameFormat = "%D - %C.cue";
_format = (string)comboCodec.SelectedItem == "wav" ? OutputAudioFormat.WAV :
(string)comboCodec.SelectedItem == "flac" ? OutputAudioFormat.FLAC :
(string)comboCodec.SelectedItem == "wv" ? OutputAudioFormat.WavPack :
(string)comboCodec.SelectedItem == "ape" ? OutputAudioFormat.APE :
OutputAudioFormat.NoAudio;
_style = comboImage.SelectedIndex == 0 ? CUEStyle.SingleFileWithCUE :
CUEStyle.GapsAppended;
_cueSheet.GenerateFilenames(_format, comboLossless.SelectedIndex != 0, ".");
_workThread = new Thread(Rip);
_workThread.Priority = ThreadPriority.BelowNormal;
_workThread.IsBackground = true;
@@ -174,26 +228,22 @@ namespace CUERipper
{
if (e.ListItem is string)
return;
ReadOnlyCollection<Event> events = ((Release)e.ListItem).GetEvents();
string year = events.Count > 0 ? events[0].Date.Substring(0, 4) + ": " : "";
e.Value = string.Format("{0}{1} - {2}", year, ((Release)e.ListItem).GetArtist(), ((Release)e.ListItem).GetTitle());
CUELine date = General.FindCUELine(((CUESheet)e.ListItem).Attributes, "REM", "DATE");
e.Value = string.Format("{0}{1} - {2}", date != null ? date.Params[2] + ": " : "", ((CUESheet)e.ListItem).Artist, ((CUESheet)e.ListItem).Title);
}
private void comboRelease_SelectedIndexChanged(object sender, EventArgs e)
{
listTracks.Items.Clear();
if (comboRelease.SelectedItem == null || comboRelease.SelectedItem is string)
{
for (int i = 1; i <= _reader.TOC.AudioTracks; i++)
listTracks.Items.Add(new ListViewItem(new string[] { "Track " + _reader.TOC[i].Number.ToString(), _reader.TOC[i].Number.ToString(), _reader.TOC[i].StartMSF, _reader.TOC[i].LengthMSF }));
return;
}
Release release = (Release) comboRelease.SelectedItem;
_cueSheet = (CUESheet)comboRelease.SelectedItem;
for (int i = 1; i <= _reader.TOC.AudioTracks; i++)
{
Track track = release.GetTracks()[(int)_reader.TOC[i].Number - 1];
listTracks.Items.Add(new ListViewItem(new string[] { track.GetTitle(), _reader.TOC[i].Number.ToString(), _reader.TOC[i].StartMSF, _reader.TOC[i].LengthMSF }));
}
listTracks.Items.Add(new ListViewItem(new string[] {
_cueSheet.Tracks[i-1].Title,
_reader.TOC[i].Number.ToString(),
_reader.TOC[i].StartMSF,
_reader.TOC[i].LengthMSF }));
}
private void MusicBrainz_LookupProgress(object sender, XmlRequestEventArgs e)
@@ -230,23 +280,41 @@ namespace CUERipper
CDDriveReader audioSource = (CDDriveReader)o;
ReleaseQueryParameters p = new ReleaseQueryParameters();
p.DiscId = _reader.TOC.MusicBrainzId;
p.DiscId = audioSource.TOC.MusicBrainzId;
Query<Release> results = Release.Query(p);
MusicBrainzService.XmlRequest += new EventHandler<XmlRequestEventArgs>(MusicBrainz_LookupProgress);
foreach (Release release in results)
{
release.GetEvents();
release.GetTracks();
this.BeginInvoke((MethodInvoker)delegate()
{
comboRelease.Items.Add(release);
CUESheet cueSheet = new CUESheet(_config);
cueSheet.OpenTOC(audioSource.TOC);
cueSheet.Artist = release.GetArtist();
cueSheet.Title = release.GetTitle();
if (release.GetEvents().Count > 0)
General.SetCUELine(cueSheet.Attributes, "REM", "DATE", release.GetEvents()[0].Date.Substring(0, 4), false);
for (int i = 1; i <= audioSource.TOC.AudioTracks; i++)
{
Track track = release.GetTracks()[(int)audioSource.TOC[i].Number - 1];
cueSheet.Tracks[i - 1].Title = track.GetTitle();
cueSheet.Tracks[i - 1].Artist = track.GetArtist();
}
comboRelease.Items.Add(cueSheet);
});
}
MusicBrainzService.XmlRequest -= new EventHandler<XmlRequestEventArgs>(MusicBrainz_LookupProgress);
this.BeginInvoke((MethodInvoker)delegate()
{
if (comboRelease.Items.Count == 0)
comboRelease.Items.Add("MusicBrainz: not found");
{
CUESheet cueSheet = new CUESheet(_config);
cueSheet.OpenTOC(audioSource.TOC);
comboRelease.Items.Add(cueSheet);
// cueSheet.Tracks[i - 1].Title = "Track " + _reader.TOC[i].Number.ToString();
}
});
_workThread = null;
this.BeginInvoke((MethodInvoker)delegate()

View File

@@ -270,9 +270,6 @@
<data name="&gt;&gt;buttonGo.ZOrder" xml:space="preserve">
<value>6</value>
</data>
<data name="comboLossless.Enabled" type="System.Boolean, mscorlib">
<value>False</value>
</data>
<data name="comboLossless.Items" xml:space="preserve">
<value>lossless</value>
</data>
@@ -303,14 +300,11 @@
<data name="&gt;&gt;comboLossless.ZOrder" xml:space="preserve">
<value>5</value>
</data>
<data name="comboCodec.Enabled" type="System.Boolean, mscorlib">
<value>False</value>
</data>
<data name="comboCodec.Items" xml:space="preserve">
<value>flac</value>
</data>
<data name="comboCodec.Items1" xml:space="preserve">
<value>WavPack</value>
<value>wv</value>
</data>
<data name="comboCodec.Items2" xml:space="preserve">
<value>wav</value>
@@ -339,9 +333,6 @@
<data name="&gt;&gt;comboCodec.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<data name="comboImage.Enabled" type="System.Boolean, mscorlib">
<value>False</value>
</data>
<data name="comboImage.Items" xml:space="preserve">
<value>image</value>
</data>

View File

@@ -0,0 +1,558 @@
// This is the main DLL file.
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace System::Collections::Specialized;
using namespace System::Runtime::InteropServices;
using namespace System::IO;
using namespace APETagsDotNet;
using namespace CUETools::Codecs;
#ifndef _WAVEFORMATEX_
#define _WAVEFORMATEX_
#define BOOL int
#define TRUE 1
#define FALSE 0
#define HWND long
/*
* extended waveform format structure used for all non-PCM formats. this
* structure is common to all non-PCM formats.
*/
typedef struct tWAVEFORMATEX
{
Int16 wFormatTag; /* format type */
Int16 nChannels; /* number of channels (i.e. mono, stereo...) */
Int32 nSamplesPerSec; /* sample rate */
Int32 nAvgBytesPerSec; /* for buffer estimation */
Int16 nBlockAlign; /* block size of data */
Int16 wBitsPerSample; /* number of bits per sample of mono data */
Int16 cbSize; /* the count in bytes of the size of */
/* extra information (after cbSize) */
} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
#endif /* _WAVEFORMATEX_ */
#include "All.h"
#include "MACLib.h"
#include "IO.h"
namespace CUETools { namespace Codecs { namespace APE {
class CWinFileIO : public CIO
{
public:
// construction / destruction
CWinFileIO(GCHandle gchIO, GCHandle gchBuffer)
{
_gchIO = gchIO;
_gchBuffer = gchBuffer;
}
~CWinFileIO()
{
}
// open / close
int Open(const wchar_t * pName)
{
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();
int GetSize();
int GetName(wchar_t * pBuffer)
{
throw gcnew Exception("CIO::GetName unsupported.");
}
private:
GCHandle _gchIO;
GCHandle _gchBuffer;
};
public ref class APEReader : public IAudioSource
{
public:
APEReader(String^ path, Stream^ IO)
{
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.");
}
_sampleRate = pAPEDecompress->GetInfo (APE_INFO_SAMPLE_RATE, 0, 0);
_bitsPerSample = pAPEDecompress->GetInfo (APE_INFO_BITS_PER_SAMPLE, 0, 0);
_channelCount = pAPEDecompress->GetInfo (APE_INFO_CHANNELS, 0, 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); // * ?
}
~APEReader ()
{
if (_winFileIO)
delete _winFileIO;
if (_gchIO.IsAllocated)
_gchIO.Free();
if (_gchReadBuffer.IsAllocated)
_gchReadBuffer.Free();
}
virtual property Int32 BitsPerSample {
Int32 get() {
return _bitsPerSample;
}
}
virtual property Int32 ChannelCount {
Int32 get() {
return _channelCount;
}
}
virtual property Int32 SampleRate {
Int32 get() {
return _sampleRate;
}
}
virtual property UInt64 Length {
UInt64 get() {
return _sampleCount;
}
}
virtual property UInt64 Position
{
UInt64 get() {
return _sampleOffset - SamplesInBuffer;
}
void set(UInt64 offset) {
_sampleOffset = offset;
_bufferOffset = 0;
_bufferLength = 0;
if (pAPEDecompress->Seek ((int) offset /*? */))
throw gcnew Exception("Unable to seek.");
}
}
virtual property UInt64 Remaining {
UInt64 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 property NameValueCollection^ Tags {
NameValueCollection^ get ()
{
if (!_tags)
{
APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true);
_tags = apeTag->GetStringTags (true);
apeTag->Close ();
}
return _tags;
}
void set (NameValueCollection ^tags)
{
_tags = tags;
}
}
virtual bool UpdateTags(bool preserveTime)
{
Close ();
APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, false);
apeTag->SetStringTags (_tags, true);
apeTag->Save();
apeTag->Close();
return true;
}
virtual UInt32 Read([Out] array<Int32, 2>^ buff, UInt32 sampleCount)
{
UInt32 buffOffset = 0;
UInt32 samplesNeeded = sampleCount;
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;
}
UInt32 copyCount = Math::Min(samplesNeeded, SamplesInBuffer);
AudioSamples::BytesToFLACSamples_16(_samplesBuffer, _bufferOffset*nBlockAlign, buff, buffOffset, copyCount, _channelCount);
samplesNeeded -= copyCount;
buffOffset += copyCount;
_bufferOffset += copyCount;
}
return sampleCount;
}
private:
IAPEDecompress * pAPEDecompress;
NameValueCollection^ _tags;
Int64 _sampleCount, _sampleOffset;
Int32 _bitsPerSample, _channelCount, _sampleRate;
UInt32 _bufferOffset, _bufferLength;
int nBlockAlign;
array<unsigned char>^ _samplesBuffer;
String^ _path;
Stream^ _IO;
array<unsigned char>^ _readBuffer;
CWinFileIO* _winFileIO;
GCHandle _gchIO, _gchReadBuffer;
property UInt32 SamplesInBuffer
{
UInt32 get ()
{
return (UInt32) (_bufferLength - _bufferOffset);
}
}
};
public ref class APEWriter : IAudioDest
{
public:
APEWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate)
{
if (channelCount != 1 && channelCount != 2)
throw gcnew Exception("Only stereo and mono audio formats are allowed.");
if (bitsPerSample != 16 && bitsPerSample != 24)
throw gcnew Exception("Monkey's Audio doesn't support selected bits per sample value.");
_path = path;
_tags = gcnew NameValueCollection();
_winFileIO = NULL;
_compressionLevel = COMPRESSION_LEVEL_NORMAL;
_bitsPerSample = bitsPerSample;
_channelCount = channelCount;
_sampleRate = sampleRate;
_blockAlign = _channelCount * ((_bitsPerSample + 7) / 8);
int nRetVal;
pAPECompress = CreateIAPECompress (&nRetVal);
if (!pAPECompress)
throw gcnew Exception("Unable to open APE compressor.");
}
~APEWriter()
{
if (_winFileIO)
delete _winFileIO;
if (_gchIO.IsAllocated)
_gchIO.Free();
if (_gchBuffer.IsAllocated)
_gchBuffer.Free();
}
virtual void Close()
{
if (pAPECompress)
{
pAPECompress->Finish (NULL, 0, 0);
delete pAPECompress;
pAPECompress = NULL;
}
if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) {
throw gcnew Exception("Samples written differs from the expected sample count.");
}
if (_tags->Count > 0)
{
APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true);
apeTag->SetStringTags (_tags, true);
apeTag->Save();
apeTag->Close();
_tags->Clear ();
}
if (_IO != nullptr)
{
_IO->Close ();
_IO = nullptr;
}
}
virtual void Delete()
{
try { Close (); } catch (Exception^) {}
File::Delete(_path);
}
virtual property Int64 FinalSampleCount
{
Int64 get()
{
return _finalSampleCount;
}
void set(Int64 value)
{
if (value < 0)
throw gcnew Exception("Invalid final sample count.");
if (_initialized)
throw gcnew Exception("Final sample count cannot be changed after encoding begins.");
_finalSampleCount = value;
}
}
virtual property Int64 BlockSize
{
void set(Int64 value)
{
}
}
virtual property int BitsPerSample
{
int get() { return _bitsPerSample; }
}
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 {
Int32 get() {
return _compressionLevel;
}
void set(Int32 value) {
if ((value < 1) || (value > 5)) {
throw gcnew Exception("Invalid compression mode.");
}
_compressionLevel = value * 1000;
}
}
private:
IAPECompress * pAPECompress;
bool _initialized;
Int32 _finalSampleCount, _samplesWritten;
Int32 _bitsPerSample, _channelCount, _sampleRate, _blockAlign;
Int32 _compressionLevel;
NameValueCollection^ _tags;
String^ _path;
Stream^ _IO;
GCHandle _gchIO, _gchBuffer;
CWinFileIO* _winFileIO;
array<unsigned char>^ _writeBuffer;
array<unsigned char>^ _sampleBuffer;
void Initialize() {
_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, _sampleRate, _bitsPerSample, _channelCount);
int res = pAPECompress->StartEx (_winFileIO,
&waveFormat,
(_finalSampleCount == 0) ? MAX_AUDIO_BYTES_UNKNOWN : _finalSampleCount * _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;
}
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

@@ -10,7 +10,7 @@ using namespace System::Security::Permissions;
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly:AssemblyTitleAttribute("FLACDotNet")];
[assembly:AssemblyTitleAttribute("CUETools.Codecs.FLAC")];
[assembly:AssemblyDescriptionAttribute("")];
[assembly:AssemblyConfigurationAttribute("")];
[assembly:AssemblyCompanyAttribute("")];

View File

@@ -85,8 +85,10 @@ namespace CUETools.Codecs.LossyWAV
process_this_codec_block();
}
}
if (_lwcdfDest != null)
try { _lwcdfDest.Close(); }
catch { }
if (_audioDest != null) _audioDest.Close();
if (_lwcdfDest != null) _lwcdfDest.Close();
}
public void Write(int[,] buff, uint sampleCount)

View File

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

View File

@@ -1,10 +1,10 @@
using System;
using System.IO;
using FLACDotNet;
using WavPackDotNet;
using APEDotNet;
using CUETools.Codecs;
using CUETools.Codecs.ALAC;
using CUETools.Codecs.FLAC;
using CUETools.Codecs.WavPack;
using CUETools.Codecs.APE;
using CUETools.Codecs.LossyWAV;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -95,7 +95,7 @@ namespace CUETools.Processor
int destBitsPerSample = (config.detectHDCD && config.decodeHDCD) ? ((!config.decodeHDCDtoLW16 && config.decodeHDCDto24bit) ? 24 : 20) : 16;
int lossyBitsPerSample = (config.detectHDCD && config.decodeHDCD && !config.decodeHDCDtoLW16) ? 24 : 16;
IAudioDest lossyDest = GetAudioDest(path, lossyBitsPerSample, 2, 44100, finalSampleCount, extension, config);
IAudioDest lwcdfDest = GetAudioDest(lwcdfPath, destBitsPerSample, 2, 44100, finalSampleCount, extension, config);
IAudioDest lwcdfDest = config.lossyWAVHybrid ? GetAudioDest(lwcdfPath, destBitsPerSample, 2, 44100, finalSampleCount, extension, config) : null;
return new LossyWAVWriter(lossyDest, lwcdfDest, destBitsPerSample, 2, 44100, config.lossyWAVQuality);
}
}

View File

@@ -84,7 +84,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AudioReadWrite.cs" />
<Compile Include="Main.cs" />
<Compile Include="Processor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
</ItemGroup>

View File

@@ -806,6 +806,8 @@ namespace CUETools.Ripper.SCSI
}
set
{
_currentTrack = -1;
_currentIndex = -1;
_sampleOffset = (int) value + _driveOffset;
}
}

View File

@@ -133,7 +133,7 @@ namespace JDP
cueName = Path.GetFileNameWithoutExtension(pathIn) + ".cue";
bool outputAudio = _accurateRip != AccurateRipMode.Verify;
cueSheet.Open(pathIn, _lossyWAV);
cueSheet.Open(pathIn);
if (outputAudio)
{
bool pathFound = false;
@@ -153,7 +153,7 @@ namespace JDP
}
else
pathOut = Path.Combine(Path.GetDirectoryName(pathIn) ?? pathIn, cueName);
cueSheet.GenerateFilenames(_audioFormat, pathOut);
cueSheet.GenerateFilenames(_audioFormat, _lossyWAV, pathOut);
if (outputAudio)
{
if (_cueStyle == CUEStyle.SingleFileWithCUE)

View File

@@ -304,7 +304,7 @@ namespace JDP {
bool outputCUE = cueStyle != CUEStyle.SingleFileWithCUE && accurateRip != AccurateRipMode.Verify;
string pathOut = null;
cueSheet.Open(pathIn, lossyWAV);
cueSheet.Open(pathIn);
this.Invoke((MethodInvoker)delegate()
{
@@ -312,7 +312,7 @@ namespace JDP {
pathOut = txtOutputPath.Text;
});
cueSheet.GenerateFilenames(outputFormat, pathOut);
cueSheet.GenerateFilenames(outputFormat, lossyWAV, pathOut);
string outDir = Path.GetDirectoryName(pathOut);
if (cueStyle == CUEStyle.SingleFileWithCUE)
cueSheet.SingleFilename = Path.GetFileName(pathOut);