More robustness to ripper

This commit is contained in:
chudov
2008-12-07 00:33:20 +00:00
parent 764f9f2368
commit 3fd37e6afe
3 changed files with 198 additions and 77 deletions

View File

@@ -2131,11 +2131,31 @@ namespace Bwg.Scsi
return CommandStatus.Success; 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
};
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="mode">subchannel mode (+16 bytes if equals 2)</param> /// <param name="submode">subchannel mode</param>
/// <param name="c2">report C2 errors (+296 bytes if true)</param> /// <param name="c2mode">C2 errors report mode</param>
/// <param name="exp">expected sector type</param> /// <param name="exp">expected sector type</param>
/// <param name="dap"></param> /// <param name="dap"></param>
/// <param name="start"></param> /// <param name="start"></param>
@@ -2143,28 +2163,33 @@ namespace Bwg.Scsi
/// <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="size">the size of the memory area given by the data parameter</param>
/// <returns></returns> /// <returns></returns>
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) 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 + ")")); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadCD(" + args + ")"));
} }
if (mode != 1 && mode != 2 && mode != 4) int size = (4 * 588 +
throw new Exception("invalid read mode for ReadSubchannel() call"); (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) if (exp != 1 && exp != 2 && exp != 3 && exp != 4 && exp != 5)
return CommandStatus.NotSupported; 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); byte b = (byte)((exp & 0x07) << 2);
if (dap) if (dap)
b |= 0x02; b |= 0x02;
byte byte9 = 0x10; byte byte9 = (byte) (mainmode == MainChannelSelection.UserData ? 0x10 : 0xF8);
if (c2) if (c2mode == C2ErrorMode.Mode294)
byte9 |= 0x02; byte9 |= 0x02;
else if (c2mode == C2ErrorMode.Mode296)
byte9 |= 0x04;
cmd.SetCDB8(1, b); cmd.SetCDB8(1, b);
cmd.SetCDB32(2, start); cmd.SetCDB32(2, start);
cmd.SetCDB24(6, length); cmd.SetCDB24(6, length);
@@ -2250,7 +2275,7 @@ namespace Bwg.Scsi
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="mode">the subchannel mode</param> /// <param name="mode">the subchannel mode</param>
/// <returns></returns> /// <returns></returns>
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; 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"); 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.SetCDB32(2, sector); // The sector number to start with
cmd.SetCDB24(6, length); // The length in sectors cmd.SetCDB24(6, length); // The length in sectors

View File

@@ -79,6 +79,7 @@ namespace CUERipper
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;");
} }
static void Main(string[] args) static void Main(string[] args)
@@ -92,11 +93,14 @@ namespace CUERipper
int correctionQuality = 1; int correctionQuality = 1;
string driveLetter = null; string driveLetter = null;
int driveOffset = 0; int driveOffset = 0;
bool test = 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")
test = true;
//else if (args[arg] == "-B" || args[arg] == "--burst") //else if (args[arg] == "-B" || args[arg] == "--burst")
// correctionQuality = 1; // correctionQuality = 1;
else if ((args[arg] == "-D" || args[arg] == "--drive") && ++arg < args.Length) else if ((args[arg] == "-D" || args[arg] == "--drive") && ++arg < args.Length)
@@ -145,8 +149,14 @@ namespace CUERipper
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.TestReadCommand());
return;
}
audioSource.DriveOffset = driveOffset; audioSource.DriveOffset = driveOffset;
audioSource.CorrectionQuality = correctionQuality; audioSource.CorrectionQuality = correctionQuality;
audioSource.DebugMessages = true;
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];

View File

@@ -30,6 +30,7 @@ using Bwg.Scsi;
using Bwg.Logging; using Bwg.Logging;
using CUETools.CDImage; using CUETools.CDImage;
using CUETools.Codecs; using CUETools.Codecs;
using System.Threading;
namespace CUETools.Ripper.SCSI namespace CUETools.Ripper.SCSI
{ {
@@ -44,24 +45,26 @@ namespace CUETools.Ripper.SCSI
int _driveOffset = 0; int _driveOffset = 0;
int _correctionQuality = 1; int _correctionQuality = 1;
int _currentStart = -1, _currentEnd = -1, _currentErrorsCount = 0; int _currentStart = -1, _currentEnd = -1, _currentErrorsCount = 0;
const bool DoC2 = true; const int CB_AUDIO = 588 * 4 + 2 + 294 + 16;
const int CB_AUDIO = 588 * 4 + 16 + (DoC2 ? 294 : 0); const int NSECTORS = 32;
//const int REDUNDANCY = 8;
const int NSECTORS = 64; //255 - REDUNDANCY;
const int MSECTORS = 10000000 / CB_AUDIO; const int MSECTORS = 10000000 / CB_AUDIO;
int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1; int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1;
Logger m_logger; Logger m_logger;
CDImageLayout _toc; CDImageLayout _toc;
DeviceInfo m_info; DeviceInfo m_info;
Crc16Ccitt _crc; Crc16Ccitt _crc;
//RsEncode _rsEncoder;
//RsDecode _rsDecoder;
List<ScanResults> _scanResults; List<ScanResults> _scanResults;
ScanResults _currentScan; ScanResults _currentScan;
BitArray _errors; BitArray _errors;
int _errorsCount; int _errorsCount;
byte[] _currentData = new byte[MSECTORS * 4 * 588]; byte[] _currentData = new byte[MSECTORS * 4 * 588];
int[] valueScore = new int[256]; 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<ReadProgressArgs> ReadProgress; public event EventHandler<ReadProgressArgs> ReadProgress;
@@ -89,12 +92,22 @@ namespace CUETools.Ripper.SCSI
} }
} }
public bool DebugMessages
{
get
{
return _debugMessages;
}
set
{
_debugMessages = value;
}
}
public CDDriveReader() public CDDriveReader()
{ {
m_logger = new Logger(); m_logger = new Logger();
_crc = new Crc16Ccitt(InitialCrcValue.Zeros); _crc = new Crc16Ccitt(InitialCrcValue.Zeros);
//_rsEncoder = new RsEncode(REDUNDANCY);
//_rsDecoder = new RsDecode(REDUNDANCY);
} }
public bool Open(char Drive) 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++) for (int iSector = 0; iSector < Sectors2Read; iSector++)
{ {
int q_pos = (sector - _currentStart + iSector + 1) * CB_AUDIO - 16; int q_pos = (sector - _currentStart + iSector + 1) * CB_AUDIO - 16;
@@ -206,26 +220,31 @@ namespace CUETools.Ripper.SCSI
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);
//ushort crc = _crc.ComputeChecksum(_currentScan.Data, q_pos, 10); ushort crc = _crc.ComputeChecksum(_currentScan.Data, q_pos, 10);
//crc ^= 0xffff; crc ^= 0xffff;
//if (_currentScan.Data[q_pos + 10] != 0 && _currentScan.Data[q_pos + 11] != 0 && if (_currentScan.Data[q_pos + 10] != 0 && _currentScan.Data[q_pos + 11] != 0 &&
// ((crc & 0xff) != _currentScan.Data[q_pos + 11] || ((crc & 0xff) != _currentScan.Data[q_pos + 11] ||
// (crc >> 8) != _currentScan.Data[q_pos + 10]) (crc >> 8) != _currentScan.Data[q_pos + 10])
// ) )
//{ {
// System.Console.WriteLine("CRC error at {0}", CDImageLayout.TimeToString((uint)(sector + iSector))); if (_debugMessages)
//} System.Console.WriteLine("\nCRC error at {0}", CDImageLayout.TimeToString((uint)(sector + iSector)));
continue;
}
if (iTrack == 110) if (iTrack == 110)
{ {
if (sector + iSector + 75 < _toc.AudioLength) if (sector + iSector + 75 < _toc.AudioLength)
throw new Exception("lead out area encountred"); throw new Exception("lead out area encountred");
// make sure that data is zero? // make sure that data is zero?
return; return posCount;
} }
if (iTrack == 0) if (iTrack == 0)
throw new Exception("lead in area encountred"); throw new Exception("lead in area encountred");
posCount++;
if (!updateMap) if (!updateMap)
break; break;
if (iTrack > _toc.AudioTracks)
throw new Exception("strange track number encountred");
if (iTrack != _currentTrack) if (iTrack != _currentTrack)
{ {
_currentTrack = iTrack; _currentTrack = iTrack;
@@ -265,13 +284,12 @@ namespace CUETools.Ripper.SCSI
if (_toc[_currentTrack].ISRC == null) if (_toc[_currentTrack].ISRC == null)
{ {
StringBuilder isrc = new StringBuilder(); 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(from6bit(_currentScan.Data[q_pos + 1] >> 2));
isrc.Append(ISRC6[_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(ISRC6[((_currentScan.Data[q_pos + 1] & 0x3) << 4) + (_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(ISRC6[((_currentScan.Data[q_pos + 2] & 0xf) << 2) + (_currentScan.Data[q_pos + 3] >> 6)]); isrc.Append(from6bit((_currentScan.Data[q_pos + 3] & 0x3f)));
isrc.Append(ISRC6[(_currentScan.Data[q_pos + 3] & 0x3f)]); isrc.Append(from6bit(_currentScan.Data[q_pos + 4] >> 2));
isrc.Append(ISRC6[_currentScan.Data[q_pos + 4] >> 2]); isrc.Append(from6bit(((_currentScan.Data[q_pos + 4] & 0x3) << 4) + (0x0f & (_currentScan.Data[q_pos + 5] >> 4))));
isrc.Append(ISRC6[((_currentScan.Data[q_pos + 4] & 0x3) << 4) + (_currentScan.Data[q_pos + 5] >> 4)]);
isrc.AppendFormat("{0:x}", _currentScan.Data[q_pos + 5] & 0xf); 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 + 6]);
isrc.AppendFormat("{0:x2}", _currentScan.Data[q_pos + 7]); isrc.AppendFormat("{0:x2}", _currentScan.Data[q_pos + 7]);
@@ -281,11 +299,57 @@ namespace CUETools.Ripper.SCSI
break; 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) private unsafe void FetchSectors(int sector, int Sectors2Read)
{ {
fixed (byte* data = _currentScan.Data) fixed (byte* data = _readBuffer)
{ {
//Device.CommandStatus st; //Device.CommandStatus st;
//using (Command cmd = new Command(ScsiCommandCode.Read12, 12, (IntPtr)((void*)data), Sectors2Read * 588 * 4, Command.CmdDirection.In, 5 * 60)) //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 // //cmd.SetCDB8(10, 0x80); // streaming
// st= m_device.SendCommand(cmd); // 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); 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.Success)
{ {
if (st == Device.CommandStatus.DeviceFailed && m_device.GetSenseAsc() == 0x64 && m_device.GetSenseAscq() == 0x00) ReorganiseSectors(sector, Sectors2Read);
return;
}
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; int iErrors = 0;
for (int iSector = 0; iSector < Sectors2Read; iSector++) 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); st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)(sector + iSector), 1U, (IntPtr)((void*)data), 5);
if (st != Device.CommandStatus.Success) if (st != Device.CommandStatus.Success)
{ {
iErrors ++; iErrors ++;
for (int iPos = 0; iPos < CB_AUDIO; iPos++) 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; _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) if (iErrors < Sectors2Read)
return; return;
} }
string status = (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()); 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); string test = TestReadCommand();
if (st != Device.CommandStatus.Success) throw new Exception("ReadCD: " + status + "; Autodetect: " + test);
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);
}
//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;
} }
} }
@@ -343,7 +411,7 @@ namespace CUETools.Ripper.SCSI
for (int iPar = 0; iPar < 4 * 588; iPar++) for (int iPar = 0; iPar < 4 * 588; iPar++)
{ {
int dataPos = (sector - _currentStart + iSector) * CB_AUDIO + 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); int c2Bit = 0x80 >> (iPar % 8);
Array.Clear(valueScore, 0, 256); Array.Clear(valueScore, 0, 256);
@@ -391,7 +459,7 @@ namespace CUETools.Ripper.SCSI
// for (int iPar = 0; iPar < 4 * 588; iPar++) // for (int iPar = 0; iPar < 4 * 588; iPar++)
// { // {
// int dataPos = iSector * CB_AUDIO + 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); // int c2Bit = 0x80 >> (iPar % 8);
// Array.Clear(valueScore, 0, 256); // Array.Clear(valueScore, 0, 256);
@@ -453,16 +521,27 @@ namespace CUETools.Ripper.SCSI
for (int pass = 0; pass <= nPasses + nExtraPasses; pass++) 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); _currentScan = new ScanResults(MSECTORS, CB_AUDIO);
_currentErrorsCount = 0; _currentErrorsCount = 0;
int nSectors = Math.Min(NSECTORS, m_device.MaximumTransferLength / CB_AUDIO - 1); int nSectors = Math.Min(NSECTORS, m_device.MaximumTransferLength / CB_AUDIO - 1);
for (int sector = _currentStart; sector < _currentEnd; sector += nSectors) for (int sector = _currentStart; sector < _currentEnd; sector += nSectors)
{ {
int Sectors2Read = Math.Min(nSectors, _currentEnd - sector); 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); 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); CorrectSectors(sector, Sectors2Read, pass > nPasses, pass == nPasses + nExtraPasses);
ProcessSubchannel(sector, Sectors2Read, pass == 0);
if (ReadProgress != null) if (ReadProgress != null)
ReadProgress(this, new ReadProgressArgs(sector + Sectors2Read, pass, _currentStart, _currentEnd, _currentErrorsCount, PassTime)); 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); 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() public static char[] DrivesAvailable()
{ {
List<char> result = new List<char>(); List<char> result = new List<char>();