diff --git a/Bwg.Scsi/Device.cs b/Bwg.Scsi/Device.cs
index f2a119b..1571e50 100644
--- a/Bwg.Scsi/Device.cs
+++ b/Bwg.Scsi/Device.cs
@@ -2131,11 +2131,31 @@ namespace Bwg.Scsi
return CommandStatus.Success;
}
+ public enum SubChannelMode
+ {
+ None,
+ QOnly, /// + 16 bytes
+ RWMode /// + 96 bytes
+ };
+
+ public enum C2ErrorMode
+ {
+ None,
+ Mode294, /// +294 bytes
+ Mode296, /// +296 bytes
+ };
+
+ public enum MainChannelSelection
+ {
+ UserData,
+ F8h
+ };
+
///
///
///
- /// subchannel mode (+16 bytes if equals 2)
- /// report C2 errors (+296 bytes if true)
+ /// subchannel mode
+ /// C2 errors report mode
/// expected sector type
///
///
@@ -2143,28 +2163,33 @@ namespace Bwg.Scsi
/// the memory area
/// the size of the memory area given by the data parameter
///
- public CommandStatus ReadCDAndSubChannel(byte mode, bool c2, byte exp, bool dap, uint start, uint length, IntPtr data, int size)
+ public CommandStatus ReadCDAndSubChannel(MainChannelSelection mainmode, SubChannelMode submode, C2ErrorMode c2mode, byte exp, bool dap, uint start, uint length, IntPtr data, int timeout)
{
if (m_logger != null)
{
- string args = exp.ToString() + ", " + dap.ToString() + ", " + start.ToString() + ", " + length.ToString() + ", data, " + size.ToString();
+ string args = exp.ToString() + ", " + dap.ToString() + ", " + start.ToString() + ", " + length.ToString() + ", data";
m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadCD(" + args + ")"));
}
- if (mode != 1 && mode != 2 && mode != 4)
- throw new Exception("invalid read mode for ReadSubchannel() call");
+ int size = (4 * 588 +
+ (submode == SubChannelMode.QOnly ? 16 : submode == SubChannelMode.RWMode ? 96 : 0) +
+ (c2mode == C2ErrorMode.Mode294 ? 294 : c2mode == C2ErrorMode.Mode296 ? 296 : 0)) * (int) length;
+
+ byte mode = (byte) (submode == SubChannelMode.QOnly ? 2 : submode == SubChannelMode.RWMode ? 4 : 0);
if (exp != 1 && exp != 2 && exp != 3 && exp != 4 && exp != 5)
return CommandStatus.NotSupported;
- using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, data, size, Command.CmdDirection.In, 5 * 60))
+ using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, data, size, Command.CmdDirection.In, timeout))
{
byte b = (byte)((exp & 0x07) << 2);
if (dap)
b |= 0x02;
- byte byte9 = 0x10;
- if (c2)
+ byte byte9 = (byte) (mainmode == MainChannelSelection.UserData ? 0x10 : 0xF8);
+ if (c2mode == C2ErrorMode.Mode294)
byte9 |= 0x02;
+ else if (c2mode == C2ErrorMode.Mode296)
+ byte9 |= 0x04;
cmd.SetCDB8(1, b);
cmd.SetCDB32(2, start);
cmd.SetCDB24(6, length);
@@ -2250,7 +2275,7 @@ namespace Bwg.Scsi
///
/// the subchannel mode
///
- public CommandStatus ReadSubChannel(byte mode, uint sector, uint length, ref byte[] data)
+ public CommandStatus ReadSubChannel(byte mode, uint sector, uint length, ref byte[] data, int timeout)
{
byte bytes_per_sector;
@@ -2271,7 +2296,7 @@ namespace Bwg.Scsi
throw new Exception("data buffer is not large enough to hold the data requested");
- using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, (int)(length * bytes_per_sector), Command.CmdDirection.In, 10 * 60))
+ using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, (int)(length * bytes_per_sector), Command.CmdDirection.In, timeout))
{
cmd.SetCDB32(2, sector); // The sector number to start with
cmd.SetCDB24(6, length); // The length in sectors
diff --git a/CUETools.Ripper.Console/Program.cs b/CUETools.Ripper.Console/Program.cs
index 26edf2e..08d0a8c 100644
--- a/CUETools.Ripper.Console/Program.cs
+++ b/CUETools.Ripper.Console/Program.cs
@@ -79,6 +79,7 @@ namespace CUERipper
Console.WriteLine("-P, --paranoid maximum level of error correction;");
Console.WriteLine("-D, --drive use a specific CD drive, e.g. {0};", drives);
Console.WriteLine("-O, --offset use specific drive read offset;");
+ Console.WriteLine("-T, --test detect read command;");
}
static void Main(string[] args)
@@ -92,11 +93,14 @@ namespace CUERipper
int correctionQuality = 1;
string driveLetter = null;
int driveOffset = 0;
+ bool test = false;
for (int arg = 0; arg < args.Length; arg++)
{
bool ok = true;
if (args[arg] == "-P" || args[arg] == "--paranoid")
correctionQuality = 4;
+ if (args[arg] == "-T" || args[arg] == "--test")
+ test = true;
//else if (args[arg] == "-B" || args[arg] == "--burst")
// correctionQuality = 1;
else if ((args[arg] == "-D" || args[arg] == "--drive") && ++arg < args.Length)
@@ -145,8 +149,14 @@ namespace CUERipper
if (!AccurateRipVerify.FindDriveReadOffset(audioSource.ARName, out driveOffset))
Console.WriteLine("Unknown read offset for drive {0}!!!", audioSource.Path);
//throw new Exception("Failed to find drive read offset for drive" + audioSource.ARName);
+ if (test)
+ {
+ Console.Write(audioSource.TestReadCommand());
+ return;
+ }
audioSource.DriveOffset = driveOffset;
audioSource.CorrectionQuality = correctionQuality;
+ audioSource.DebugMessages = true;
AccurateRipVerify arVerify = new AccurateRipVerify(audioSource.TOC);
int[,] buff = new int[audioSource.BestBlockSize, audioSource.ChannelCount];
diff --git a/CUETools.Ripper.SCSI/SCSIDrive.cs b/CUETools.Ripper.SCSI/SCSIDrive.cs
index 4676b11..390af4c 100644
--- a/CUETools.Ripper.SCSI/SCSIDrive.cs
+++ b/CUETools.Ripper.SCSI/SCSIDrive.cs
@@ -30,6 +30,7 @@ using Bwg.Scsi;
using Bwg.Logging;
using CUETools.CDImage;
using CUETools.Codecs;
+using System.Threading;
namespace CUETools.Ripper.SCSI
{
@@ -44,24 +45,26 @@ namespace CUETools.Ripper.SCSI
int _driveOffset = 0;
int _correctionQuality = 1;
int _currentStart = -1, _currentEnd = -1, _currentErrorsCount = 0;
- const bool DoC2 = true;
- const int CB_AUDIO = 588 * 4 + 16 + (DoC2 ? 294 : 0);
- //const int REDUNDANCY = 8;
- const int NSECTORS = 64; //255 - REDUNDANCY;
+ const int CB_AUDIO = 588 * 4 + 2 + 294 + 16;
+ const int NSECTORS = 32;
const int MSECTORS = 10000000 / CB_AUDIO;
int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1;
Logger m_logger;
CDImageLayout _toc;
DeviceInfo m_info;
Crc16Ccitt _crc;
- //RsEncode _rsEncoder;
- //RsDecode _rsDecoder;
List _scanResults;
ScanResults _currentScan;
BitArray _errors;
int _errorsCount;
byte[] _currentData = new byte[MSECTORS * 4 * 588];
int[] valueScore = new int[256];
+ bool _debugMessages = false;
+ Device.MainChannelSelection _mainChannelMode = Device.MainChannelSelection.UserData;
+ Device.SubChannelMode _subChannelMode = Device.SubChannelMode.None;
+ Device.C2ErrorMode _c2ErrorMode = Device.C2ErrorMode.Mode296;
+ byte[] _readBuffer = new byte[NSECTORS * CB_AUDIO];
+ byte[] _subchannelBuffer = new byte[NSECTORS * 16];
public event EventHandler ReadProgress;
@@ -89,12 +92,22 @@ namespace CUETools.Ripper.SCSI
}
}
+ public bool DebugMessages
+ {
+ get
+ {
+ return _debugMessages;
+ }
+ set
+ {
+ _debugMessages = value;
+ }
+ }
+
public CDDriveReader()
{
m_logger = new Logger();
_crc = new Crc16Ccitt(InitialCrcValue.Zeros);
- //_rsEncoder = new RsEncode(REDUNDANCY);
- //_rsDecoder = new RsDecode(REDUNDANCY);
}
public bool Open(char Drive)
@@ -186,8 +199,9 @@ namespace CUETools.Ripper.SCSI
}
}
- private void ProcessSubchannel(int sector, int Sectors2Read, bool updateMap)
+ private int ProcessSubchannel(int sector, int Sectors2Read, bool updateMap)
{
+ int posCount = 0;
for (int iSector = 0; iSector < Sectors2Read; iSector++)
{
int q_pos = (sector - _currentStart + iSector + 1) * CB_AUDIO - 16;
@@ -205,27 +219,32 @@ namespace CUETools.Ripper.SCSI
int ff = fromBCD(_currentScan.Data[q_pos + 9]);
int sec = ff + 75 * (ss + 60 * mm) - 150; // 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);
- //ushort crc = _crc.ComputeChecksum(_currentScan.Data, q_pos, 10);
- //crc ^= 0xffff;
- //if (_currentScan.Data[q_pos + 10] != 0 && _currentScan.Data[q_pos + 11] != 0 &&
- // ((crc & 0xff) != _currentScan.Data[q_pos + 11] ||
- // (crc >> 8) != _currentScan.Data[q_pos + 10])
- // )
- //{
- // System.Console.WriteLine("CRC error at {0}", CDImageLayout.TimeToString((uint)(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);
+ ushort crc = _crc.ComputeChecksum(_currentScan.Data, q_pos, 10);
+ crc ^= 0xffff;
+ if (_currentScan.Data[q_pos + 10] != 0 && _currentScan.Data[q_pos + 11] != 0 &&
+ ((crc & 0xff) != _currentScan.Data[q_pos + 11] ||
+ (crc >> 8) != _currentScan.Data[q_pos + 10])
+ )
+ {
+ if (_debugMessages)
+ System.Console.WriteLine("\nCRC error at {0}", CDImageLayout.TimeToString((uint)(sector + iSector)));
+ continue;
+ }
if (iTrack == 110)
{
if (sector + iSector + 75 < _toc.AudioLength)
throw new Exception("lead out area encountred");
// make sure that data is zero?
- return;
+ return posCount;
}
if (iTrack == 0)
throw new Exception("lead in area encountred");
+ posCount++;
if (!updateMap)
break;
+ if (iTrack > _toc.AudioTracks)
+ throw new Exception("strange track number encountred");
if (iTrack != _currentTrack)
{
_currentTrack = iTrack;
@@ -265,13 +284,12 @@ namespace CUETools.Ripper.SCSI
if (_toc[_currentTrack].ISRC == null)
{
StringBuilder isrc = new StringBuilder();
- char[] ISRC6 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '#', '#', '#', '#', '#', '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
- isrc.Append(ISRC6[_currentScan.Data[q_pos + 1] >> 2]);
- isrc.Append(ISRC6[((_currentScan.Data[q_pos + 1] & 0x3) << 4) + (_currentScan.Data[q_pos + 2] >> 4)]);
- isrc.Append(ISRC6[((_currentScan.Data[q_pos + 2] & 0xf) << 2) + (_currentScan.Data[q_pos + 3] >> 6)]);
- isrc.Append(ISRC6[(_currentScan.Data[q_pos + 3] & 0x3f)]);
- isrc.Append(ISRC6[_currentScan.Data[q_pos + 4] >> 2]);
- isrc.Append(ISRC6[((_currentScan.Data[q_pos + 4] & 0x3) << 4) + (_currentScan.Data[q_pos + 5] >> 4)]);
+ isrc.Append(from6bit(_currentScan.Data[q_pos + 1] >> 2));
+ isrc.Append(from6bit(((_currentScan.Data[q_pos + 1] & 0x3) << 4) + (0x0f & (_currentScan.Data[q_pos + 2] >> 4))));
+ isrc.Append(from6bit(((_currentScan.Data[q_pos + 2] & 0xf) << 2) + (0x03 & (_currentScan.Data[q_pos + 3] >> 6))));
+ isrc.Append(from6bit((_currentScan.Data[q_pos + 3] & 0x3f)));
+ isrc.Append(from6bit(_currentScan.Data[q_pos + 4] >> 2));
+ isrc.Append(from6bit(((_currentScan.Data[q_pos + 4] & 0x3) << 4) + (0x0f & (_currentScan.Data[q_pos + 5] >> 4))));
isrc.AppendFormat("{0:x}", _currentScan.Data[q_pos + 5] & 0xf);
isrc.AppendFormat("{0:x2}", _currentScan.Data[q_pos + 6]);
isrc.AppendFormat("{0:x2}", _currentScan.Data[q_pos + 7]);
@@ -281,11 +299,57 @@ namespace CUETools.Ripper.SCSI
break;
}
}
+ return posCount;
+ }
+
+ public unsafe string TestReadCommand()
+ {
+ byte[] test = new byte[CB_AUDIO];
+ string s = "";
+ fixed (byte* data = test)
+ {
+ for (int m = 0; m <= 1; m++)
+ for (int q = 0; q <= 2; q++)
+ for (int c = 0; c <= 2; c++)
+ {
+ Device.MainChannelSelection[] mainmode = { Device.MainChannelSelection.UserData, Device.MainChannelSelection.F8h };
+ Device.SubChannelMode[] submode = { Device.SubChannelMode.None, Device.SubChannelMode.QOnly, Device.SubChannelMode.RWMode };
+ Device.C2ErrorMode[] c2mode = { Device.C2ErrorMode.None, Device.C2ErrorMode.Mode294, Device.C2ErrorMode.Mode296 };
+ Device.CommandStatus st = m_device.ReadCDAndSubChannel(mainmode[m], submode[q], c2mode[c], 1, false, (uint)0, (uint)1, (IntPtr)((void*)data), 3);
+ s += string.Format("M{0}Q{1}C{2}: {3}\n", m, q, c, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
+ }
+ }
+ return s;
+ }
+
+
+ private void ReorganiseSectors(int sector, int Sectors2Read)
+ {
+ if (_subChannelMode == Device.SubChannelMode.QOnly && _c2ErrorMode == Device.C2ErrorMode.Mode296)
+ {
+ Array.Copy(_readBuffer, 0, _currentScan.Data, (sector - _currentStart) * CB_AUDIO, Sectors2Read * CB_AUDIO);
+ return;
+ }
+ // fill Q subchannel
+ if (_subChannelMode == Device.SubChannelMode.None)
+ {
+ Device.CommandStatus st = m_device.ReadSubChannel(2, (uint)sector, (uint)Sectors2Read, ref _subchannelBuffer, 10);
+ if (st != Device.CommandStatus.Success)
+ throw new Exception("ReadSubChannel: " + (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
+ for (int iSector = 0; iSector < Sectors2Read; iSector++)
+ Array.Copy(_subchannelBuffer, iSector * 16, _currentScan.Data, (sector - _currentStart + iSector + 1) * CB_AUDIO - 16, 16);
+ }
+ int c2Size = _c2ErrorMode == Device.C2ErrorMode.None ? 0 : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : 296;
+ int oldSize = 4 * 588 + c2Size + (_subChannelMode == Device.SubChannelMode.None ? 0 : 16);
+ // fill Data & C2
+ // TODO: handle other c2 modes here...
+ for (int iSector = 0; iSector < Sectors2Read; iSector++)
+ Array.Copy(_readBuffer, iSector * oldSize, _currentScan.Data, (sector - _currentStart + iSector) * CB_AUDIO, 4 * 588 + 296);
}
private unsafe void FetchSectors(int sector, int Sectors2Read)
{
- fixed (byte* data = _currentScan.Data)
+ fixed (byte* data = _readBuffer)
{
//Device.CommandStatus st;
//using (Command cmd = new Command(ScsiCommandCode.Read12, 12, (IntPtr)((void*)data), Sectors2Read * 588 * 4, Command.CmdDirection.In, 5 * 60))
@@ -296,42 +360,46 @@ namespace CUETools.Ripper.SCSI
// //cmd.SetCDB8(10, 0x80); // streaming
// st= m_device.SendCommand(cmd);
//}
- Device.CommandStatus st = m_device.ReadCDAndSubChannel(2, DoC2, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)(data + (sector - _currentStart) * CB_AUDIO)), Sectors2Read * CB_AUDIO);
- if (st != Device.CommandStatus.Success)
+ Device.CommandStatus st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)data), 10);
+ if (st == Device.CommandStatus.Success)
{
- if (st == Device.CommandStatus.DeviceFailed && m_device.GetSenseAsc() == 0x64 && m_device.GetSenseAscq() == 0x00)
- {
- int iErrors = 0;
- for (int iSector = 0; iSector < Sectors2Read; iSector++)
- {
- st = m_device.ReadCDAndSubChannel(2, DoC2, 1, false, (uint)(sector + iSector), 1U, (IntPtr)((void*)(data + (sector + iSector - _currentStart) * CB_AUDIO)), CB_AUDIO);
- if (st != Device.CommandStatus.Success)
- {
- iErrors ++;
- for (int iPos = 0; iPos < CB_AUDIO; iPos++)
- data[(sector + iSector - _currentStart) * CB_AUDIO + iPos] = (DoC2 && iPos >= 4 * 588 && iPos < 4 * 588 + 294) ? (byte)255 : (byte)0;
- }
- }
- if (iErrors < Sectors2Read)
- return;
- }
- string status = (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString());
- st = m_device.ReadCDAndSubChannel(0, false, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)(data + (sector - _currentStart) * 4 * 588)), Sectors2Read * 4 * 588);
- if (st != Device.CommandStatus.Success)
- status += "; ReadWithoutSubchannel: " + (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString());
- else
- status += "; ReadWithoutSubchannel: might work";
- throw new Exception("ReadCD: " + status);
+ ReorganiseSectors(sector, Sectors2Read);
+ return;
}
-
- //int localC2 = 0;
- //if (DoC2)
- // for (int iSector = 0; iSector < Sectors2Read; iSector++)
- // {
- // _currentScan.C2Errors[sector + iSector] = data[(iSector + 1) * CB_AUDIO - 18] != 0;
- // localC2 += (data[(iSector + 1) * CB_AUDIO - 18] != 0) ? 1 : 0;
- // }
- //_currentScan.C2Count += localC2;
+ if (sector == 0 && _subChannelMode != Device.SubChannelMode.None)
+ {
+ _subChannelMode = Device.SubChannelMode.None;
+ if (_debugMessages)
+ System.Console.WriteLine("\nFailed to read CD data with subchannel. Switching to ReadCD without subchannel + ReadSubchannel.");
+ st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)data), 10);
+ if (st == Device.CommandStatus.Success)
+ {
+ ReorganiseSectors(sector, Sectors2Read);
+ return;
+ }
+ }
+ if (sector != 0 && st == Device.CommandStatus.DeviceFailed && m_device.GetSenseAsc() == 0x64 && m_device.GetSenseAscq() == 0x00)
+ {
+ int iErrors = 0;
+ for (int iSector = 0; iSector < Sectors2Read; iSector++)
+ {
+ st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)(sector + iSector), 1U, (IntPtr)((void*)data), 5);
+ if (st != Device.CommandStatus.Success)
+ {
+ iErrors ++;
+ for (int iPos = 0; iPos < CB_AUDIO; iPos++)
+ _currentScan.Data[(sector + iSector - _currentStart) * CB_AUDIO + iPos] = (iPos == 4 * 588 || (iPos >= 4 * 588 + 2 && iPos < 4 * 588 + 2 + 294)) ? (byte)255 : (byte)0;
+ if (_debugMessages)
+ System.Console.WriteLine("\nSector lost");
+ } else
+ ReorganiseSectors(sector+iSector, 1);
+ }
+ if (iErrors < Sectors2Read)
+ return;
+ }
+ string status = (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString());
+ string test = TestReadCommand();
+ throw new Exception("ReadCD: " + status + "; Autodetect: " + test);
}
}
@@ -343,7 +411,7 @@ namespace CUETools.Ripper.SCSI
for (int iPar = 0; iPar < 4 * 588; iPar++)
{
int dataPos = (sector - _currentStart + iSector) * CB_AUDIO + iPar;
- int c2Pos = (sector - _currentStart + iSector) * CB_AUDIO + 4 * 588 + iPar / 8;
+ int c2Pos = (sector - _currentStart + iSector) * CB_AUDIO + 2 + 4 * 588 + iPar / 8;
int c2Bit = 0x80 >> (iPar % 8);
Array.Clear(valueScore, 0, 256);
@@ -391,7 +459,7 @@ namespace CUETools.Ripper.SCSI
// for (int iPar = 0; iPar < 4 * 588; iPar++)
// {
// int dataPos = iSector * CB_AUDIO + iPar;
- // int c2Pos = iSector * CB_AUDIO + 4 * 588 + iPar / 8;
+ // int c2Pos = iSector * CB_AUDIO + 2 + 4 * 588 + iPar / 8;
// int c2Bit = 0x80 >> (iPar % 8);
// Array.Clear(valueScore, 0, 256);
@@ -453,16 +521,27 @@ namespace CUETools.Ripper.SCSI
for (int pass = 0; pass <= nPasses + nExtraPasses; pass++)
{
- DateTime PassTime = DateTime.Now;
+ DateTime PassTime = DateTime.Now, LastFetch = DateTime.Now;
_currentScan = new ScanResults(MSECTORS, CB_AUDIO);
_currentErrorsCount = 0;
int nSectors = Math.Min(NSECTORS, m_device.MaximumTransferLength / CB_AUDIO - 1);
for (int sector = _currentStart; sector < _currentEnd; sector += nSectors)
{
int Sectors2Read = Math.Min(nSectors, _currentEnd - sector);
+ int speed = pass == 4 || pass == 5 ? 4 : pass == 8 || pass == 9 ? 2 : pass == 17 || pass == 18 ? 1 : 0;
+ if (speed != 0)
+ Thread.Sleep(Math.Max(1, 1000 * nSectors / (75 * speed) - (int)((DateTime.Now - LastFetch).TotalMilliseconds)));
+ LastFetch = DateTime.Now;
FetchSectors(sector, Sectors2Read);
+
+ 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;
+ FetchSectors(sector, Sectors2Read);
+ }
CorrectSectors(sector, Sectors2Read, pass > nPasses, pass == nPasses + nExtraPasses);
- ProcessSubchannel(sector, Sectors2Read, pass == 0);
if (ReadProgress != null)
ReadProgress(this, new ReadProgressArgs(sector + Sectors2Read, pass, _currentStart, _currentEnd, _currentErrorsCount, PassTime));
}
@@ -699,6 +778,13 @@ namespace CUETools.Ripper.SCSI
return (hex >> 4) * 10 + (hex & 15);
}
+ private char from6bit(int bcd)
+ {
+ char[] ISRC6 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '#', '#', '#', '#', '#', '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
+ bcd &= 0x3f;
+ return bcd >= ISRC6.Length ? '#' : ISRC6[bcd];
+ }
+
public static char[] DrivesAvailable()
{
List result = new List();