mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
More robustness to ripper
This commit is contained in:
@@ -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
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="mode">subchannel mode (+16 bytes if equals 2)</param>
|
||||
/// <param name="c2">report C2 errors (+296 bytes if true)</param>
|
||||
/// <param name="submode">subchannel mode</param>
|
||||
/// <param name="c2mode">C2 errors report mode</param>
|
||||
/// <param name="exp">expected sector type</param>
|
||||
/// <param name="dap"></param>
|
||||
/// <param name="start"></param>
|
||||
@@ -2143,28 +2163,33 @@ namespace Bwg.Scsi
|
||||
/// <param name="data">the memory area </param>
|
||||
/// <param name="size">the size of the memory area given by the data parameter</param>
|
||||
/// <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)
|
||||
{
|
||||
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
|
||||
/// <param name="data"></param>
|
||||
/// <param name="mode">the subchannel mode</param>
|
||||
/// <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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace CUERipper
|
||||
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("-O, --offset <samples> 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];
|
||||
|
||||
@@ -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;
|
||||
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<ReadProgressArgs> 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;
|
||||
@@ -206,26 +220,31 @@ namespace CUETools.Ripper.SCSI
|
||||
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)));
|
||||
//}
|
||||
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)
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
_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());
|
||||
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);
|
||||
}
|
||||
|
||||
//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;
|
||||
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<char> result = new List<char>();
|
||||
|
||||
Reference in New Issue
Block a user