more work on ripper

This commit is contained in:
chudov
2008-12-10 06:48:38 +00:00
parent e3f461e43c
commit 905414db84
11 changed files with 732 additions and 441 deletions

View File

@@ -76,6 +76,7 @@ namespace Bwg.Scsi
SetCdSpeed = 0xBB, SetCdSpeed = 0xBB,
MechanismStatus = 0xBD, MechanismStatus = 0xBD,
ReadCd = 0xBE, ReadCd = 0xBE,
SendDvdStructure = 0xBF SendDvdStructure = 0xBF,
ReadCDDA = 0xD8
} ; } ;
} }

View File

@@ -2161,7 +2161,7 @@ namespace Bwg.Scsi
/// <param name="start"></param> /// <param name="start"></param>
/// <param name="length"></param> /// <param name="length"></param>
/// <param name="data">the memory area </param> /// <param name="data">the memory area </param>
/// <param name="size">the size of the memory area given by the data parameter</param> /// <param name="timeout">timeout (in seconds)</param>
/// <returns></returns> /// <returns></returns>
public CommandStatus ReadCDAndSubChannel(MainChannelSelection mainmode, SubChannelMode submode, C2ErrorMode c2mode, byte exp, bool dap, uint start, uint length, IntPtr data, int timeout) public CommandStatus ReadCDAndSubChannel(MainChannelSelection mainmode, SubChannelMode submode, C2ErrorMode c2mode, byte exp, bool dap, uint start, uint length, IntPtr data, int timeout)
{ {
@@ -2204,6 +2204,41 @@ namespace Bwg.Scsi
return CommandStatus.Success; return CommandStatus.Success;
} }
/// <summary>
///
/// </summary>
/// <param name="submode">subchannel mode</param>
/// <param name="start"></param>
/// <param name="length"></param>
/// <param name="data">the memory area </param>
/// <param name="timeout">timeout (in seconds)</param>
/// <returns></returns>
public CommandStatus ReadCDDA(SubChannelMode submode, uint start, uint length, IntPtr data, int timeout)
{
if (m_logger != null)
{
string args = start.ToString() + ", " + length.ToString() + ", data";
m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadCDDA(" + args + ")"));
}
byte mode = (byte)(submode == SubChannelMode.QOnly ? 1 : submode == SubChannelMode.RWMode ? 2 : 0);
int size = 4 * 588 + (submode == SubChannelMode.QOnly ? 16 : submode == SubChannelMode.RWMode ? 96 : 0);
using (Command cmd = new Command(ScsiCommandCode.ReadCDDA, 12, data, size, Command.CmdDirection.In, timeout))
{
cmd.SetCDB8(1, 0 << 5); // lun
cmd.SetCDB32(2, start);
cmd.SetCDB24(7, length);
cmd.SetCDB8(10, mode); // Subchannel
CommandStatus st = SendCommand(cmd);
if (st != CommandStatus.Success)
return st;
}
return CommandStatus.Success;
}
/// <summary> /// <summary>
/// Read CD header data from the disk /// Read CD header data from the disk
/// </summary> /// </summary>

View File

@@ -86,12 +86,22 @@
<Compile Include="frmCUERipper.Designer.cs"> <Compile Include="frmCUERipper.Designer.cs">
<DependentUpon>frmCUERipper.cs</DependentUpon> <DependentUpon>frmCUERipper.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="frmRelease.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="frmRelease.Designer.cs">
<DependentUpon>frmRelease.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="frmCUERipper.resx"> <EmbeddedResource Include="frmCUERipper.resx">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<DependentUpon>frmCUERipper.cs</DependentUpon> <DependentUpon>frmCUERipper.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="frmRelease.resx">
<SubType>Designer</SubType>
<DependentUpon>frmRelease.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>

View File

@@ -48,8 +48,11 @@ namespace CUERipper
this.buttonPause = new System.Windows.Forms.Button(); this.buttonPause = new System.Windows.Forms.Button();
this.comboRelease = new System.Windows.Forms.ComboBox(); this.comboRelease = new System.Windows.Forms.ComboBox();
this.releaseBindingSource = new System.Windows.Forms.BindingSource(this.components); this.releaseBindingSource = new System.Windows.Forms.BindingSource(this.components);
this.contextMenuStripRelease = new System.Windows.Forms.ContextMenuStrip(this.components);
this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).BeginInit();
this.contextMenuStripRelease.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// comboDrives // comboDrives
@@ -106,6 +109,7 @@ namespace CUERipper
this.listTracks.Name = "listTracks"; this.listTracks.Name = "listTracks";
this.listTracks.UseCompatibleStateImageBehavior = false; this.listTracks.UseCompatibleStateImageBehavior = false;
this.listTracks.View = System.Windows.Forms.View.Details; this.listTracks.View = System.Windows.Forms.View.Details;
this.listTracks.AfterLabelEdit += new System.Windows.Forms.LabelEditEventHandler(this.listTracks_AfterLabelEdit);
this.listTracks.DoubleClick += new System.EventHandler(this.listTracks_DoubleClick); this.listTracks.DoubleClick += new System.EventHandler(this.listTracks_DoubleClick);
this.listTracks.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.listTracks_PreviewKeyDown); this.listTracks.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.listTracks_PreviewKeyDown);
this.listTracks.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listTracks_KeyDown); this.listTracks.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listTracks_KeyDown);
@@ -183,6 +187,7 @@ namespace CUERipper
// comboRelease // comboRelease
// //
resources.ApplyResources(this.comboRelease, "comboRelease"); resources.ApplyResources(this.comboRelease, "comboRelease");
this.comboRelease.ContextMenuStrip = this.contextMenuStripRelease;
this.comboRelease.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboRelease.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboRelease.FormattingEnabled = true; this.comboRelease.FormattingEnabled = true;
this.comboRelease.Name = "comboRelease"; this.comboRelease.Name = "comboRelease";
@@ -193,6 +198,19 @@ namespace CUERipper
// //
this.releaseBindingSource.DataSource = typeof(MusicBrainz.Release); this.releaseBindingSource.DataSource = typeof(MusicBrainz.Release);
// //
// contextMenuStripRelease
//
this.contextMenuStripRelease.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.editToolStripMenuItem});
this.contextMenuStripRelease.Name = "contextMenuStripRelease";
resources.ApplyResources(this.contextMenuStripRelease, "contextMenuStripRelease");
//
// editToolStripMenuItem
//
this.editToolStripMenuItem.Name = "editToolStripMenuItem";
resources.ApplyResources(this.editToolStripMenuItem, "editToolStripMenuItem");
this.editToolStripMenuItem.Click += new System.EventHandler(this.editToolStripMenuItem_Click);
//
// frmCUERipper // frmCUERipper
// //
resources.ApplyResources(this, "$this"); resources.ApplyResources(this, "$this");
@@ -215,6 +233,7 @@ namespace CUERipper
this.statusStrip1.ResumeLayout(false); this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout(); this.statusStrip1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).EndInit();
this.contextMenuStripRelease.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -240,6 +259,8 @@ namespace CUERipper
private System.Windows.Forms.Button buttonPause; private System.Windows.Forms.Button buttonPause;
private System.Windows.Forms.ComboBox comboRelease; private System.Windows.Forms.ComboBox comboRelease;
private System.Windows.Forms.BindingSource releaseBindingSource; private System.Windows.Forms.BindingSource releaseBindingSource;
private System.Windows.Forms.ContextMenuStrip contextMenuStripRelease;
private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem;
} }
} }

View File

@@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Data; using System.Data;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
@@ -25,6 +26,7 @@ namespace CUERipper
private OutputAudioFormat _format; private OutputAudioFormat _format;
private CUEStyle _style; private CUEStyle _style;
private CUESheet _cueSheet; private CUESheet _cueSheet;
private string _pathOut;
public frmCUERipper() public frmCUERipper()
{ {
@@ -39,7 +41,13 @@ namespace CUERipper
{ {
CDDriveReader reader = new CDDriveReader(); CDDriveReader reader = new CDDriveReader();
if (reader.Open(drive)) if (reader.Open(drive))
{
int driveOffset;
if (!AccurateRipVerify.FindDriveReadOffset(reader.ARName, out driveOffset))
; //throw new Exception("Failed to find drive read offset for drive" + _ripper.ARName);
reader.DriveOffset = driveOffset;
comboDrives.Items.Add(reader); comboDrives.Items.Add(reader);
}
} }
if (comboDrives.Items.Count == 0) if (comboDrives.Items.Count == 0)
comboDrives.Items.Add("No CD drives found"); comboDrives.Items.Add("No CD drives found");
@@ -105,58 +113,18 @@ namespace CUERipper
{ {
CDDriveReader audioSource = (CDDriveReader)o; CDDriveReader audioSource = (CDDriveReader)o;
audioSource.ReadProgress += new EventHandler<ReadProgressArgs>(CDReadProgress); 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;
CUESheet.WriteText(_pathOut, _cueSheet.CUESheetContents(_style));
CUESheet.WriteText(Path.ChangeExtension(_pathOut, ".log"), _cueSheet.LOGContents());
try try
{ {
audioSource.Position = 0; _cueSheet.WriteAudioFiles(".", _style);
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 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 != toRead)
throw new Exception("samples read != samples requested");
arVerify.Write(buff, samplesRead);
audioDest.Write(buff, samplesRead);
samplesRemTrack -= samplesRead;
}
}
if (audioDest != null)
audioDest.Close();
audioDest = null;
} }
catch (StopException) catch (StopException)
{ {
if (audioDest != null)
try { audioDest.Close(); }
catch { };
audioDest = null;
} }
catch (Exception ex) catch (Exception ex)
{ {
if (audioDest != null)
try { audioDest.Close(); }
catch { };
audioDest = null;
this.Invoke((MethodInvoker)delegate() this.Invoke((MethodInvoker)delegate()
{ {
string message = "Exception"; string message = "Exception";
@@ -165,6 +133,7 @@ namespace CUERipper
DialogResult dlgRes = MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); DialogResult dlgRes = MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}); });
} }
audioSource.ReadProgress -= new EventHandler<ReadProgressArgs>(CDReadProgress);
_workThread = null; _workThread = null;
this.BeginInvoke((MethodInvoker)delegate() this.BeginInvoke((MethodInvoker)delegate()
{ {
@@ -176,17 +145,20 @@ namespace CUERipper
{ {
if (_reader == null) if (_reader == null)
return; return;
_style = comboImage.SelectedIndex == 0 ? CUEStyle.SingleFileWithCUE :
CUEStyle.GapsAppended;
_pathOut = _config.CleanseString(_cueSheet.Artist) + " - " +
_config.CleanseString(_cueSheet.Title) + ".cue";
_config.lossyWAVHybrid = comboLossless.SelectedIndex == 1; // _cueSheet.Config? _config.lossyWAVHybrid = comboLossless.SelectedIndex == 1; // _cueSheet.Config?
_config.singleFilenameFormat = "%D - %C.cue"; if (_style == CUEStyle.SingleFileWithCUE)
_cueSheet.SingleFilename = Path.GetFileName(_pathOut);
_format = (string)comboCodec.SelectedItem == "wav" ? OutputAudioFormat.WAV : _format = (string)comboCodec.SelectedItem == "wav" ? OutputAudioFormat.WAV :
(string)comboCodec.SelectedItem == "flac" ? OutputAudioFormat.FLAC : (string)comboCodec.SelectedItem == "flac" ? OutputAudioFormat.FLAC :
(string)comboCodec.SelectedItem == "wv" ? OutputAudioFormat.WavPack : (string)comboCodec.SelectedItem == "wv" ? OutputAudioFormat.WavPack :
(string)comboCodec.SelectedItem == "ape" ? OutputAudioFormat.APE : (string)comboCodec.SelectedItem == "ape" ? OutputAudioFormat.APE :
OutputAudioFormat.NoAudio; OutputAudioFormat.NoAudio;
_style = comboImage.SelectedIndex == 0 ? CUEStyle.SingleFileWithCUE : _cueSheet.GenerateFilenames(_format, comboLossless.SelectedIndex != 0, _pathOut);
CUEStyle.GapsAppended;
_cueSheet.GenerateFilenames(_format, comboLossless.SelectedIndex != 0, ".");
_workThread = new Thread(Rip); _workThread = new Thread(Rip);
_workThread.Priority = ThreadPriority.BelowNormal; _workThread.Priority = ThreadPriority.BelowNormal;
@@ -197,31 +169,12 @@ namespace CUERipper
private void buttonAbort_Click(object sender, EventArgs e) private void buttonAbort_Click(object sender, EventArgs e)
{ {
lock (_startStop) _startStop.Stop();
{
if (_startStop._pause)
{
_startStop._pause = false;
Monitor.Pulse(_startStop);
}
_startStop._stop = true;
}
} }
private void buttonPause_Click(object sender, EventArgs e) private void buttonPause_Click(object sender, EventArgs e)
{ {
lock (_startStop) _startStop.Pause();
{
if (_startStop._pause)
{
_startStop._pause = false;
Monitor.Pulse(_startStop);
}
else
{
_startStop._pause = true;
}
}
} }
private void comboRelease_Format(object sender, ListControlConvertEventArgs e) private void comboRelease_Format(object sender, ListControlConvertEventArgs e)
@@ -283,27 +236,25 @@ namespace CUERipper
p.DiscId = audioSource.TOC.MusicBrainzId; p.DiscId = audioSource.TOC.MusicBrainzId;
Query<Release> results = Release.Query(p); Query<Release> results = Release.Query(p);
MusicBrainzService.XmlRequest += new EventHandler<XmlRequestEventArgs>(MusicBrainz_LookupProgress); MusicBrainzService.XmlRequest += new EventHandler<XmlRequestEventArgs>(MusicBrainz_LookupProgress);
foreach (Release release in results) try
{ {
release.GetEvents(); foreach (Release release in results)
release.GetTracks();
this.BeginInvoke((MethodInvoker)delegate()
{ {
release.GetEvents();
release.GetTracks();
CUESheet cueSheet = new CUESheet(_config); CUESheet cueSheet = new CUESheet(_config);
cueSheet.OpenTOC(audioSource.TOC); cueSheet.OpenCD(audioSource);
cueSheet.Artist = release.GetArtist(); cueSheet.FillFromMusicBrainz(release);
cueSheet.Title = release.GetTitle(); cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
if (release.GetEvents().Count > 0) cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
General.SetCUELine(cueSheet.Attributes, "REM", "DATE", release.GetEvents()[0].Date.Substring(0, 4), false); this.BeginInvoke((MethodInvoker)delegate()
for (int i = 1; i <= audioSource.TOC.AudioTracks; i++)
{ {
Track track = release.GetTracks()[(int)audioSource.TOC[i].Number - 1]; comboRelease.Items.Add(cueSheet);
cueSheet.Tracks[i - 1].Title = track.GetTitle(); });
cueSheet.Tracks[i - 1].Artist = track.GetArtist(); }
} }
comboRelease.Items.Add(cueSheet); catch (Exception)
}); {
} }
MusicBrainzService.XmlRequest -= new EventHandler<XmlRequestEventArgs>(MusicBrainz_LookupProgress); MusicBrainzService.XmlRequest -= new EventHandler<XmlRequestEventArgs>(MusicBrainz_LookupProgress);
this.BeginInvoke((MethodInvoker)delegate() this.BeginInvoke((MethodInvoker)delegate()
@@ -311,9 +262,16 @@ namespace CUERipper
if (comboRelease.Items.Count == 0) if (comboRelease.Items.Count == 0)
{ {
CUESheet cueSheet = new CUESheet(_config); CUESheet cueSheet = new CUESheet(_config);
cueSheet.OpenTOC(audioSource.TOC); cueSheet.OpenCD(audioSource);
General.SetCUELine(cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false);
General.SetCUELine(cueSheet.Attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
cueSheet.Artist = "Unknown Artist";
cueSheet.Title = "Unknown Title";
cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
cueSheet.Tracks[i].Title = string.Format("Track {0:00}", i + 1);
comboRelease.Items.Add(cueSheet); comboRelease.Items.Add(cueSheet);
// cueSheet.Tracks[i - 1].Title = "Track " + _reader.TOC[i].Number.ToString();
} }
}); });
_workThread = null; _workThread = null;
@@ -370,13 +328,20 @@ namespace CUERipper
} }
} }
} }
}
public class StopException : Exception private void listTracks_AfterLabelEdit(object sender, LabelEditEventArgs e)
{
public StopException()
: base()
{ {
CUESheet cueSheet = (CUESheet)comboRelease.SelectedItem;
cueSheet.Tracks[e.Item].Title = e.Label;
}
private void editToolStripMenuItem_Click(object sender, EventArgs e)
{
CUESheet cueSheet = (CUESheet)comboRelease.SelectedItem;
frmRelease frm = new frmRelease();
frm.CUE = cueSheet;
frm.ShowDialog();
comboRelease.Items[comboRelease.SelectedIndex] = cueSheet;
} }
} }
@@ -388,5 +353,34 @@ namespace CUERipper
_stop = false; _stop = false;
_pause = false; _pause = false;
} }
public void Stop()
{
lock (this)
{
if (_pause)
{
_pause = false;
Monitor.Pulse(this);
}
_stop = true;
}
}
public void Pause()
{
lock (this)
{
if (_pause)
{
_pause = false;
Monitor.Pulse(this);
}
else
{
_pause = true;
}
}
}
} }
} }

View File

@@ -142,29 +142,11 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;comboDrives.ZOrder" xml:space="preserve"> <data name="&gt;&gt;comboDrives.ZOrder" xml:space="preserve">
<value>9</value> <value>10</value>
</data> </data>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>0, 371</value> <value>0, 371</value>
</metadata> </metadata>
<data name="toolStripStatusLabel1.Size" type="System.Drawing.Size, System.Drawing">
<value>200, 17</value>
</data>
<data name="toolStripStatusLabel1.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
<value>MiddleLeft</value>
</data>
<data name="toolStripProgressBar1.Size" type="System.Drawing.Size, System.Drawing">
<value>140, 16</value>
</data>
<data name="toolStripProgressBar1.ToolTipText" xml:space="preserve">
<value>Track progress</value>
</data>
<data name="toolStripProgressBar2.Size" type="System.Drawing.Size, System.Drawing">
<value>140, 16</value>
</data>
<data name="toolStripProgressBar2.ToolTipText" xml:space="preserve">
<value>Disk progress</value>
</data>
<data name="statusStrip1.Location" type="System.Drawing.Point, System.Drawing"> <data name="statusStrip1.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 371</value> <value>0, 371</value>
</data> </data>
@@ -187,11 +169,50 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;statusStrip1.ZOrder" xml:space="preserve"> <data name="&gt;&gt;statusStrip1.ZOrder" xml:space="preserve">
<value>8</value> <value>9</value>
</data>
<data name="toolStripStatusLabel1.Size" type="System.Drawing.Size, System.Drawing">
<value>200, 17</value>
</data>
<data name="toolStripStatusLabel1.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
<value>MiddleLeft</value>
</data>
<data name="toolStripProgressBar1.Size" type="System.Drawing.Size, System.Drawing">
<value>140, 16</value>
</data>
<data name="toolStripProgressBar1.ToolTipText" xml:space="preserve">
<value>Track progress</value>
</data>
<data name="toolStripProgressBar2.Size" type="System.Drawing.Size, System.Drawing">
<value>140, 16</value>
</data>
<data name="toolStripProgressBar2.ToolTipText" xml:space="preserve">
<value>Disk progress</value>
</data> </data>
<data name="listTracks.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="listTracks.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value> <value>Top, Left, Right</value>
</data> </data>
<data name="listTracks.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 60</value>
</data>
<data name="listTracks.Size" type="System.Drawing.Size, System.Drawing">
<value>481, 269</value>
</data>
<data name="listTracks.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="&gt;&gt;listTracks.Name" xml:space="preserve">
<value>listTracks</value>
</data>
<data name="&gt;&gt;listTracks.Type" xml:space="preserve">
<value>System.Windows.Forms.ListView, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;listTracks.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;listTracks.ZOrder" xml:space="preserve">
<value>8</value>
</data>
<data name="Title.DisplayIndex" type="System.Int32, mscorlib"> <data name="Title.DisplayIndex" type="System.Int32, mscorlib">
<value>1</value> <value>1</value>
</data> </data>
@@ -222,27 +243,6 @@
<data name="Length.Width" type="System.Int32, mscorlib"> <data name="Length.Width" type="System.Int32, mscorlib">
<value>70</value> <value>70</value>
</data> </data>
<data name="listTracks.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 60</value>
</data>
<data name="listTracks.Size" type="System.Drawing.Size, System.Drawing">
<value>481, 269</value>
</data>
<data name="listTracks.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="&gt;&gt;listTracks.Name" xml:space="preserve">
<value>listTracks</value>
</data>
<data name="&gt;&gt;listTracks.Type" xml:space="preserve">
<value>System.Windows.Forms.ListView, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;listTracks.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;listTracks.ZOrder" xml:space="preserve">
<value>7</value>
</data>
<data name="buttonGo.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="buttonGo.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value> <value>Top, Left, Right</value>
</data> </data>
@@ -268,7 +268,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;buttonGo.ZOrder" xml:space="preserve"> <data name="&gt;&gt;buttonGo.ZOrder" xml:space="preserve">
<value>6</value> <value>7</value>
</data> </data>
<data name="comboLossless.Items" xml:space="preserve"> <data name="comboLossless.Items" xml:space="preserve">
<value>lossless</value> <value>lossless</value>
@@ -298,7 +298,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;comboLossless.ZOrder" xml:space="preserve"> <data name="&gt;&gt;comboLossless.ZOrder" xml:space="preserve">
<value>5</value> <value>6</value>
</data> </data>
<data name="comboCodec.Items" xml:space="preserve"> <data name="comboCodec.Items" xml:space="preserve">
<value>flac</value> <value>flac</value>
@@ -331,7 +331,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;comboCodec.ZOrder" xml:space="preserve"> <data name="&gt;&gt;comboCodec.ZOrder" xml:space="preserve">
<value>4</value> <value>5</value>
</data> </data>
<data name="comboImage.Items" xml:space="preserve"> <data name="comboImage.Items" xml:space="preserve">
<value>image</value> <value>image</value>
@@ -358,7 +358,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;comboImage.ZOrder" xml:space="preserve"> <data name="&gt;&gt;comboImage.ZOrder" xml:space="preserve">
<value>3</value> <value>4</value>
</data> </data>
<data name="buttonAbort.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="buttonAbort.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value> <value>Top, Left, Right</value>
@@ -391,7 +391,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;buttonAbort.ZOrder" xml:space="preserve"> <data name="&gt;&gt;buttonAbort.ZOrder" xml:space="preserve">
<value>2</value> <value>3</value>
</data> </data>
<data name="buttonPause.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="buttonPause.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value> <value>Top, Left, Right</value>
@@ -424,11 +424,29 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;buttonPause.ZOrder" xml:space="preserve"> <data name="&gt;&gt;buttonPause.ZOrder" xml:space="preserve">
<value>1</value> <value>2</value>
</data> </data>
<data name="comboRelease.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="comboRelease.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value> <value>Top, Left, Right</value>
</data> </data>
<metadata name="contextMenuStripRelease.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>285, 58</value>
</metadata>
<data name="editToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>152, 22</value>
</data>
<data name="editToolStripMenuItem.Text" xml:space="preserve">
<value>Edit</value>
</data>
<data name="contextMenuStripRelease.Size" type="System.Drawing.Size, System.Drawing">
<value>95, 26</value>
</data>
<data name="&gt;&gt;contextMenuStripRelease.Name" xml:space="preserve">
<value>contextMenuStripRelease</value>
</data>
<data name="&gt;&gt;contextMenuStripRelease.Type" xml:space="preserve">
<value>System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="comboRelease.Location" type="System.Drawing.Point, System.Drawing"> <data name="comboRelease.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 33</value> <value>6, 33</value>
</data> </data>
@@ -448,7 +466,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;comboRelease.ZOrder" xml:space="preserve"> <data name="&gt;&gt;comboRelease.ZOrder" xml:space="preserve">
<value>0</value> <value>1</value>
</data> </data>
<metadata name="releaseBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="releaseBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>116, 371</value> <value>116, 371</value>
@@ -516,6 +534,12 @@
<data name="&gt;&gt;releaseBindingSource.Type" xml:space="preserve"> <data name="&gt;&gt;releaseBindingSource.Type" xml:space="preserve">
<value>System.Windows.Forms.BindingSource, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Windows.Forms.BindingSource, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="&gt;&gt;editToolStripMenuItem.Name" xml:space="preserve">
<value>editToolStripMenuItem</value>
</data>
<data name="&gt;&gt;editToolStripMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve"> <data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>frmCUERipper</value> <value>frmCUERipper</value>
</data> </data>

View File

@@ -201,6 +201,18 @@ namespace CUETools.CDImage
} }
} }
public bool DCP
{
get
{
return _dcp;
}
set
{
_dcp = value;
}
}
public void AddIndex(CDTrackIndex index) public void AddIndex(CDTrackIndex index)
{ {
if (index.Index < 2) if (index.Index < 2)
@@ -212,7 +224,7 @@ namespace CUETools.CDImage
IList<CDTrackIndex> _indexes; IList<CDTrackIndex> _indexes;
string _isrc; string _isrc;
bool _isAudio; bool _isAudio;
bool _preEmphasis; bool _preEmphasis, _dcp;
uint _start; uint _start;
uint _length; uint _length;
uint _number; uint _number;

View File

@@ -439,9 +439,7 @@ namespace CUETools.Processor
private CUEConfig _config; private CUEConfig _config;
private string _cddbDiscIdTag; private string _cddbDiscIdTag;
private bool _isCD; private bool _isCD;
private string _driveName; private CDDriveReader _ripper;
private int _driveOffset;
private BitArray _cdErrors;
private bool _isArchive; private bool _isArchive;
private List<string> _archiveContents; private List<string> _archiveContents;
private string _archiveCUEpath; private string _archiveCUEpath;
@@ -481,17 +479,55 @@ namespace CUETools.Processor
_isCD = false; _isCD = false;
} }
public void OpenTOC(CDImageLayout toc) public void OpenCD(CDDriveReader ripper)
{ {
_toc = toc; _ripper = ripper;
_toc = (CDImageLayout)_ripper.TOC.Clone();
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++) for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
{ {
_trackFilenames.Add(string.Format("{0:00}.wav", iTrack + 1)); _trackFilenames.Add(string.Format("{0:00}.wav", iTrack + 1));
_tracks.Add(new TrackInfo()); _tracks.Add(new TrackInfo());
} }
_hasTrackFilenames = false;
_accurateRipId = _accurateRipIdActual = AccurateRipVerify.CalculateAccurateRipId(_toc); _accurateRipId = _accurateRipIdActual = AccurateRipVerify.CalculateAccurateRipId(_toc);
_arVerify = new AccurateRipVerify(_toc); _arVerify = new AccurateRipVerify(_toc);
_isCD = true;
SourceInfo cdInfo;
cdInfo.Path = _ripper.ARName;
cdInfo.Offset = 0;
cdInfo.Length = _toc.AudioLength * 588;
_sources.Add(cdInfo);
_ripper.ReadProgress += new EventHandler<ReadProgressArgs>(CDReadProgress);
}
public void Close()
{
if (_ripper != null)
_ripper.Close();
_ripper = null;
}
public AccurateRipVerify ArVerify
{
get
{
return _arVerify;
}
}
public void FillFromMusicBrainz(Release release)
{
General.SetCUELine(_attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(_toc), false);
General.SetCUELine(_attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
if (release.GetEvents().Count > 0)
General.SetCUELine(_attributes, "REM", "DATE", release.GetEvents()[0].Date.Substring(0, 4), false);
Artist = release.GetArtist();
Title = release.GetTitle();
for (int i = 1; i <= _toc.AudioTracks; i++)
{
Track track = release.GetTracks()[(int)_toc[i].Number - 1];
Tracks[i - 1].Title = track.GetTitle();
Tracks[i - 1].Artist = track.GetArtist();
}
} }
public void Open(string pathIn) public void Open(string pathIn)
@@ -502,27 +538,13 @@ namespace CUETools.Processor
{ {
CDDriveReader ripper = new CDDriveReader(); CDDriveReader ripper = new CDDriveReader();
ripper.Open(pathIn[0]); ripper.Open(pathIn[0]);
_toc = ripper.TOC; if (ripper.TOC.AudioTracks > 0)
_driveName = ripper.ARName;
ripper.Close();
if (_toc.AudioTracks > 0)
{ {
if (!AccurateRipVerify.FindDriveReadOffset(_driveName, out _driveOffset)) OpenCD(ripper);
throw new Exception("Failed to find drive read offset for drive" + _driveName); int driveOffset;
_isCD = true; if (!AccurateRipVerify.FindDriveReadOffset(_ripper.ARName, out driveOffset))
SourceInfo cdInfo; throw new Exception("Failed to find drive read offset for drive" + _ripper.ARName);
cdInfo.Path = pathIn; _ripper.DriveOffset = driveOffset;
cdInfo.Offset = 0;
cdInfo.Length = _toc.AudioLength * 588;
_sources.Add(cdInfo);
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
{
_trackFilenames.Add(string.Format("{0:00}.wav", iTrack + 1));
_tracks.Add(new TrackInfo());
}
_hasTrackFilenames = false;
_accurateRipId = _accurateRipIdActual = AccurateRipVerify.CalculateAccurateRipId(_toc);
_arVerify = new AccurateRipVerify(_toc);
Release release; Release release;
ReleaseQueryParameters p = new ReleaseQueryParameters(); ReleaseQueryParameters p = new ReleaseQueryParameters();
@@ -533,15 +555,11 @@ namespace CUETools.Processor
try try
{ {
release = results.First(); release = results.First();
General.SetCUELine(_attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(_toc), false); if (release != null)
General.SetCUELine(_attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
General.SetCUELine(_attributes, "REM", "DATE", release.GetEvents()[0].Date.Substring(0, 4), false);
General.SetCUELine(_attributes, "PERFORMER", release.GetArtist(), true);
General.SetCUELine(_attributes, "TITLE", release.GetTitle(), true);
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
{ {
General.SetCUELine(_tracks[iTrack].Attributes, "TITLE", release.GetTracks()[iTrack].GetTitle(), true); release.GetEvents();
General.SetCUELine(_tracks[iTrack].Attributes, "PERFORMER ", release.GetTracks()[iTrack].GetArtist(), true); release.GetTracks();
FillFromMusicBrainz(release);
} }
} }
catch catch
@@ -1212,7 +1230,7 @@ namespace CUETools.Processor
return (int)audioSource.Length; return (int)audioSource.Length;
} }
public void WriteText(string path, string text) public static void WriteText(string path, string text)
{ {
bool utf8Required = CUESheet.Encoding.GetString(CUESheet.Encoding.GetBytes(text)) != text; bool utf8Required = CUESheet.Encoding.GetString(CUESheet.Encoding.GetBytes(text)) != text;
StreamWriter sw1 = new StreamWriter(path, false, utf8Required ? Encoding.UTF8 : CUESheet.Encoding); StreamWriter sw1 = new StreamWriter(path, false, utf8Required ? Encoding.UTF8 : CUESheet.Encoding);
@@ -1222,16 +1240,18 @@ namespace CUETools.Processor
public string LOGContents() public string LOGContents()
{ {
if (!_isCD) if (!_isCD || _ripper == null)
return null; return null;
#if !MONO #if !MONO
StringWriter logWriter = new StringWriter(); StringWriter logWriter = new StringWriter();
logWriter.WriteLine("{0}", CDDriveReader.RipperVersion()); logWriter.WriteLine("{0}", CDDriveReader.RipperVersion());
logWriter.WriteLine("Extraction logfile from : {0}", DateTime.Now); logWriter.WriteLine("Extraction logfile from : {0}", DateTime.Now);
logWriter.WriteLine("Used drive : {0}", _driveName); logWriter.WriteLine("Used drive : {0}", _ripper.ARName);
logWriter.WriteLine("Read offset correction : {0}", _driveOffset); logWriter.WriteLine("Read offset correction : {0}", _ripper.DriveOffset);
//logWriter.WriteLine("Read command : {0}", ); logWriter.WriteLine("Read command : {0}", _ripper.CurrentReadCommand);
//logWriter.WriteLine("Secure mode : {0}", ); logWriter.WriteLine("Secure mode : {0}", _ripper.CorrectionQuality);
logWriter.WriteLine("Disk length : {0}", CDImageLayout.TimeToString(_toc.AudioLength));
logWriter.WriteLine("AccurateRip : {0}", _arVerify.ARStatus == null ? "ok" : _arVerify.ARStatus);
if (hdcdDecoder != null && hdcdDecoder.Detected) if (hdcdDecoder != null && hdcdDecoder.Detected)
{ {
hdcd_decoder_statistics stats; hdcd_decoder_statistics stats;
@@ -1264,7 +1284,7 @@ namespace CUETools.Processor
bool crcMismatch = _accurateRipMode == AccurateRipMode.VerifyThenConvert && bool crcMismatch = _accurateRipMode == AccurateRipMode.VerifyThenConvert &&
_arVerify.BackupCRC(iTrack) != _arVerify.CRC(iTrack); _arVerify.BackupCRC(iTrack) != _arVerify.CRC(iTrack);
for (uint iSector = _toc[iTrack + 1].Start; iSector <= _toc[iTrack + 1].End; iSector++) for (uint iSector = _toc[iTrack + 1].Start; iSector <= _toc[iTrack + 1].End; iSector++)
if (_cdErrors[(int)iSector]) if (_ripper.Errors[(int)iSector])
cdErrors++; cdErrors++;
if (crcMismatch || cdErrors != 0) if (crcMismatch || cdErrors != 0)
{ {
@@ -2040,10 +2060,9 @@ namespace CUETools.Processor
if (_isCD && audioSource != null && audioSource is CDDriveReader) if (_isCD && audioSource != null && audioSource is CDDriveReader)
{ {
updatedTOC = ((CDDriveReader)audioSource).TOC; updatedTOC = ((CDDriveReader)audioSource).TOC;
_cdErrors = ((CDDriveReader)audioSource).Errors;
} }
#endif #endif
if (audioSource != null) audioSource.Close(); if (audioSource != null && !_isCD) audioSource.Close();
audioSource = GetAudioSource(++iSource); audioSource = GetAudioSource(++iSource);
samplesRemSource = (uint)_sources[iSource].Length; samplesRemSource = (uint)_sources[iSource].Length;
} }
@@ -2073,7 +2092,7 @@ namespace CUETools.Processor
hdcdDecoder = null; hdcdDecoder = null;
if (_config.decodeHDCD) if (_config.decodeHDCD)
{ {
audioSource.Close(); if (!_isCD) audioSource.Close();
audioDest.Delete(); audioDest.Delete();
throw new Exception("HDCD not detected."); throw new Exception("HDCD not detected.");
} }
@@ -2113,7 +2132,7 @@ namespace CUETools.Processor
if (hdcdDecoder != null) if (hdcdDecoder != null)
hdcdDecoder.AudioDest = null; hdcdDecoder.AudioDest = null;
hdcdDecoder = null; hdcdDecoder = null;
try { if (audioSource != null) audioSource.Close(); } try { if (audioSource != null && !_isCD) audioSource.Close(); }
catch { } catch { }
audioSource = null; audioSource = null;
try { if (audioDest != null) audioDest.Close(); } try { if (audioDest != null) audioDest.Close(); }
@@ -2126,7 +2145,6 @@ namespace CUETools.Processor
if (_isCD && audioSource != null && audioSource is CDDriveReader) if (_isCD && audioSource != null && audioSource is CDDriveReader)
{ {
updatedTOC = ((CDDriveReader)audioSource).TOC; updatedTOC = ((CDDriveReader)audioSource).TOC;
_cdErrors = ((CDDriveReader)audioSource).Errors;
} }
if (updatedTOC != null) if (updatedTOC != null)
{ {
@@ -2134,10 +2152,15 @@ namespace CUETools.Processor
if (_toc.Catalog != null) if (_toc.Catalog != null)
General.SetCUELine(_attributes, "CATALOG", _toc.Catalog, false); General.SetCUELine(_attributes, "CATALOG", _toc.Catalog, false);
for (iTrack = 1; iTrack <= _toc.TrackCount; iTrack++) for (iTrack = 1; iTrack <= _toc.TrackCount; iTrack++)
if (_toc[iTrack].IsAudio)
{ {
if (_toc[iTrack].IsAudio && _toc[iTrack].ISRC != null) if (_toc[iTrack].ISRC != null)
General.SetCUELine(_tracks[iTrack - 1].Attributes, "ISRC", _toc[iTrack].ISRC, false); General.SetCUELine(_tracks[iTrack - 1].Attributes, "ISRC", _toc[iTrack].ISRC, false);
if (_toc[iTrack].IsAudio && _toc[iTrack].PreEmphasis) //if (_toc[iTrack].DCP || _toc[iTrack].PreEmphasis)
//cueWriter.WriteLine(" FLAGS{0}{1}", audioSource.TOC[track].PreEmphasis ? " PRE" : "", audioSource.TOC[track].DCP ? " DCP" : "");
if (_toc[iTrack].DCP)
General.SetCUELine(_tracks[iTrack - 1].Attributes, "FLAGS", "DCP", false);
if (_toc[iTrack].PreEmphasis)
General.SetCUELine(_tracks[iTrack - 1].Attributes, "FLAGS", "PRE", false); General.SetCUELine(_tracks[iTrack - 1].Attributes, "FLAGS", "PRE", false);
} }
} }
@@ -2145,7 +2168,7 @@ namespace CUETools.Processor
if (hdcdDecoder != null) if (hdcdDecoder != null)
hdcdDecoder.AudioDest = null; hdcdDecoder.AudioDest = null;
if (audioSource != null) if (audioSource != null && !_isCD)
audioSource.Close(); audioSource.Close();
if (audioDest != null) if (audioDest != null)
audioDest.Close(); audioDest.Close();
@@ -2339,11 +2362,8 @@ namespace CUETools.Processor
#if !MONO #if !MONO
if (_isCD) if (_isCD)
{ {
CDDriveReader ripper = new CDDriveReader(); audioSource = _ripper;
ripper.Open(sourceInfo.Path[0]); audioSource.Position = 0;
ripper.DriveOffset = _driveOffset;
ripper.ReadProgress += new EventHandler<ReadProgressArgs>(CDReadProgress);
audioSource = ripper;
} else } else
if (_isArchive) if (_isArchive)
{ {

View File

@@ -75,11 +75,14 @@ namespace CUETools.ConsoleRipper
drives += string.Format("{0}: ", drivesAvailable[i]); drives += string.Format("{0}: ", drivesAvailable[i]);
Console.WriteLine("Usage : CUERipper.exe <options>"); Console.WriteLine("Usage : CUERipper.exe <options>");
Console.WriteLine(); Console.WriteLine();
//Console.WriteLine("-S, --secure secure mode, read each block twice;"); Console.WriteLine("-S, --secure secure mode, read each block twice (default);");
Console.WriteLine("-B, --burst burst (1 pass) mode;");
Console.WriteLine("-P, --paranoid maximum level of error correction;"); Console.WriteLine("-P, --paranoid maximum level of error correction;");
Console.WriteLine("-D, --drive <letter> use a specific CD drive, e.g. {0};", drives); Console.WriteLine("-D, --drive <letter> use a specific CD drive, e.g. {0};", drives);
Console.WriteLine("-O, --offset <samples> use specific drive read offset;"); Console.WriteLine("-O, --offset <samples> use specific drive read offset;");
Console.WriteLine("-T, --test detect read command;"); Console.WriteLine("-T, --test detect read command;");
Console.WriteLine("--d8 force D8h read command;");
Console.WriteLine("--be force BEh read command;");
} }
static void Main(string[] args) static void Main(string[] args)
@@ -94,15 +97,22 @@ namespace CUETools.ConsoleRipper
string driveLetter = null; string driveLetter = null;
int driveOffset = 0; int driveOffset = 0;
bool test = false; bool test = false;
bool forceD8 = false, forceBE = false;
for (int arg = 0; arg < args.Length; arg++) for (int arg = 0; arg < args.Length; arg++)
{ {
bool ok = true; bool ok = true;
if (args[arg] == "-P" || args[arg] == "--paranoid") if (args[arg] == "-P" || args[arg] == "--paranoid")
correctionQuality = 4; correctionQuality = 4;
if (args[arg] == "-T" || args[arg] == "--test") else if (args[arg] == "-S" || args[arg] == "--secure")
correctionQuality = 1;
else if (args[arg] == "-B" || args[arg] == "--burst")
correctionQuality = 0;
else if (args[arg] == "-T" || args[arg] == "--test")
test = true; test = true;
//else if (args[arg] == "-B" || args[arg] == "--burst") else if (args[arg] == "--d8")
// correctionQuality = 1; forceD8 = true;
else if (args[arg] == "--be")
forceBE = true;
else if ((args[arg] == "-D" || args[arg] == "--drive") && ++arg < args.Length) else if ((args[arg] == "-D" || args[arg] == "--drive") && ++arg < args.Length)
driveLetter = args[arg]; driveLetter = args[arg];
else if ((args[arg] == "-O" || args[arg] == "--offset") && ++arg < args.Length) else if ((args[arg] == "-O" || args[arg] == "--offset") && ++arg < args.Length)
@@ -149,14 +159,18 @@ namespace CUETools.ConsoleRipper
if (!AccurateRipVerify.FindDriveReadOffset(audioSource.ARName, out driveOffset)) if (!AccurateRipVerify.FindDriveReadOffset(audioSource.ARName, out driveOffset))
Console.WriteLine("Unknown read offset for drive {0}!!!", audioSource.Path); Console.WriteLine("Unknown read offset for drive {0}!!!", audioSource.Path);
//throw new Exception("Failed to find drive read offset for drive" + audioSource.ARName); //throw new Exception("Failed to find drive read offset for drive" + audioSource.ARName);
if (test)
{
Console.Write(audioSource.AutoDetectReadCommand);
return;
}
audioSource.DriveOffset = driveOffset; audioSource.DriveOffset = driveOffset;
audioSource.CorrectionQuality = correctionQuality; audioSource.CorrectionQuality = correctionQuality;
audioSource.DebugMessages = true; audioSource.DebugMessages = true;
if (forceD8) audioSource.ForceD8 = true;
if (forceBE) audioSource.ForceBE = true;
string readCmd = audioSource.AutoDetectReadCommand;
if (test)
{
Console.Write(readCmd);
return;
}
AccurateRipVerify arVerify = new AccurateRipVerify(audioSource.TOC); AccurateRipVerify arVerify = new AccurateRipVerify(audioSource.TOC);
int[,] buff = new int[audioSource.BestBlockSize, audioSource.ChannelCount]; int[,] buff = new int[audioSource.BestBlockSize, audioSource.ChannelCount];
@@ -183,7 +197,7 @@ namespace CUETools.ConsoleRipper
Console.WriteLine("Drive : {0}", audioSource.Path); Console.WriteLine("Drive : {0}", audioSource.Path);
Console.WriteLine("Read offset : {0}", audioSource.DriveOffset); Console.WriteLine("Read offset : {0}", audioSource.DriveOffset);
Console.WriteLine("Read cmd : {0}", audioSource.ChosenReadCommand); Console.WriteLine("Read cmd : {0}", audioSource.CurrentReadCommand);
Console.WriteLine("Secure mode : {0}", audioSource.CorrectionQuality); Console.WriteLine("Secure mode : {0}", audioSource.CorrectionQuality);
Console.WriteLine("Filename : {0}", destFile); Console.WriteLine("Filename : {0}", destFile);
Console.WriteLine("Disk length : {0}", CDImageLayout.TimeToString(audioSource.TOC.AudioLength)); Console.WriteLine("Disk length : {0}", CDImageLayout.TimeToString(audioSource.TOC.AudioLength));
@@ -285,8 +299,8 @@ namespace CUETools.ConsoleRipper
} }
if (audioSource.TOC[track].ISRC != null) if (audioSource.TOC[track].ISRC != null)
cueWriter.WriteLine(" ISRC {0}", audioSource.TOC[track].ISRC); cueWriter.WriteLine(" ISRC {0}", audioSource.TOC[track].ISRC);
if (audioSource.TOC[track].PreEmphasis) if (audioSource.TOC[track].DCP || audioSource.TOC[track].PreEmphasis)
cueWriter.WriteLine(" FLAGS PRE"); cueWriter.WriteLine(" FLAGS{0}{1}", audioSource.TOC[track].PreEmphasis ? " PRE" : "", audioSource.TOC[track].DCP ? " DCP" : "");
for (int index = audioSource.TOC[track].Pregap > 0 ? 0 : 1; index <= audioSource.TOC[track].LastIndex; index++) for (int index = audioSource.TOC[track].Pregap > 0 ? 0 : 1; index <= audioSource.TOC[track].LastIndex; index++)
cueWriter.WriteLine(" INDEX {0:00} {1}", index, audioSource.TOC[track][index].MSF); cueWriter.WriteLine(" INDEX {0:00} {1}", index, audioSource.TOC[track][index].MSF);
} }

View File

@@ -46,8 +46,9 @@ namespace CUETools.Ripper.SCSI
int _correctionQuality = 1; int _correctionQuality = 1;
int _currentStart = -1, _currentEnd = -1, _currentErrorsCount = 0; int _currentStart = -1, _currentEnd = -1, _currentErrorsCount = 0;
const int CB_AUDIO = 4 * 588 + 2 + 294 + 16; const int CB_AUDIO = 4 * 588 + 2 + 294 + 16;
const int MAXSCANS = 20;
const int NSECTORS = 16; const int NSECTORS = 16;
const int MSECTORS = 10000000 / (4 * 588); const int MSECTORS = 5*1024*1024 / (4 * 588);
int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1; int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1;
Logger m_logger; Logger m_logger;
CDImageLayout _toc; CDImageLayout _toc;
@@ -56,17 +57,23 @@ namespace CUETools.Ripper.SCSI
int m_max_sectors; int m_max_sectors;
int _timeout = 10; int _timeout = 10;
Crc16Ccitt _crc; Crc16Ccitt _crc;
List<ScanResults> _scanResults; int _currentScan;
ScanResults _currentScan = null; public byte[,,] UserData;
public byte[,,] C2Data;
public byte[,,] QData;
public long[] Quality;
BitArray _errors; BitArray _errors;
int _errorsCount; int _errorsCount;
int _crcErrorsCount = 0;
byte[] _currentData = new byte[MSECTORS * 4 * 588]; byte[] _currentData = new byte[MSECTORS * 4 * 588];
int[] valueScore = new int[256]; short[] _valueScore = new short[256];
bool _debugMessages = false; bool _debugMessages = false;
ReadCDCommand _readCDCommand = ReadCDCommand.Unknown;
ReadCDCommand _forceReadCommand = ReadCDCommand.Unknown;
Device.MainChannelSelection _mainChannelMode = Device.MainChannelSelection.UserData; Device.MainChannelSelection _mainChannelMode = Device.MainChannelSelection.UserData;
Device.SubChannelMode _subChannelMode = Device.SubChannelMode.None; Device.SubChannelMode _subChannelMode = Device.SubChannelMode.QOnly;
Device.C2ErrorMode _c2ErrorMode = Device.C2ErrorMode.Mode296; Device.C2ErrorMode _c2ErrorMode = Device.C2ErrorMode.Mode296;
string m_test_result; string _autodetectResult;
byte[] _readBuffer = new byte[NSECTORS * CB_AUDIO]; byte[] _readBuffer = new byte[NSECTORS * CB_AUDIO];
byte[] _subchannelBuffer = new byte[NSECTORS * 16]; byte[] _subchannelBuffer = new byte[NSECTORS * 16];
@@ -124,9 +131,36 @@ namespace CUETools.Ripper.SCSI
{ {
get get
{ {
if (m_test_result == null) if (_autodetectResult != null || TestReadCommand())
TestReadCommand(); return _autodetectResult;
return m_test_result; string ret = _autodetectResult;
_autodetectResult = null;
return ret;
}
}
public bool ForceD8
{
get
{
return _forceReadCommand == ReadCDCommand.ReadCdD8h;
}
set
{
_forceReadCommand = value ? ReadCDCommand.ReadCdD8h : ReadCDCommand.Unknown;
}
}
public bool ForceBE
{
get
{
return _forceReadCommand == ReadCDCommand.ReadCdBEh;
}
set
{
_forceReadCommand = value ? ReadCDCommand.ReadCdBEh : ReadCDCommand.Unknown;
} }
} }
@@ -134,25 +168,24 @@ namespace CUETools.Ripper.SCSI
{ {
get get
{ {
return string.Format("BEh, {0}, {1}, {2}, {3} blocks at a time", (_mainChannelMode == Device.MainChannelSelection.UserData ? "10h" : "F8h"), return _readCDCommand == ReadCDCommand.Unknown ? "unknown" :
string.Format("{0}, {1}, {2}, {3}, {4} blocks at a time",
(_readCDCommand == ReadCDCommand.ReadCdBEh ? "BEh" : "D8h"),
(_mainChannelMode == Device.MainChannelSelection.UserData ? "10h" : "F8h"),
(_subChannelMode == Device.SubChannelMode.None ? "00h" : _subChannelMode == Device.SubChannelMode.QOnly ? "02h" : "04h"), (_subChannelMode == Device.SubChannelMode.None ? "00h" : _subChannelMode == Device.SubChannelMode.QOnly ? "02h" : "04h"),
(_c2ErrorMode == Device.C2ErrorMode.None ? "00h" : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? "01h" : "04h"), (_c2ErrorMode == Device.C2ErrorMode.None ? "00h" : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? "01h" : "04h"),
m_max_sectors); m_max_sectors);
} }
} }
public string ChosenReadCommand
{
get
{
return m_test_result == null && !TestReadCommand() ? "not detected" : CurrentReadCommand;
}
}
public CDDriveReader() public CDDriveReader()
{ {
m_logger = new Logger(); m_logger = new Logger();
_crc = new Crc16Ccitt(InitialCrcValue.Zeros); _crc = new Crc16Ccitt(InitialCrcValue.Zeros);
UserData = new byte[MAXSCANS, MSECTORS, 4 * 588];
C2Data = new byte[MAXSCANS, MSECTORS, 294];
QData = new byte[MAXSCANS, MSECTORS, 16];
Quality = new long[MAXSCANS];
} }
public bool Open(char Drive) public bool Open(char Drive)
@@ -197,6 +230,7 @@ namespace CUETools.Ripper.SCSI
//if (st != Device.CommandStatus.Success) //if (st != Device.CommandStatus.Success)
// throw new Exception("GetSpeed failed: SCSI error"); // throw new Exception("GetSpeed failed: SCSI error");
//m_device.SetCdSpeed(Device.RotationalControl.CLVandNonPureCav, (ushort)(0x7fff), (ushort)(0x7fff));
//int bytesPerSec = 4 * 588 * 75 * (pass > 8 ? 4 : pass > 4 ? 8 : pass > 0 ? 16 : 32); //int bytesPerSec = 4 * 588 * 75 * (pass > 8 ? 4 : pass > 4 ? 8 : pass > 0 ? 16 : 32);
//Device.CommandStatus st = m_device.SetStreaming(Device.RotationalControl.CLVandNonPureCav, start, end, bytesPerSec, 1, bytesPerSec, 1); //Device.CommandStatus st = m_device.SetStreaming(Device.RotationalControl.CLVandNonPureCav, start, end, bytesPerSec, 1, bytesPerSec, 1);
//if (st != Device.CommandStatus.Success) //if (st != Device.CommandStatus.Success)
@@ -253,34 +287,39 @@ namespace CUETools.Ripper.SCSI
int posCount = 0; int posCount = 0;
for (int iSector = 0; iSector < Sectors2Read; iSector++) for (int iSector = 0; iSector < Sectors2Read; iSector++)
{ {
int q_pos = sector - _currentStart + iSector; int q_pos = (sector - _currentStart + iSector);
int ctl = _currentScan.QData[q_pos, 0] >> 4; int ctl = QData[_currentScan, q_pos, 0] >> 4;
int adr = _currentScan.QData[q_pos, 0] & 7; int adr = QData[_currentScan, q_pos, 0] & 7;
bool preemph = (ctl & 1) == 1; bool preemph = (ctl & 1) == 1;
bool dcp = (ctl & 2) == 2;
switch (adr) switch (adr)
{ {
case 1: // current position case 1: // current position
{ {
int iTrack = fromBCD(_currentScan.QData[q_pos, 1]); int iTrack = fromBCD(QData[_currentScan, q_pos, 1]);
int iIndex = fromBCD(_currentScan.QData[q_pos, 2]); int iIndex = fromBCD(QData[_currentScan, q_pos, 2]);
int mm = fromBCD(_currentScan.QData[q_pos, 7]); int mm = fromBCD(QData[_currentScan, q_pos, 7]);
int ss = fromBCD(_currentScan.QData[q_pos, 8]); int ss = fromBCD(QData[_currentScan, q_pos, 8]);
int ff = fromBCD(_currentScan.QData[q_pos, 9]); int ff = fromBCD(QData[_currentScan, q_pos, 9]);
int sec = ff + 75 * (ss + 60 * mm) - 150; // sector + iSector; int sec = ff + 75 * (ss + 60 * mm) - 150; // sector + iSector;
//if (sec != sector + iSector) //if (sec != sector + iSector)
// System.Console.WriteLine("\rLost sync: {0} vs {1} ({2:X} vs {3:X})", CDImageLayout.TimeToString((uint)(sector + iSector)), CDImageLayout.TimeToString((uint)sec), sector + iSector, sec); // System.Console.WriteLine("\rLost sync: {0} vs {1} ({2:X} vs {3:X})", CDImageLayout.TimeToString((uint)(sector + iSector)), CDImageLayout.TimeToString((uint)sec), sector + iSector, sec);
byte[] tmp = new byte[16];
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
_subchannelBuffer[i] = _currentScan.QData[q_pos, i]; _subchannelBuffer[i] = QData[_currentScan, q_pos, i];
ushort crc = _crc.ComputeChecksum(_subchannelBuffer, 0, 10); ushort crc = _crc.ComputeChecksum(_subchannelBuffer, 0, 10);
crc ^= 0xffff; crc ^= 0xffff;
if (_currentScan.QData[q_pos, 10] != 0 && _currentScan.QData[q_pos, 11] != 0 && if ((QData[_currentScan, q_pos, 10] != 0 || QData[_currentScan, q_pos, 11] != 0) &&
((crc & 0xff) != _currentScan.QData[q_pos, 11] || ((byte)(crc & 0xff) != QData[_currentScan, q_pos, 11] || (byte)(crc >> 8) != QData[_currentScan, q_pos, 10])
(crc >> 8) != _currentScan.QData[q_pos, 10])
) )
{ {
if (_debugMessages) _crcErrorsCount ++;
System.Console.WriteLine("\nCRC error at {0}", CDImageLayout.TimeToString((uint)(sector + iSector))); if (_debugMessages && _crcErrorsCount < 4)
{
StringBuilder st = new StringBuilder();
for (int i = 0; i < 12; i++)
st.AppendFormat(" 0x{0:X2}", QData[_currentScan, q_pos, i]);
System.Console.WriteLine("\nCRC error at {0}:{1}", CDImageLayout.TimeToString((uint)(sector + iSector)), st.ToString());
}
continue; continue;
} }
if (iTrack == 110) if (iTrack == 110)
@@ -299,16 +338,33 @@ namespace CUETools.Ripper.SCSI
throw new Exception("strange track number encountred"); throw new Exception("strange track number encountred");
if (iTrack != _currentTrack) if (iTrack != _currentTrack)
{ {
if (_currentTrack != -1 && iTrack != _currentTrack + 1)
{
if (_debugMessages)
System.Console.WriteLine("\nNon-consequent track at {0}: {1} after {2}", CDImageLayout.TimeToString((uint)(sector + iSector)), iTrack, _currentTrack);
//throw new Exception("invalid track");
continue;
}
if (iIndex != 1 && iIndex != 0)
{
if (_debugMessages)
System.Console.WriteLine("\nInvalid track start index at {0}: {1}.{2}", CDImageLayout.TimeToString((uint)(sector + iSector)), iTrack, iIndex);
//throw new Exception("invalid index");
continue;
}
_currentTrack = iTrack; _currentTrack = iTrack;
_currentTrackActualStart = sec; _currentTrackActualStart = sec;
_currentIndex = iIndex; _currentIndex = iIndex;
if (_currentIndex != 1 && _currentIndex != 0)
throw new Exception("invalid index");
} }
else if (iIndex != _currentIndex) else if (iIndex != _currentIndex)
{ {
if (iIndex != _currentIndex + 1) if (iIndex != _currentIndex + 1)
throw new Exception("invalid index"); {
if (_debugMessages)
System.Console.WriteLine("\nNon-consequent index at {0}: {1} after {2}", CDImageLayout.TimeToString((uint)(sector + iSector)), iIndex, _currentIndex);
//throw new Exception("invalid index");
continue;
}
_currentIndex = iIndex; _currentIndex = iIndex;
if (_currentIndex == 1) if (_currentIndex == 1)
{ {
@@ -321,32 +377,35 @@ namespace CUETools.Ripper.SCSI
} }
if (preemph) if (preemph)
_toc[iTrack].PreEmphasis = true; _toc[iTrack].PreEmphasis = true;
if (dcp)
_toc[iTrack].DCP = true;
break; break;
} }
case 2: // catalog case 2: // catalog
if (_toc.Catalog == null) if (updateMap && _toc.Catalog == null)
{ {
StringBuilder catalog = new StringBuilder(); StringBuilder catalog = new StringBuilder();
for (int i = 1; i < 8; i++) for (int i = 1; i < 8; i++)
catalog.AppendFormat("{0:x2}", _currentScan.QData[q_pos, i]); catalog.AppendFormat("{0:x2}", QData[_currentScan, q_pos, i]);
_toc.Catalog = catalog.ToString(0, 13); _toc.Catalog = catalog.ToString(0, 13);
} }
break; break;
case 3: //isrc case 3: //isrc
if (_toc[_currentTrack].ISRC == null) if (updateMap && _toc[_currentTrack].ISRC == null)
{ {
StringBuilder isrc = new StringBuilder(); StringBuilder isrc = new StringBuilder();
isrc.Append(from6bit(_currentScan.QData[q_pos, 1] >> 2)); isrc.Append(from6bit(QData[_currentScan, q_pos, 1] >> 2));
isrc.Append(from6bit(((_currentScan.QData[q_pos, 1] & 0x3) << 4) + (0x0f & (_currentScan.QData[q_pos, 2] >> 4)))); isrc.Append(from6bit(((QData[_currentScan, q_pos, 1] & 0x3) << 4) + (0x0f & (QData[_currentScan, q_pos, 2] >> 4))));
isrc.Append(from6bit(((_currentScan.QData[q_pos, 2] & 0xf) << 2) + (0x03 & (_currentScan.QData[q_pos, 3] >> 6)))); isrc.Append(from6bit(((QData[_currentScan, q_pos, 2] & 0xf) << 2) + (0x03 & (QData[_currentScan, q_pos, 3] >> 6))));
isrc.Append(from6bit((_currentScan.QData[q_pos, 3] & 0x3f))); isrc.Append(from6bit((QData[_currentScan, q_pos, 3] & 0x3f)));
isrc.Append(from6bit(_currentScan.QData[q_pos, 4] >> 2)); isrc.Append(from6bit(QData[_currentScan, q_pos, 4] >> 2));
isrc.Append(from6bit(((_currentScan.QData[q_pos, 4] & 0x3) << 4) + (0x0f & (_currentScan.QData[q_pos, 5] >> 4)))); isrc.Append(from6bit(((QData[_currentScan, q_pos, 4] & 0x3) << 4) + (0x0f & (QData[_currentScan, q_pos, 5] >> 4))));
isrc.AppendFormat("{0:x}", _currentScan.QData[q_pos, 5] & 0xf); isrc.AppendFormat("{0:x}", QData[_currentScan, q_pos, 5] & 0xf);
isrc.AppendFormat("{0:x2}", _currentScan.QData[q_pos, 6]); isrc.AppendFormat("{0:x2}", QData[_currentScan, q_pos, 6]);
isrc.AppendFormat("{0:x2}", _currentScan.QData[q_pos, 7]); isrc.AppendFormat("{0:x2}", QData[_currentScan, q_pos, 7]);
isrc.AppendFormat("{0:x}", _currentScan.QData[q_pos, 8] >> 4); isrc.AppendFormat("{0:x}", QData[_currentScan, q_pos, 8] >> 4);
_toc[_currentTrack].ISRC = isrc.ToString(); if (!isrc.ToString().Contains("#") && isrc.ToString() != "0000000000")
_toc[_currentTrack].ISRC = isrc.ToString();
} }
break; break;
} }
@@ -356,38 +415,60 @@ namespace CUETools.Ripper.SCSI
public unsafe bool TestReadCommand() public unsafe bool TestReadCommand()
{ {
Device.MainChannelSelection[] mainmode = { Device.MainChannelSelection.UserData, Device.MainChannelSelection.F8h }; //ReadCDCommand[] readmode = { ReadCDCommand.ReadCdBEh, ReadCDCommand.ReadCdD8h };
Device.SubChannelMode[] submode = { Device.SubChannelMode.None, Device.SubChannelMode.QOnly, Device.SubChannelMode.RWMode }; ReadCDCommand[] readmode = { ReadCDCommand.ReadCdD8h, ReadCDCommand.ReadCdBEh };
Device.SubChannelMode[] submode = { Device.SubChannelMode.QOnly, Device.SubChannelMode.None, Device.SubChannelMode.RWMode };
Device.C2ErrorMode[] c2mode = { Device.C2ErrorMode.Mode296, Device.C2ErrorMode.Mode294, Device.C2ErrorMode.None }; Device.C2ErrorMode[] c2mode = { Device.C2ErrorMode.Mode296, Device.C2ErrorMode.Mode294, Device.C2ErrorMode.None };
Device.MainChannelSelection[] mainmode = { Device.MainChannelSelection.UserData, Device.MainChannelSelection.F8h };
bool found = false; bool found = false;
ScanResults saved = _currentScan; _currentStart = 0;
_currentScan = new ScanResults(MSECTORS); _currentScan = 0;
for (int m = 0; m <= 1 && !found; m++) _currentTrack = -1;
for (int q = 0; q <= 2 && !found; q++) _currentIndex = -1;
for (int c = 0; c <= 2 && !found; c++)
{
_mainChannelMode = mainmode[m];
_subChannelMode = submode[q];
_c2ErrorMode = c2mode[c];
m_max_sectors = 1;
Device.CommandStatus st = FetchSectors(0, 1, false);
m_test_result += string.Format("{0}: {1}\n", CurrentReadCommand, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
found = st == Device.CommandStatus.Success && _subChannelMode != Device.SubChannelMode.RWMode;
}
m_max_sectors = Math.Min(NSECTORS, m_device.MaximumTransferLength / CB_AUDIO - 1); m_max_sectors = Math.Min(NSECTORS, m_device.MaximumTransferLength / CB_AUDIO - 1);
int sector = 3;
for (int q = 0; q <= 1 && !found; q++)
for (int c = 0; c <= 2 && !found; c++)
for (int r = 0; r <= 1 && !found; r++)
for (int m = 0; m <= 1 && !found; m++)
{
_readCDCommand = readmode[r];
_subChannelMode = submode[q];
_c2ErrorMode = c2mode[c];
_mainChannelMode = mainmode[m];
if (_forceReadCommand != ReadCDCommand.Unknown && _readCDCommand != _forceReadCommand)
continue;
if (_readCDCommand == ReadCDCommand.ReadCdD8h && (_c2ErrorMode != Device.C2ErrorMode.None || _mainChannelMode != Device.MainChannelSelection.UserData))
continue;
Array.Clear(_readBuffer, 0, _readBuffer.Length); // fill with something nasty instead?
DateTime tm = DateTime.Now;
Device.CommandStatus st = FetchSectors(sector, m_max_sectors, false, false);
TimeSpan delay = DateTime.Now - tm;
if (st == Device.CommandStatus.Success && _subChannelMode == Device.SubChannelMode.QOnly && ProcessSubchannel(sector, m_max_sectors, false) == 0)
{
_autodetectResult += string.Format("{0}: {1}\n", CurrentReadCommand, "Got no subchannel information");
continue;
}
_autodetectResult += string.Format("{0}: {1} ({2}ms)\n", CurrentReadCommand, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()), delay.TotalMilliseconds);
found = st == Device.CommandStatus.Success && _subChannelMode != Device.SubChannelMode.RWMode;// && _subChannelMode != Device.SubChannelMode.QOnly;
//sector += m_max_sectors;
}
//if (found)
// for (int n = 1; n <= m_max_sectors; n++)
// {
// Device.CommandStatus st = FetchSectors(0, n, false, false);
// if (st != Device.CommandStatus.Success)
// {
// _autodetectResult += string.Format("Maximum sectors: {0}, else {1}; max length {2}\n", n - 1, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()), m_device.MaximumTransferLength);
// m_max_sectors = n - 1;
// break;
// }
// }
if (found) if (found)
for (int n = 1; n <= m_max_sectors; n++) _autodetectResult += "Chosen " + CurrentReadCommand + "\n";
{ else
Device.CommandStatus st = FetchSectors(0, n, false); _readCDCommand = ReadCDCommand.Unknown;
if (st != Device.CommandStatus.Success) _currentStart = -1;
{
m_test_result += string.Format("Maximum sectors: {0}, else {1}; max length {2}\n", n - 1, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()), m_device.MaximumTransferLength);
m_max_sectors = n - 1;
break;
}
}
m_test_result += "Chosen " + CurrentReadCommand + "\n";
_currentScan = saved;
return found; return found;
} }
@@ -395,26 +476,26 @@ namespace CUETools.Ripper.SCSI
{ {
int c2Size = _c2ErrorMode == Device.C2ErrorMode.None ? 0 : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : 296; int c2Size = _c2ErrorMode == Device.C2ErrorMode.None ? 0 : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : 296;
int oldSize = 4 * 588 + c2Size + (_subChannelMode == Device.SubChannelMode.None ? 0 : 16); int oldSize = 4 * 588 + c2Size + (_subChannelMode == Device.SubChannelMode.None ? 0 : 16);
fixed (byte* readBuf = _readBuffer, qBuf = _subchannelBuffer, userData = _currentScan.UserData, c2Data = _currentScan.C2Data, qData = _currentScan.QData) fixed (byte* readBuf = _readBuffer, qBuf = _subchannelBuffer, userData = UserData, c2Data = C2Data, qData = QData)
{ {
for (int iSector = 0; iSector < Sectors2Read; iSector++) for (int iSector = 0; iSector < Sectors2Read; iSector++)
{ {
byte* sectorPtr = readBuf + iSector * oldSize; byte* sectorPtr = readBuf + iSector * oldSize;
byte* userDataPtr = userData + (sector - _currentStart + iSector) * 4 * 588; byte* userDataPtr = userData + (_currentScan * MSECTORS + sector - _currentStart + iSector) * 4 * 588;
byte* c2DataPtr = c2Data + (sector - _currentStart + iSector) * 294; byte* c2DataPtr = c2Data + (_currentScan * MSECTORS + sector - _currentStart + iSector) * 294;
byte* qDataPtr = qData + (sector - _currentStart + iSector) * 16; byte* qDataPtr = qData + (_currentScan * MSECTORS + sector - _currentStart + iSector) * 16;
for (int sample = 0; sample < 4 * 588; sample++) for (int sample = 0; sample < 4 * 588; sample++)
userDataPtr[sample] = sectorPtr[sample]; userDataPtr[sample] = sectorPtr[sample];
if (_c2ErrorMode != Device.C2ErrorMode.None) if (_c2ErrorMode != Device.C2ErrorMode.None)
for (int c2 = 0; c2 < 294; c2++) for (int c2 = 0; c2 < 294; c2++)
c2DataPtr[c2] = sectorPtr[4 * 588 + c2Size - 294]; c2DataPtr[c2] = sectorPtr[4 * 588 + c2Size - 294 + c2];
else else
for (int c2 = 0; c2 < 294; c2++) for (int c2 = 0; c2 < 294; c2++)
c2DataPtr[c2] = 0xff; c2DataPtr[c2] = 0; // 0xff??
if (_subChannelMode != Device.SubChannelMode.None) if (_subChannelMode != Device.SubChannelMode.None)
for (int qi = 0; qi < 16; qi++) for (int qi = 0; qi < 16; qi++)
qDataPtr[qi] = sectorPtr[4 * 588 + c2Size]; qDataPtr[qi] = sectorPtr[4 * 588 + c2Size + qi];
else else
for (int qi = 0; qi < 16; qi++) for (int qi = 0; qi < 16; qi++)
qDataPtr[qi] = qBuf[iSector * 16 + qi]; qDataPtr[qi] = qBuf[iSector * 16 + qi];
@@ -422,47 +503,45 @@ namespace CUETools.Ripper.SCSI
} }
} }
private unsafe Device.CommandStatus FetchSectors(int sector, int Sectors2Read, bool abort) private unsafe Device.CommandStatus FetchSectors(int sector, int Sectors2Read, bool abort, bool subchannel)
{ {
Device.CommandStatus st; Device.CommandStatus st;
fixed (byte* data = _readBuffer) fixed (byte* data = _readBuffer)
{ {
st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout); if (_readCDCommand == ReadCDCommand.ReadCdBEh)
st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout);
else
st = m_device.ReadCDDA(_subChannelMode, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout);
} }
if (st == Device.CommandStatus.Success && _subChannelMode == Device.SubChannelMode.None && subchannel)
st = m_device.ReadSubChannel(2, (uint)sector, (uint)Sectors2Read, ref _subchannelBuffer, _timeout);
if (st == Device.CommandStatus.Success) if (st == Device.CommandStatus.Success)
{ {
if (_subChannelMode == Device.SubChannelMode.None) ReorganiseSectors(sector, Sectors2Read);
{ return st;
st = m_device.ReadSubChannel(2, (uint)sector, (uint)Sectors2Read, ref _subchannelBuffer, _timeout);
if (st == Device.CommandStatus.Success)
{
ReorganiseSectors(sector, Sectors2Read);
return st;
}
}
else
{
ReorganiseSectors(sector, Sectors2Read);
return st;
}
} }
if (!abort) if (!abort)
return st; return st;
SCSIException ex = new SCSIException("ReadCD", m_device, st); SCSIException ex = new SCSIException("ReadCD", m_device, st);
if (sector != 0 && Sectors2Read > 1 && st == Device.CommandStatus.DeviceFailed && m_device.GetSenseAsc() == 0x64 && m_device.GetSenseAscq() == 0x00) if (sector != 0 && Sectors2Read > 1 && st == Device.CommandStatus.DeviceFailed && m_device.GetSenseAsc() == 0x64 && m_device.GetSenseAscq() == 0x00)
{ {
if (_debugMessages)
System.Console.WriteLine("\n{0}: retrying one sector at a time", ex.Message);
int iErrors = 0; int iErrors = 0;
for (int iSector = 0; iSector < Sectors2Read; iSector++) for (int iSector = 0; iSector < Sectors2Read; iSector++)
{ {
if (FetchSectors(sector + iSector, 1, false) != Device.CommandStatus.Success) if (FetchSectors(sector + iSector, 1, false, subchannel) != Device.CommandStatus.Success)
{ {
iErrors ++; iErrors ++;
for (int i = 0; i < 4 * 588; i++) for (int i = 0; i < 4 * 588; i++)
_currentScan.UserData[sector + iSector - _currentStart, i] = 0; UserData[_currentScan, sector + iSector - _currentStart, i] = 0;
for (int i = 0; i < 294; i++) for (int i = 0; i < 294; i++)
_currentScan.C2Data[sector + iSector - _currentStart, i] = 0xff; C2Data[_currentScan, sector + iSector - _currentStart, i] = 0xff;
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
_currentScan.QData[sector + iSector - _currentStart, i] = 0; QData[_currentScan, sector + iSector - _currentStart, i] = 0;
if (_debugMessages) if (_debugMessages)
System.Console.WriteLine("\nSector lost"); System.Console.WriteLine("\nSector lost");
} }
@@ -470,46 +549,136 @@ namespace CUETools.Ripper.SCSI
if (iErrors < Sectors2Read) if (iErrors < Sectors2Read)
return Device.CommandStatus.Success; return Device.CommandStatus.Success;
} }
throw new Exception(ex.Message + "; Autodetect: " + m_test_result); throw ex;
} }
private unsafe void CorrectSectors(int sector, int Sectors2Read, bool findWorst, bool markErrors) private unsafe void ZeroMemory(short *buf, int count)
{
if (IntPtr.Size == 4)
{
Int32* start = (Int32*)buf;
Int32* end = (Int32*)(buf + count);
while (start < end)
*(start++) = 0;
}
else if (IntPtr.Size == 8)
{
Int64* start = (Int64*)buf;
Int64* end = (Int64*)(buf + count);
while (start < end)
*(start++) = 0;
}
else
throw new Exception("wierd IntPtr.Size");
}
private unsafe void ZeroMemory(byte* buf, int count)
{
if (IntPtr.Size == 4)
{
Int32* start = (Int32*)buf;
Int32* end = (Int32*)(buf + count);
while (start < end)
*(start++) = 0;
for (int i = 0; i < (count & 3); i++)
buf[count - i - 1] = 0;
}
else if (IntPtr.Size == 8)
{
Int64* start = (Int64*)buf;
Int64* end = (Int64*)(buf + count);
while (start < end)
*(start++) = 0;
for (int i = 0; i < (count & 7); i++)
buf[count - i - 1] = 0;
}
else
throw new Exception("wierd IntPtr.Size");
}
private unsafe void CorrectSectors0(int sector, int Sectors2Read)
{ {
int c2Score = 10;
for (int iSector = 0; iSector < Sectors2Read; iSector++) for (int iSector = 0; iSector < Sectors2Read; iSector++)
{ {
int pos = sector - _currentStart + iSector;
for (int iPar = 0; iPar < 4 * 588; iPar++) for (int iPar = 0; iPar < 4 * 588; iPar++)
{ {
int pos = sector - _currentStart + iSector; byte bestValue = UserData[0, pos, iPar];
int c2Bit = 0x80 >> (iPar % 8); _currentErrorsCount += (C2Data[0, pos, iPar >> 3] >> (iPar & 7)) & 1;
_currentData[pos * 4 * 588 + iPar] = bestValue;
}
}
}
Array.Clear(valueScore, 0, 256); private unsafe void CorrectSectors1(int sector, int Sectors2Read)
byte bestValue = _currentScan.UserData[pos, iPar]; {
valueScore[bestValue] += 1 + (((_currentScan.C2Data[pos, iPar/8] & c2Bit) == 0) ? c2Score : 0); for (int iSector = 0; iSector < Sectors2Read; iSector++)
int totalScore = valueScore[bestValue]; {
for (int result = 0; result < _scanResults.Count; result++) int pos = sector - _currentStart + iSector;
for (int iPar = 0; iPar < 4 * 588; iPar++)
{
byte val1 = UserData[0, pos, iPar];
byte val2 = UserData[1, pos, iPar];
int err1 = (C2Data[0, pos, iPar >> 3] >> (iPar & 7)) & 1;
int err2 = (C2Data[1, pos, iPar >> 3] >> (iPar & 7)) & 1;
_currentErrorsCount += err1 | err2 | (val1 != val2 ? 1 : 0);
_currentData[pos * 4 * 588 + iPar] = err1 != 0 ? val2 : val1;
}
}
}
private unsafe void CorrectSectors(int pass, int sector, int Sectors2Read, bool findWorst, bool markErrors)
{
if (pass == 0)
{
CorrectSectors0(sector, Sectors2Read);
return;
}
if (pass == 1)
{
CorrectSectors1(sector, Sectors2Read);
return;
}
short c2Score = 10;
fixed (short* valueScore = _valueScore)
{
fixed (byte* userData = UserData, c2Data = C2Data, qData = QData)
{
for (int iSector = 0; iSector < Sectors2Read; iSector++)
{ {
byte value = _scanResults[result].UserData[pos, iPar]; int pos = sector - _currentStart + iSector;
int score = 1 + (((_scanResults[result].C2Data[pos, iPar/8] & c2Bit) == 0) ? c2Score : 0); for (int iPar = 0; iPar < 4 * 588; iPar++)
valueScore[value] += score; {
totalScore += score; int c2Bit = 0x80 >> (iPar % 8);
if (valueScore[value] > valueScore[bestValue])
bestValue = value; ZeroMemory(valueScore, 256);
} byte bestValue = 0;
bool fError = valueScore[bestValue] * 2 <= c2Score + totalScore; short totalScore = 0;
if (fError) for (int result = 0; result <= pass; result++)
_currentErrorsCount++; {
_currentData[(sector - _currentStart + iSector) * 4 * 588 + iPar] = bestValue; int offs = (result * MSECTORS + pos) * 4 * 588 + iPar;
if (findWorst) byte value = userData[offs];
{ short score = (short)(1 + (((c2Data[offs >> 3] & c2Bit) == 0) ? c2Score : (short)0));
for (int result = 0; result < _scanResults.Count; result++) valueScore[value] += score;
_scanResults[result].Quality += Math.Min(0, valueScore[_scanResults[result].UserData[pos, iPar]] - c2Score - 1); totalScore += score;
_currentScan.Quality += Math.Min(0, valueScore[_currentScan.UserData[pos, iPar]] - c2Score - 1); if (valueScore[value] > valueScore[bestValue])
} bestValue = value;
if (markErrors) }
{ bool fError = valueScore[bestValue] <= _correctionQuality + c2Score + totalScore / 2;
_errors[sector + iSector] = fError; if (fError)
_errorsCount += fError ? 1 : 0; _currentErrorsCount++;
_currentData[(sector - _currentStart + iSector) * 4 * 588 + iPar] = bestValue;
if (findWorst)
{
for (int result = 0; result <= pass; result++)
Quality[result] += Math.Min(0, valueScore[userData[(result * MSECTORS + pos) * 4 * 588 + iPar]] - c2Score - 2);
}
if (markErrors)
{
_errors[sector + iSector] |= fError;
_errorsCount += fError ? 1 : 0;
}
}
} }
} }
} }
@@ -569,20 +738,18 @@ namespace CUETools.Ripper.SCSI
// return realErrors; // return realErrors;
//} //}
public void PrefetchSector(int iSector) public unsafe void PrefetchSector(int iSector)
{ {
int nPasses = 16 + _correctionQuality * 2; int nExtraPasses = MAXSCANS / 2 + _correctionQuality;
int nExtraPasses = 8 + _correctionQuality;
if (_currentStart == MSECTORS * (iSector / MSECTORS)) if (_currentStart == MSECTORS * (iSector / MSECTORS))
return; return;
if (m_test_result == null && !TestReadCommand()) if (_readCDCommand == ReadCDCommand.Unknown && !TestReadCommand())
throw new Exception("failed to autodetect read command: " + m_test_result); throw new Exception("failed to autodetect read command: " + _autodetectResult);
_currentStart = MSECTORS * (iSector / MSECTORS); _currentStart = MSECTORS * (iSector / MSECTORS);
_currentEnd = Math.Min(_currentStart + MSECTORS, (int)_toc.AudioLength); _currentEnd = Math.Min(_currentStart + MSECTORS, (int)_toc.AudioLength);
_scanResults = new List<ScanResults>();
//FileStream correctFile = new FileStream("correct.wav", FileMode.Open); //FileStream correctFile = new FileStream("correct.wav", FileMode.Open);
//byte[] realData = new byte[MSECTORS * 4 * 588]; //byte[] realData = new byte[MSECTORS * 4 * 588];
@@ -591,82 +758,80 @@ namespace CUETools.Ripper.SCSI
// throw new Exception("read"); // throw new Exception("read");
//correctFile.Close(); //correctFile.Close();
for (int pass = 0; pass <= nPasses + nExtraPasses; pass++) fixed (byte* userData = UserData, c2Data = C2Data, qData = QData)
{ {
DateTime PassTime = DateTime.Now, LastFetch = DateTime.Now; for (int pass = 0; pass < MAXSCANS + nExtraPasses; pass++)
_currentScan = new ScanResults(MSECTORS);
_currentErrorsCount = 0;
for (int sector = _currentStart; sector < _currentEnd; sector += m_max_sectors)
{ {
int Sectors2Read = Math.Min(m_max_sectors, _currentEnd - sector); DateTime PassTime = DateTime.Now, LastFetch = DateTime.Now;
int speed = pass == 4 || pass == 5 ? 4 : pass == 8 || pass == 9 ? 2 : pass == 17 || pass == 18 ? 1 : 0; if (pass < MAXSCANS)
if (speed != 0) _currentScan = pass;
Thread.Sleep(Math.Max(1, 1000 * Sectors2Read / (75 * speed) - (int)((DateTime.Now - LastFetch).TotalMilliseconds)));
LastFetch = DateTime.Now;
FetchSectors(sector, Sectors2Read, true);
if (ProcessSubchannel(sector, Sectors2Read, pass == 0) == 0 && _subChannelMode != Device.SubChannelMode.None && sector == 0)
{
if (_debugMessages)
System.Console.WriteLine("\nGot no subchannel using ReadCD. Switching to ReadSubchannel.");
_subChannelMode = Device.SubChannelMode.None;
// TODO: move to TestReadCommand
FetchSectors(sector, Sectors2Read, true);
}
CorrectSectors(sector, Sectors2Read, pass > nPasses, pass == nPasses + nExtraPasses);
if (ReadProgress != null)
ReadProgress(this, new ReadProgressArgs(sector + Sectors2Read, pass, _currentStart, _currentEnd, _currentErrorsCount, PassTime));
}
//System.Console.WriteLine();
//if (CorrectSectorsTest(start, _currentEnd, 10, realData) == 0)
// break;
if (pass == nPasses + nExtraPasses)
break;
if (pass > nPasses)
{
int worstPass = -1;
for (int result = 0; result < _scanResults.Count; result++)
if (_scanResults[result].Quality < (worstPass < 0 ? _currentScan.Quality : _scanResults[worstPass].Quality))
worstPass = result;
//if (worstPass < 0)
// System.Console.WriteLine("bad scan");
//else
// System.Console.WriteLine("{0}->{1}, {2}->{3}", _scanResults[worstPass].Quality, _currentScan.Quality, CorrectSectorsTest(_currentStart, _currentEnd, 10, realData, -1), CorrectSectorsTest(_currentStart, _currentEnd, 10, realData, worstPass));
if (worstPass < 0)
_currentScan = null;
else else
_scanResults[worstPass] = _currentScan; {
for (int result = 0; result < _scanResults.Count; result++) _currentScan = 0;
_scanResults[result].Quality = 0; for (int result = 1; result < MAXSCANS; result++)
continue; if (Quality[result] < Quality[_currentScan])
} _currentScan = result;
if (_currentErrorsCount == 0 && pass >= _correctionQuality) //if (worstPass < 0)
{ // System.Console.WriteLine("bad scan");
bool syncOk = true; //else
//if (pass == 0) // System.Console.WriteLine("{0}->{1}, {2}->{3}", _scanResults[worstPass].Quality, _currentScan.Quality, CorrectSectorsTest(_currentStart, _currentEnd, 10, realData, -1), CorrectSectorsTest(_currentStart, _currentEnd, 10, realData, worstPass));
//{ }
// ScanResults saved = _currentScan; for (int result = 0; result < MAXSCANS; result++)
// _currentScan = new ScanResults(_currentEnd - _currentStart, CB_AUDIO); Quality[result] = 0;
// for (int sector = _currentStart; sector < _currentEnd && syncOk; sector += 7) _currentErrorsCount = 0;
// {
// FetchSectors(sector, 2); for (int sector = _currentStart; sector < _currentEnd; sector += m_max_sectors)
// for (int i = 0; i < 2 * CB_AUDIO; i++) {
// if (_currentScan.Data[(sector - _currentStart) * CB_AUDIO + i] != saved.Data[(sector - _currentStart) * CB_AUDIO + i]) int Sectors2Read = Math.Min(m_max_sectors, _currentEnd - sector);
// { int speed = pass == 5 ? 300 : pass == 6 ? 150 : pass == 7 ? 75 : 32500; // sectors per second
// System.Console.WriteLine("Lost Sync"); int msToSleep = 1000 * Sectors2Read / speed - (int)((DateTime.Now - LastFetch).TotalMilliseconds);
// syncOk = false;
// break; //if (msToSleep > 0) Thread.Sleep(msToSleep);
// } LastFetch = DateTime.Now;
// } FetchSectors(sector, Sectors2Read, true, pass == 0);
// _currentScan = saved; //TimeSpan delay1 = DateTime.Now - LastFetch;
//} if (pass == 0)
if (syncOk) ProcessSubchannel(sector, Sectors2Read, true);
//DateTime LastFetched = DateTime.Now;
CorrectSectors(Math.Min(pass, MAXSCANS - 1), sector, Sectors2Read, pass >= MAXSCANS - 1, pass == MAXSCANS - 1 + nExtraPasses);
//TimeSpan delay2 = DateTime.Now - LastFetched;
//if (sector == _currentStart)
//System.Console.WriteLine("\n{0},{1}", delay1.TotalMilliseconds, delay2.TotalMilliseconds);
if (ReadProgress != null)
ReadProgress(this, new ReadProgressArgs(sector + Sectors2Read, pass, _currentStart, _currentEnd, _currentErrorsCount, PassTime));
}
//System.Console.WriteLine();
//if (CorrectSectorsTest(start, _currentEnd, 10, realData) == 0)
// break;
//if (pass == MAXSCANS - 1 + nExtraPasses)
// break;
if (_currentErrorsCount == 0 && pass >= _correctionQuality)
break; break;
} //if (_currentErrorsCount == 0 && pass >= _correctionQuality)
_scanResults.Add(_currentScan); //{
// bool syncOk = true;
// //if (pass == 0)
// //{
// // ScanResults saved = _currentScan;
// // _currentScan = new ScanResults(_currentEnd - _currentStart, CB_AUDIO);
// // for (int sector = _currentStart; sector < _currentEnd && syncOk; sector += 7)
// // {
// // FetchSectors(sector, 2);
// // for (int i = 0; i < 2 * CB_AUDIO; i++)
// // if (_currentScan.Data[(sector - _currentStart) * CB_AUDIO + i] != saved.Data[(sector - _currentStart) * CB_AUDIO + i])
// // {
// // System.Console.WriteLine("Lost Sync");
// // syncOk = false;
// // break;
// // }
// // }
// // _currentScan = saved;
// //}
// if (syncOk)
// break;
//}
}
} }
_currentScan = null;
_scanResults = null;
} }
public uint Read(int[,] buff, uint sampleCount) public uint Read(int[,] buff, uint sampleCount)
@@ -806,9 +971,14 @@ namespace CUETools.Ripper.SCSI
} }
set set
{ {
if (_toc.AudioLength <= 0)
throw new Exception("no audio");
_currentTrack = -1; _currentTrack = -1;
_currentIndex = -1; _currentIndex = -1;
_sampleOffset = (int) value + _driveOffset; _crcErrorsCount = 0;
_errorsCount = 0;
_errors = new BitArray((int)_toc.AudioLength);
_sampleOffset = (int)value + _driveOffset;
} }
} }
@@ -873,24 +1043,12 @@ namespace CUETools.Ripper.SCSI
} }
} }
internal class ScanResults enum ReadCDCommand
{ {
public byte[,] UserData; ReadCdBEh,
public byte[,] C2Data; ReadCdD8h,
public byte[,] QData; Unknown
public long Quality; };
public ScanResults(int msector)
{
//byte[] a1 = new byte[msector * 4 * 588];
//byte[] a2 = new byte[msector * 294];
//byte[] a3 = new byte[msector * 16];
UserData = new byte[msector, 4 * 588];
C2Data = new byte[msector, 294];
QData = new byte[msector, 16];
Quality = 0;
}
}
public sealed class SCSIException : Exception public sealed class SCSIException : Exception
{ {

View File

@@ -348,6 +348,7 @@ namespace JDP {
outputExists = false; outputExists = false;
else if (dlgRes == DialogResult.Cancel || _batchPaths.Count == 0) else if (dlgRes == DialogResult.Cancel || _batchPaths.Count == 0)
{ {
cueSheet.Close();
_batchPaths.Clear(); _batchPaths.Clear();
SetupControls(false); SetupControls(false);
return; return;
@@ -413,6 +414,7 @@ namespace JDP {
}); });
} }
#endif #endif
cueSheet.Close();
if (_batchPaths.Count != 0) { if (_batchPaths.Count != 0) {
_batchPaths.RemoveAt(0); _batchPaths.RemoveAt(0);