mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
CUERipper update;
CTDB xml interface; Minor bugfixes; Version 2.0.6-2.0.7
This commit is contained in:
@@ -52,6 +52,7 @@ namespace CUETools.Ripper.SCSI
|
||||
int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1;
|
||||
Logger m_logger;
|
||||
CDImageLayout _toc;
|
||||
CDImageLayout _toc2;
|
||||
char m_device_letter;
|
||||
InquiryResult m_inqury_result;
|
||||
int m_max_sectors;
|
||||
@@ -59,7 +60,6 @@ namespace CUETools.Ripper.SCSI
|
||||
Crc16Ccitt _crc;
|
||||
public long[,,] UserData;
|
||||
public byte[,] C2Count;
|
||||
public byte[,] QData;
|
||||
public long[] byte2long;
|
||||
BitArray _errors;
|
||||
int _errorsCount;
|
||||
@@ -70,20 +70,20 @@ namespace CUETools.Ripper.SCSI
|
||||
ReadCDCommand _readCDCommand = ReadCDCommand.Unknown;
|
||||
ReadCDCommand _forceReadCommand = ReadCDCommand.Unknown;
|
||||
Device.MainChannelSelection _mainChannelMode = Device.MainChannelSelection.UserData;
|
||||
Device.SubChannelMode _subChannelMode = Device.SubChannelMode.QOnly;
|
||||
Device.C2ErrorMode _c2ErrorMode = Device.C2ErrorMode.Mode296;
|
||||
string _autodetectResult;
|
||||
byte[] _readBuffer = new byte[NSECTORS * CB_AUDIO];
|
||||
byte[] _subchannelBuffer = new byte[NSECTORS * 16];
|
||||
byte[] _subchannelBuffer = new byte[CB_AUDIO];
|
||||
bool _qChannelInBCD = true;
|
||||
|
||||
private ReadProgressArgs progressArgs = new ReadProgressArgs();
|
||||
public event EventHandler<ReadProgressArgs> ReadProgress;
|
||||
|
||||
public CDImageLayout TOC
|
||||
{
|
||||
get
|
||||
{
|
||||
return _toc;
|
||||
return gapsDetected && _toc2 != null ? _toc2 : _toc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,11 +131,8 @@ namespace CUETools.Ripper.SCSI
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_autodetectResult != null || TestReadCommand())
|
||||
return _autodetectResult;
|
||||
string ret = _autodetectResult;
|
||||
_autodetectResult = null;
|
||||
return ret;
|
||||
TestReadCommand();
|
||||
return _autodetectResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +170,7 @@ namespace CUETools.Ripper.SCSI
|
||||
(_readCDCommand == ReadCDCommand.ReadCdBEh ? "BEh" : "D8h"),
|
||||
(_mainChannelMode == Device.MainChannelSelection.UserData ? 0x10 : 0xF8) +
|
||||
(_c2ErrorMode == Device.C2ErrorMode.None ? 0 : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? 2 : 4),
|
||||
(_subChannelMode == Device.SubChannelMode.None ? "00h" : _subChannelMode == Device.SubChannelMode.QOnly ? "02h" : "04h"),
|
||||
(_gapDetection == GapDetectionMethod.ReadCD ? "BEh" : _gapDetection == GapDetectionMethod.ReadSubchannel ? "42h" : ""),
|
||||
_qChannelInBCD ? "" : "nonBCD",
|
||||
m_max_sectors);
|
||||
}
|
||||
@@ -183,9 +180,6 @@ namespace CUETools.Ripper.SCSI
|
||||
{
|
||||
m_logger = new Logger();
|
||||
_crc = new Crc16Ccitt(InitialCrcValue.Zeros);
|
||||
UserData = new long[MSECTORS, 2, 4 * 588];
|
||||
C2Count = new byte[MSECTORS, 294];
|
||||
QData = new byte[MSECTORS, 16];
|
||||
byte2long = new long[256];
|
||||
for (long i = 0; i < 256; i++)
|
||||
{
|
||||
@@ -261,9 +255,15 @@ namespace CUETools.Ripper.SCSI
|
||||
throw new SCSIException("ReadTOC", m_device, st);
|
||||
//throw new Exception("ReadTOC: " + (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
|
||||
|
||||
//byte[] qdata = null;
|
||||
//st = m_device.ReadPMA(out qdata);
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// throw new SCSIException("ReadPMA", m_device, st);
|
||||
|
||||
st = m_device.ReadCDText(out cdtext);
|
||||
// new CDTextEncoderDecoder
|
||||
|
||||
_toc2 = null;
|
||||
_toc = new CDImageLayout();
|
||||
for (int iTrack = 0; iTrack < toc.Count - 1; iTrack++)
|
||||
_toc.AddTrack(new CDTrack((uint)iTrack + 1,
|
||||
@@ -278,15 +278,24 @@ namespace CUETools.Ripper.SCSI
|
||||
_toc[1][0].Start = 0;
|
||||
Position = 0;
|
||||
}
|
||||
|
||||
UserData = new long[MSECTORS, 2, 4 * 588];
|
||||
C2Count = new byte[MSECTORS, 294];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
UserData = null;
|
||||
C2Count = null;
|
||||
if (m_device != null)
|
||||
m_device.Close();
|
||||
m_device = null;
|
||||
_toc = null;
|
||||
_toc2 = null;
|
||||
gapsDetected = false;
|
||||
readCommandFound = false;
|
||||
_currentStart = -1;
|
||||
_currentEnd = -1;
|
||||
}
|
||||
@@ -304,199 +313,444 @@ namespace CUETools.Ripper.SCSI
|
||||
}
|
||||
}
|
||||
|
||||
private int ProcessSubchannel(int sector, int Sectors2Read, bool updateMap)
|
||||
private enum GapDetectionMethod
|
||||
{
|
||||
int posCount = 0;
|
||||
for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
{
|
||||
int q_pos = (sector - _currentStart + iSector);
|
||||
int ctl = QData[q_pos, 0] >> 4;
|
||||
int adr = QData[q_pos, 0] & 7;
|
||||
bool preemph = (ctl & 1) == 1;
|
||||
bool dcp = (ctl & 2) == 2;
|
||||
ReadCD,
|
||||
ReadSubchannel,
|
||||
None
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
_subchannelBuffer[i] = QData[ q_pos, i];
|
||||
if (!_qChannelInBCD && adr == 1)
|
||||
private GapDetectionMethod _gapDetection = GapDetectionMethod.None;
|
||||
|
||||
private unsafe void LocateLastSector(int sec0, int sec1, int iTrack, int iIndex, ref int maxIndex, out int pos)
|
||||
{
|
||||
if (sec1 <= sec0)
|
||||
{
|
||||
pos = Math.Min(sec0, sec1);
|
||||
return;
|
||||
}
|
||||
int msector = (sec0 + sec1) / 2;
|
||||
int fsector = Math.Max(sec0, msector - 1);
|
||||
int lsector = Math.Min(sec1, msector + 3);
|
||||
|
||||
if (lsector >= fsector && _gapDetection == GapDetectionMethod.ReadCD)
|
||||
{
|
||||
Device.CommandStatus st = m_device.ReadSubChannel(2, (uint)fsector, (uint)(lsector - fsector + 1), ref _subchannelBuffer, _timeout);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
lsector = fsector - 1;
|
||||
}
|
||||
|
||||
fixed (byte * data = _subchannelBuffer)
|
||||
for (int sector = fsector; sector <= lsector; sector++)
|
||||
{
|
||||
_subchannelBuffer[3] = toBCD(_subchannelBuffer[3]);
|
||||
_subchannelBuffer[4] = toBCD(_subchannelBuffer[4]);
|
||||
_subchannelBuffer[5] = toBCD(_subchannelBuffer[5]);
|
||||
_subchannelBuffer[7] = toBCD(_subchannelBuffer[7]);
|
||||
_subchannelBuffer[8] = toBCD(_subchannelBuffer[8]);
|
||||
_subchannelBuffer[9] = toBCD(_subchannelBuffer[9]);
|
||||
}
|
||||
ushort crc = _crc.ComputeChecksum(_subchannelBuffer, 0, 10);
|
||||
crc ^= 0xffff;
|
||||
if ((QData[q_pos, 10] != 0 || QData[q_pos, 11] != 0) &&
|
||||
((byte)(crc & 0xff) != QData[q_pos, 11] || (byte)(crc >> 8) != QData[q_pos, 10])
|
||||
)
|
||||
{
|
||||
if (!updateMap)
|
||||
continue;
|
||||
_crcErrorsCount++;
|
||||
if (_debugMessages && _crcErrorsCount < 4)
|
||||
Device.CommandStatus st = Device.CommandStatus.Success;
|
||||
int sTrack, sIndex, sPos, ctl;
|
||||
switch (_gapDetection)
|
||||
{
|
||||
StringBuilder st = new StringBuilder();
|
||||
for (int i = 0; i < 12; i++)
|
||||
st.AppendFormat(",0x{0:X2}", QData[q_pos, i]);
|
||||
System.Console.WriteLine("\rCRC error@{0}{1};", CDImageLayout.TimeToString((uint)(sector + iSector)), st.ToString());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
switch (adr)
|
||||
{
|
||||
case 1: // current position
|
||||
{
|
||||
int iTrack = fromBCD(QData[q_pos, 1]);
|
||||
int iIndex = fromBCD(QData[q_pos, 2]);
|
||||
int mm = _qChannelInBCD ? fromBCD(QData[q_pos, 7]) : QData[q_pos, 7];
|
||||
int ss = _qChannelInBCD ? fromBCD(QData[q_pos, 8]) : QData[q_pos, 8];
|
||||
int ff = _qChannelInBCD ? fromBCD(QData[q_pos, 9]) : QData[q_pos, 9];
|
||||
//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);
|
||||
if (iTrack == 110)
|
||||
case GapDetectionMethod.ReadSubchannel:
|
||||
{
|
||||
if (sector + iSector + 75 < _toc.AudioLength)
|
||||
throw new Exception("lead out area encountred");
|
||||
// make sure that data is zero?
|
||||
return posCount;
|
||||
}
|
||||
if (iTrack == 0)
|
||||
throw new Exception("lead in area encountred");
|
||||
posCount++;
|
||||
if (!updateMap)
|
||||
// seek to given sector
|
||||
if (_readCDCommand == ReadCDCommand.ReadCdBEh)
|
||||
st = m_device.ReadCDAndSubChannel(_mainChannelMode, Device.SubChannelMode.None, _c2ErrorMode, 1, false, (uint)sector, 1, (IntPtr)((void*)data), _timeout);
|
||||
else
|
||||
st = m_device.ReadCDDA(Device.SubChannelMode.None, (uint)sector, 1, (IntPtr)((void*)data), _timeout);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
continue;
|
||||
st = m_device.ReadSubChannel42(1, 0, ref _subchannelBuffer, 0, _timeout);
|
||||
// x x x x 01 adrctl tr ind abs abs abs rel rel rel
|
||||
if (st != Device.CommandStatus.Success)
|
||||
continue;
|
||||
if (_subchannelBuffer[0] != 0 || _subchannelBuffer[2] != 0 || _subchannelBuffer[3] != 12 || _subchannelBuffer[4] != 1)
|
||||
continue;
|
||||
|
||||
ctl = _subchannelBuffer[5] & 0xf;
|
||||
int adr = (_subchannelBuffer[5] >> 4) & 0xf;
|
||||
sTrack = _subchannelBuffer[6];
|
||||
sIndex = _subchannelBuffer[7];
|
||||
sPos = (_subchannelBuffer[8] << 24) | (_subchannelBuffer[9] << 16) | (_subchannelBuffer[10] << 8) | (_subchannelBuffer[11]);
|
||||
//int sRel = (_subchannelBuffer[12] << 24) | (_subchannelBuffer[13] << 16) | (_subchannelBuffer[14] << 8) | (_subchannelBuffer[15]);
|
||||
if (adr != 1)
|
||||
continue;
|
||||
|
||||
if (sTrack < _toc2.FirstAudio || sTrack >= _toc2.FirstAudio + _toc2.AudioTracks)
|
||||
continue;
|
||||
|
||||
break;
|
||||
int sec = ff + 75 * (ss + 60 * mm) - 150; // sector + iSector;
|
||||
if (iTrack >= _toc.FirstAudio + _toc.AudioTracks)
|
||||
throw new Exception("strange track number encountred");
|
||||
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;
|
||||
_currentTrackActualStart = sec;
|
||||
_currentIndex = iIndex;
|
||||
}
|
||||
else if (iIndex != _currentIndex)
|
||||
case GapDetectionMethod.ReadCD:
|
||||
{
|
||||
if (iIndex != _currentIndex + 1)
|
||||
int offs = 16 * (sector - fsector);
|
||||
ctl = _subchannelBuffer[offs + 0] >> 4;
|
||||
int adr = _subchannelBuffer[offs + 0] & 7;
|
||||
if (!_qChannelInBCD && adr == 1)
|
||||
{
|
||||
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;
|
||||
_subchannelBuffer[offs + 3] = toBCD(_subchannelBuffer[offs + 3]);
|
||||
_subchannelBuffer[offs + 4] = toBCD(_subchannelBuffer[offs + 4]);
|
||||
_subchannelBuffer[offs + 5] = toBCD(_subchannelBuffer[offs + 5]);
|
||||
_subchannelBuffer[offs + 7] = toBCD(_subchannelBuffer[offs + 7]);
|
||||
_subchannelBuffer[offs + 8] = toBCD(_subchannelBuffer[offs + 8]);
|
||||
_subchannelBuffer[offs + 9] = toBCD(_subchannelBuffer[offs + 9]);
|
||||
}
|
||||
_currentIndex = iIndex;
|
||||
if (_currentIndex == 1)
|
||||
{
|
||||
if (iTrack != 1)
|
||||
{
|
||||
uint pregap = (uint)(sec - _currentTrackActualStart);
|
||||
_toc[iTrack][0].Start = _toc[iTrack].Start - pregap;
|
||||
}
|
||||
_currentTrackActualStart = sec;
|
||||
} else
|
||||
_toc[iTrack].AddIndex(new CDTrackIndex((uint)iIndex, (uint)(_toc[iTrack].Start + sec - _currentTrackActualStart)));
|
||||
_currentIndex = iIndex;
|
||||
|
||||
ushort crc = _crc.ComputeChecksum(_subchannelBuffer, offs, 10);
|
||||
crc ^= 0xffff;
|
||||
ushort scrc = (ushort)((_subchannelBuffer[offs + 10] << 8) | _subchannelBuffer[offs + 11]);
|
||||
if (scrc != 0 && scrc != crc)
|
||||
continue;
|
||||
if (adr != 1)
|
||||
continue;
|
||||
|
||||
sTrack = fromBCD(_subchannelBuffer[offs + 1]);
|
||||
sIndex = fromBCD(_subchannelBuffer[offs + 2]);
|
||||
|
||||
if (sTrack < _toc2.FirstAudio || sTrack >= _toc2.FirstAudio + _toc2.AudioTracks)
|
||||
continue;
|
||||
|
||||
int mm = fromBCD(_subchannelBuffer[offs + 7]);
|
||||
int ss = fromBCD(_subchannelBuffer[offs + 8]);
|
||||
int ff = fromBCD(_subchannelBuffer[offs + 9]);
|
||||
sPos = ff + 75 * (ss + 60 * mm) - 150;
|
||||
break;
|
||||
}
|
||||
if (preemph)
|
||||
_toc[iTrack].PreEmphasis = true;
|
||||
if (dcp)
|
||||
_toc[iTrack].DCP = true;
|
||||
break;
|
||||
}
|
||||
case 2: // catalog
|
||||
if (updateMap && _toc.Catalog == null)
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
bool preemph = (ctl & 1) == 1;
|
||||
bool dcp = (ctl & 2) == 2;
|
||||
if (preemph)
|
||||
_toc2[sTrack].PreEmphasis = true;
|
||||
if (dcp)
|
||||
_toc2[sTrack].DCP = true;
|
||||
|
||||
if (sPos <= sec0 || sPos > sec1)
|
||||
continue;
|
||||
if (sTrack > iTrack || (sTrack == iTrack && iIndex >= 0 && sIndex > iIndex))
|
||||
{
|
||||
LocateLastSector(sec0, sPos - 1, iTrack, iIndex, ref maxIndex, out pos);
|
||||
return;
|
||||
}
|
||||
if (sTrack < iTrack || (sTrack == iTrack && (iIndex < 0 || sIndex <= iIndex)))
|
||||
{
|
||||
if (sTrack == iTrack && iIndex < 0)
|
||||
maxIndex = sIndex;
|
||||
LocateLastSector(sPos, sec1, iTrack, iIndex, ref maxIndex, out pos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (sec1 <= sec0 + 16)
|
||||
{
|
||||
pos = Math.Min(sec0, sec1);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: catch?
|
||||
throw new Exception("gap detection failed");
|
||||
}
|
||||
|
||||
private unsafe void TestGaps()
|
||||
{
|
||||
_gapDetection = GapDetectionMethod.None;
|
||||
|
||||
//st = m_device.Seek((uint)(sector + i * 33) + _toc[_toc.FirstAudio][0].Start);
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// break;
|
||||
//bool ready;
|
||||
//st = m_device.TestUnitReady(out ready);
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// break;
|
||||
//if (!ready)
|
||||
//{
|
||||
// st = Device.CommandStatus.NotSupported;
|
||||
// break;
|
||||
//}
|
||||
|
||||
// try ReadCD:
|
||||
Device.CommandStatus st;
|
||||
int sector = 3;
|
||||
|
||||
if (_readCDCommand == ReadCDCommand.ReadCdBEh)
|
||||
{
|
||||
st = m_device.ReadSubChannel(2, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)m_max_sectors, ref _subchannelBuffer, _timeout);
|
||||
if (st == Device.CommandStatus.Success)
|
||||
{
|
||||
int[] goodsecs = new int[2];
|
||||
for (int bcd = 1; bcd >= 0; bcd--)
|
||||
{
|
||||
for (int i = 0; i < m_max_sectors; i++)
|
||||
{
|
||||
StringBuilder catalog = new StringBuilder();
|
||||
for (int i = 1; i < 8; i++)
|
||||
catalog.AppendFormat("{0:x2}", QData[q_pos, i]);
|
||||
_toc.Catalog = catalog.ToString(0, 13);
|
||||
int adr = _subchannelBuffer[i * 16 + 0] & 7;
|
||||
if (bcd == 0 && adr == 1)
|
||||
{
|
||||
_subchannelBuffer[i * 16 + 3] = toBCD(_subchannelBuffer[i * 16 + 3]);
|
||||
_subchannelBuffer[i * 16 + 4] = toBCD(_subchannelBuffer[i * 16 + 4]);
|
||||
_subchannelBuffer[i * 16 + 5] = toBCD(_subchannelBuffer[i * 16 + 5]);
|
||||
_subchannelBuffer[i * 16 + 7] = toBCD(_subchannelBuffer[i * 16 + 7]);
|
||||
_subchannelBuffer[i * 16 + 8] = toBCD(_subchannelBuffer[i * 16 + 8]);
|
||||
_subchannelBuffer[i * 16 + 9] = toBCD(_subchannelBuffer[i * 16 + 9]);
|
||||
}
|
||||
|
||||
ushort crc = _crc.ComputeChecksum(_subchannelBuffer, i * 16, 10);
|
||||
crc ^= 0xffff;
|
||||
ushort scrc = (ushort)((_subchannelBuffer[i * 16 + 10] << 8) | _subchannelBuffer[i * 16 + 11]);
|
||||
if (scrc != 0 && scrc != crc)
|
||||
continue;
|
||||
if (adr != 1)
|
||||
continue;
|
||||
|
||||
int sTrack = fromBCD(_subchannelBuffer[i * 16 + 1]);
|
||||
int sIndex = fromBCD(_subchannelBuffer[i * 16 + 2]);
|
||||
|
||||
if (sTrack == 0 || sTrack == 110)
|
||||
continue;
|
||||
|
||||
int mm = fromBCD(_subchannelBuffer[i * 16 + 7]);
|
||||
int ss = fromBCD(_subchannelBuffer[i * 16 + 8]);
|
||||
int ff = fromBCD(_subchannelBuffer[i * 16 + 9]);
|
||||
int sPos = ff + 75 * (ss + 60 * mm) - 150;
|
||||
|
||||
if (sPos < sector + i - 8 || sPos > sector + i + 8)
|
||||
continue;
|
||||
|
||||
goodsecs[bcd]++;
|
||||
}
|
||||
break;
|
||||
case 3: //isrc
|
||||
if (updateMap && _toc[_currentTrack].ISRC == null)
|
||||
{
|
||||
StringBuilder isrc = new StringBuilder();
|
||||
isrc.Append(from6bit(QData[q_pos, 1] >> 2));
|
||||
isrc.Append(from6bit(((QData[q_pos, 1] & 0x3) << 4) + (0x0f & (QData[q_pos, 2] >> 4))));
|
||||
isrc.Append(from6bit(((QData[q_pos, 2] & 0xf) << 2) + (0x03 & (QData[q_pos, 3] >> 6))));
|
||||
isrc.Append(from6bit((QData[q_pos, 3] & 0x3f)));
|
||||
isrc.Append(from6bit(QData[q_pos, 4] >> 2));
|
||||
isrc.Append(from6bit(((QData[q_pos, 4] & 0x3) << 4) + (0x0f & (QData[q_pos, 5] >> 4))));
|
||||
isrc.AppendFormat("{0:x}", QData[q_pos, 5] & 0xf);
|
||||
isrc.AppendFormat("{0:x2}", QData[q_pos, 6]);
|
||||
isrc.AppendFormat("{0:x2}", QData[q_pos, 7]);
|
||||
isrc.AppendFormat("{0:x}", QData[q_pos, 8] >> 4);
|
||||
if (!isrc.ToString().Contains("#") && isrc.ToString() != "0000000000")
|
||||
_toc[_currentTrack].ISRC = isrc.ToString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (goodsecs[0] > 0 || goodsecs[1] > 0)
|
||||
{
|
||||
_qChannelInBCD = goodsecs[1] >= goodsecs[0];
|
||||
_gapDetection = GapDetectionMethod.ReadCD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_gapDetection == GapDetectionMethod.None)
|
||||
{
|
||||
fixed (byte* data = _subchannelBuffer)
|
||||
{
|
||||
// seek to given sector
|
||||
if (_readCDCommand == ReadCDCommand.ReadCdBEh)
|
||||
st = m_device.ReadCDAndSubChannel(_mainChannelMode, Device.SubChannelMode.None, _c2ErrorMode, 1, false, (uint)sector + _toc[_toc.FirstAudio][0].Start, 1, (IntPtr)((void*)data), _timeout);
|
||||
else
|
||||
st = m_device.ReadCDDA(Device.SubChannelMode.None, (uint)sector + _toc[_toc.FirstAudio][0].Start, 1, (IntPtr)((void*)data), _timeout);
|
||||
}
|
||||
if (st == Device.CommandStatus.Success)
|
||||
{
|
||||
st = m_device.ReadSubChannel42(1, 0, ref _subchannelBuffer, 0, _timeout);
|
||||
if (st == Device.CommandStatus.Success)
|
||||
{
|
||||
if (_subchannelBuffer[0] == 0 && _subchannelBuffer[2] == 0 && _subchannelBuffer[3] == 12 && _subchannelBuffer[4] == 1)
|
||||
{
|
||||
int ctl = _subchannelBuffer[5] & 0xf;
|
||||
int adr = (_subchannelBuffer[5] >> 4) & 0xf;
|
||||
if (adr == 1)
|
||||
{
|
||||
_gapDetection = GapDetectionMethod.ReadSubchannel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return posCount;
|
||||
}
|
||||
|
||||
public bool GapsDetected
|
||||
{
|
||||
get
|
||||
{
|
||||
return gapsDetected;
|
||||
}
|
||||
}
|
||||
|
||||
bool gapsDetected = false;
|
||||
|
||||
public unsafe bool DetectGaps()
|
||||
{
|
||||
if (!TestReadCommand())
|
||||
throw new Exception("failed to autodetect read command:\n" + _autodetectResult);
|
||||
|
||||
if (_gapDetection == GapDetectionMethod.None)
|
||||
{
|
||||
gapsDetected = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gapsDetected)
|
||||
return true;
|
||||
|
||||
_toc2 = (CDImageLayout)_toc.Clone();
|
||||
|
||||
if (_gapDetection == GapDetectionMethod.ReadSubchannel)
|
||||
{
|
||||
Device.CommandStatus st = m_device.ReadSubChannel42(2, 0, ref _subchannelBuffer, 0, _timeout);
|
||||
if (st == Device.CommandStatus.Success)
|
||||
if (_subchannelBuffer[0] == 0 && _subchannelBuffer[2] == 0 && _subchannelBuffer[3] == 20
|
||||
&& _subchannelBuffer[4] == 2 && _subchannelBuffer[8] == 0x80)
|
||||
{
|
||||
string catalog = Encoding.ASCII.GetString(_subchannelBuffer, 9, 13);
|
||||
if (catalog.ToString() != "0000000000000")
|
||||
_toc2.Catalog = catalog.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
int sec0 = (int)_toc2[_toc2.FirstAudio][0].Start, disc1 = (int)(_toc2[_toc2.FirstAudio][0].Start + _toc2.AudioLength) - 1;
|
||||
for (int iTrack = _toc2.FirstAudio; iTrack < _toc2.FirstAudio + _toc2.AudioTracks; iTrack++)
|
||||
{
|
||||
if (ReadProgress != null)
|
||||
{
|
||||
progressArgs.Action = "Detecting gaps";
|
||||
progressArgs.Pass = -1;
|
||||
progressArgs.Position = (iTrack - _toc2.FirstAudio) * 3;
|
||||
progressArgs.PassStart = 0;
|
||||
progressArgs.PassEnd = _toc2.TrackCount * 3 - 1;
|
||||
progressArgs.ErrorsCount = 0;
|
||||
progressArgs.PassTime = DateTime.Now;
|
||||
ReadProgress(this, progressArgs);
|
||||
}
|
||||
int sec1, idx1 = 1;
|
||||
LocateLastSector(sec0, Math.Min(disc1, (int)_toc[iTrack].End + 16), iTrack, -1, ref idx1, out sec1);
|
||||
int isec0 = sec0;
|
||||
for (int idx = 0; idx <= idx1; idx++)
|
||||
{
|
||||
int isec1 = sec1, iidx1 = 1;
|
||||
if (idx < idx1)
|
||||
{
|
||||
if (ReadProgress != null)
|
||||
{
|
||||
progressArgs.Position = (iTrack - _toc2.FirstAudio) * 3 + 1;
|
||||
progressArgs.PassTime = DateTime.Now;
|
||||
ReadProgress(this, progressArgs);
|
||||
}
|
||||
LocateLastSector(isec0, sec1, iTrack, idx, ref iidx1, out isec1);
|
||||
}
|
||||
if (isec1 > isec0)
|
||||
{
|
||||
if (idx == 0 && iTrack > 1)
|
||||
_toc2[iTrack][0].Start = _toc2[iTrack].Start - (uint)(isec1 - isec0 + 1);
|
||||
if (idx > 1)
|
||||
_toc2[iTrack].AddIndex(new CDTrackIndex((uint)idx, (uint)(_toc2[iTrack][0].Start + isec0 - sec0)));
|
||||
}
|
||||
isec0 = isec1 + 1;
|
||||
}
|
||||
|
||||
if (ReadProgress != null)
|
||||
{
|
||||
progressArgs.Position = (iTrack - _toc2.FirstAudio) * 3 + 2;
|
||||
progressArgs.PassTime = DateTime.Now;
|
||||
ReadProgress(this, progressArgs);
|
||||
}
|
||||
|
||||
if (_gapDetection == GapDetectionMethod.ReadSubchannel)
|
||||
{
|
||||
Device.CommandStatus st = m_device.ReadSubChannel42(3, iTrack, ref _subchannelBuffer, 0, _timeout);
|
||||
if (st == Device.CommandStatus.Success)
|
||||
if (_subchannelBuffer[0] == 0 && _subchannelBuffer[2] == 0 && _subchannelBuffer[3] == 20
|
||||
&& _subchannelBuffer[4] == 3 && _subchannelBuffer[8] == 0x80) //&& _subchannelBuffer[6] == iTrack)
|
||||
{
|
||||
string isrc = Encoding.ASCII.GetString(_subchannelBuffer, 9, 12);
|
||||
if (!isrc.ToString().Contains("#") && isrc.ToString() != "000000000000")
|
||||
_toc2[iTrack].ISRC = isrc.ToString();
|
||||
}
|
||||
}
|
||||
if (_gapDetection == GapDetectionMethod.ReadCD)
|
||||
{
|
||||
Device.CommandStatus st = m_device.ReadSubChannel(2, _toc2[iTrack].Start + 16, 100, ref _subchannelBuffer, _timeout);
|
||||
if (st == Device.CommandStatus.Success)
|
||||
{
|
||||
for (int offs = 0; offs < 100 * 16; offs += 16)
|
||||
{
|
||||
int ctl = _subchannelBuffer[offs + 0] >> 4;
|
||||
int adr = _subchannelBuffer[offs + 0] & 7;
|
||||
if (adr != 2 && adr != 3)
|
||||
continue;
|
||||
ushort crc = _crc.ComputeChecksum(_subchannelBuffer, offs, 10);
|
||||
crc ^= 0xffff;
|
||||
ushort scrc = (ushort)((_subchannelBuffer[offs + 10] << 8) | _subchannelBuffer[offs + 11]);
|
||||
if (scrc != 0 && scrc != crc)
|
||||
continue;
|
||||
if (adr == 3 && _toc2[iTrack].ISRC == null)
|
||||
{
|
||||
StringBuilder isrc = new StringBuilder();
|
||||
isrc.Append(from6bit(_subchannelBuffer[offs + 1] >> 2));
|
||||
isrc.Append(from6bit(((_subchannelBuffer[offs + 1] & 0x3) << 4) + (0x0f & (_subchannelBuffer[offs + 2] >> 4))));
|
||||
isrc.Append(from6bit(((_subchannelBuffer[offs + 2] & 0xf) << 2) + (0x03 & (_subchannelBuffer[offs + 3] >> 6))));
|
||||
isrc.Append(from6bit((_subchannelBuffer[offs + 3] & 0x3f)));
|
||||
isrc.Append(from6bit(_subchannelBuffer[offs + 4] >> 2));
|
||||
isrc.Append(from6bit(((_subchannelBuffer[offs + 4] & 0x3) << 4) + (0x0f & (_subchannelBuffer[offs + 5] >> 4))));
|
||||
isrc.AppendFormat("{0:x}", _subchannelBuffer[offs + 5] & 0xf);
|
||||
isrc.AppendFormat("{0:x2}", _subchannelBuffer[offs + 6]);
|
||||
isrc.AppendFormat("{0:x2}", _subchannelBuffer[offs + 7]);
|
||||
isrc.AppendFormat("{0:x}", _subchannelBuffer[offs + 8] >> 4);
|
||||
if (!isrc.ToString().Contains("#") && isrc.ToString() != "000000000000")
|
||||
_toc2[iTrack].ISRC = isrc.ToString();
|
||||
}
|
||||
if (adr == 2 && _toc2.Catalog == null)
|
||||
{
|
||||
StringBuilder catalog = new StringBuilder();
|
||||
for (int i = 1; i < 8; i++)
|
||||
catalog.AppendFormat("{0:x2}", _subchannelBuffer[offs + i]);
|
||||
if (catalog.ToString() != "0000000000000")
|
||||
_toc2.Catalog = catalog.ToString(0, 13);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sec0 = sec1 + 1;
|
||||
}
|
||||
|
||||
gapsDetected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readCommandFound = false;
|
||||
|
||||
public unsafe bool TestReadCommand()
|
||||
{
|
||||
if (readCommandFound)
|
||||
return true;
|
||||
|
||||
//ReadCDCommand[] readmode = { ReadCDCommand.ReadCdBEh, ReadCDCommand.ReadCdD8h };
|
||||
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.Mode294, Device.C2ErrorMode.Mode296, Device.C2ErrorMode.None };
|
||||
Device.MainChannelSelection[] mainmode = { Device.MainChannelSelection.UserData, Device.MainChannelSelection.F8h };
|
||||
bool found = false;
|
||||
_autodetectResult = "";
|
||||
_currentStart = 0;
|
||||
_currentTrack = -1;
|
||||
_currentIndex = -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++)
|
||||
int pass = 0;
|
||||
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];
|
||||
_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;
|
||||
if (ReadProgress != null)
|
||||
{
|
||||
_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)
|
||||
{
|
||||
_qChannelInBCD = false;
|
||||
int sub1 = ProcessSubchannel(sector, m_max_sectors, false);
|
||||
_qChannelInBCD = true;
|
||||
int sub2 = ProcessSubchannel(sector, m_max_sectors, false);
|
||||
_qChannelInBCD = sub2 >= sub1;
|
||||
if (sub1 == 0 && sub2 == 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;
|
||||
progressArgs.Action = "Detecting drive features";
|
||||
progressArgs.Pass = -1;
|
||||
progressArgs.Position = pass++;
|
||||
progressArgs.PassStart = 0;
|
||||
progressArgs.PassEnd = 2 * 3 * 2 - 1;
|
||||
progressArgs.ErrorsCount = 0;
|
||||
progressArgs.PassTime = tm;
|
||||
ReadProgress(this, progressArgs);
|
||||
}
|
||||
Device.CommandStatus st = FetchSectors(sector, m_max_sectors, false);
|
||||
TimeSpan delay = DateTime.Now - tm;
|
||||
_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;
|
||||
|
||||
//sector += m_max_sectors;
|
||||
}
|
||||
//if (found)
|
||||
// for (int n = 1; n <= m_max_sectors; n++)
|
||||
// {
|
||||
@@ -508,11 +762,16 @@ namespace CUETools.Ripper.SCSI
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
TestGaps();
|
||||
|
||||
if (found)
|
||||
_autodetectResult += "Chosen " + CurrentReadCommand + "\n";
|
||||
else
|
||||
_readCDCommand = ReadCDCommand.Unknown;
|
||||
|
||||
_currentStart = -1;
|
||||
_currentEnd = -1;
|
||||
readCommandFound = found;
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -522,8 +781,8 @@ namespace CUETools.Ripper.SCSI
|
||||
private unsafe void ReorganiseSectors(int sector, int Sectors2Read)
|
||||
{
|
||||
int c2Size = _c2ErrorMode == Device.C2ErrorMode.None ? 0 : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : 296;
|
||||
int oldSize = 4 * 588 + c2Size + (_subChannelMode == Device.SubChannelMode.None ? 0 : 16);
|
||||
fixed (byte* readBuf = _readBuffer, qBuf = _subchannelBuffer, qData = QData, c2Count = C2Count)
|
||||
int oldSize = 4 * 588 + c2Size;
|
||||
fixed (byte* readBuf = _readBuffer, c2Count = C2Count)
|
||||
fixed (long* userData = UserData)
|
||||
{
|
||||
for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
@@ -531,7 +790,6 @@ namespace CUETools.Ripper.SCSI
|
||||
byte* sectorPtr = readBuf + iSector * oldSize;
|
||||
long* userDataPtr = userData + (sector - _currentStart + iSector) * 8 * 588;
|
||||
byte* c2CountPtr = c2Count + (sector - _currentStart + iSector) * 294;
|
||||
byte* qDataPtr = qData + (sector - _currentStart + iSector) * 16;
|
||||
|
||||
//if (_currentStart > 0)
|
||||
//{
|
||||
@@ -552,7 +810,7 @@ namespace CUETools.Ripper.SCSI
|
||||
int offs = 0;
|
||||
if (c2Size == 296)
|
||||
{
|
||||
// sometimes sector C2 byte is placed after C2 info, not before!!
|
||||
// TODO: sometimes sector C2 byte is placed after C2 info, not before!!
|
||||
int c2 = 0;
|
||||
for (int pos = 2; pos < 294; pos++)
|
||||
c2 |= sectorPtr[4 * 588 + pos];
|
||||
@@ -582,14 +840,8 @@ namespace CUETools.Ripper.SCSI
|
||||
else
|
||||
{
|
||||
for (int sample = 0; sample < 4 * 588; sample++)
|
||||
userDataPtr[sample] += byte2long[sectorPtr[sample]] * 3;
|
||||
userDataPtr[sample] += byte2long[sectorPtr[sample]];
|
||||
}
|
||||
if (_subChannelMode != Device.SubChannelMode.None)
|
||||
for (int qi = 0; qi < 16; qi++)
|
||||
qDataPtr[qi] = sectorPtr[4 * 588 + c2Size + qi];
|
||||
else
|
||||
for (int qi = 0; qi < 16; qi++)
|
||||
qDataPtr[qi] = qBuf[iSector * 16 + qi];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,26 +856,22 @@ namespace CUETools.Ripper.SCSI
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe Device.CommandStatus FetchSectors(int sector, int Sectors2Read, bool abort, bool subchannel)
|
||||
private unsafe Device.CommandStatus FetchSectors(int sector, int Sectors2Read, bool abort)
|
||||
{
|
||||
Device.CommandStatus st;
|
||||
fixed (byte* data = _readBuffer)
|
||||
{
|
||||
if (_debugMessages)
|
||||
{
|
||||
int size = (4 * 588 +
|
||||
(_subChannelMode == Device.SubChannelMode.QOnly ? 16 : _subChannelMode == Device.SubChannelMode.RWMode ? 96 : 0) +
|
||||
(_c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : _c2ErrorMode == Device.C2ErrorMode.Mode296 ? 296 : 0)) * (int)Sectors2Read;
|
||||
int size = (4 * 588 + (_c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : _c2ErrorMode == Device.C2ErrorMode.Mode296 ? 296 : 0))
|
||||
* (int)Sectors2Read;
|
||||
MemSet(data, size, 0xff);
|
||||
}
|
||||
if (_readCDCommand == ReadCDCommand.ReadCdBEh)
|
||||
st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout);
|
||||
st = m_device.ReadCDAndSubChannel(_mainChannelMode, Device.SubChannelMode.None, _c2ErrorMode, 1, false, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout);
|
||||
else
|
||||
st = m_device.ReadCDDA(_subChannelMode, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout);
|
||||
st = m_device.ReadCDDA(Device.SubChannelMode.None, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout);
|
||||
}
|
||||
|
||||
if (st == Device.CommandStatus.Success && _subChannelMode == Device.SubChannelMode.None && subchannel)
|
||||
st = m_device.ReadSubChannel(2, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, ref _subchannelBuffer, _timeout);
|
||||
|
||||
if (st == Device.CommandStatus.Success)
|
||||
{
|
||||
@@ -641,13 +889,11 @@ namespace CUETools.Ripper.SCSI
|
||||
int iErrors = 0;
|
||||
for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
{
|
||||
if (FetchSectors(sector + iSector, 1, false, subchannel) != Device.CommandStatus.Success)
|
||||
if (FetchSectors(sector + iSector, 1, false) != Device.CommandStatus.Success)
|
||||
{
|
||||
iErrors ++;
|
||||
for (int i = 0; i < 294; i++)
|
||||
C2Count[sector + iSector - _currentStart, i] ++;
|
||||
for (int i = 0; i < 16; i++)
|
||||
QData[ sector + iSector - _currentStart, i] = 0;
|
||||
if (_debugMessages)
|
||||
System.Console.WriteLine("\nSector lost");
|
||||
}
|
||||
@@ -814,6 +1060,7 @@ namespace CUETools.Ripper.SCSI
|
||||
fError |= (sum ^ sig) < er_limit;
|
||||
bestValue += sig & (1 << i);
|
||||
val >>= 8;
|
||||
val1 >>= 8;
|
||||
}
|
||||
currentData.Bytes[pos * 4 * 588 + iPar] = (byte)bestValue;
|
||||
}
|
||||
@@ -891,10 +1138,10 @@ namespace CUETools.Ripper.SCSI
|
||||
if (iSector >= _currentStart && iSector < _currentEnd)
|
||||
return;
|
||||
|
||||
if (_readCDCommand == ReadCDCommand.Unknown && !TestReadCommand())
|
||||
throw new Exception("failed to autodetect read command: " + _autodetectResult);
|
||||
if (!TestReadCommand())
|
||||
throw new Exception("failed to autodetect read command:\n" + _autodetectResult);
|
||||
|
||||
_currentStart = MSECTORS * (iSector / MSECTORS);
|
||||
_currentStart = iSector;
|
||||
_currentEnd = _currentStart + MSECTORS;
|
||||
if (_currentEnd > (int)_toc.AudioLength)
|
||||
{
|
||||
@@ -918,6 +1165,12 @@ namespace CUETools.Ripper.SCSI
|
||||
for (int i = 0; i < MSECTORS; i++)
|
||||
errtmp[i] = 0;
|
||||
|
||||
//Device.CommandStatus st = m_device.SetCdSpeed(Device.RotationalControl.CLVandNonPureCav, (ushort)(176 * 4), 65535);
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// System.Console.WriteLine("SetCdSpeed: {0}", (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
|
||||
|
||||
// TODO:
|
||||
//int max_scans = 1 << _correctionQuality;
|
||||
int max_scans = 16 << _correctionQuality;
|
||||
for (int pass = 0; pass < max_scans; pass++)
|
||||
{
|
||||
@@ -935,10 +1188,8 @@ namespace CUETools.Ripper.SCSI
|
||||
LastFetch = DateTime.Now;
|
||||
if (pass == 0)
|
||||
ClearSectors(sector, Sectors2Read);
|
||||
FetchSectors(sector, Sectors2Read, true, pass == 0);
|
||||
FetchSectors(sector, Sectors2Read, true);
|
||||
//TimeSpan delay1 = DateTime.Now - LastFetch;
|
||||
if (pass == 0)
|
||||
ProcessSubchannel(sector, Sectors2Read, true);
|
||||
//DateTime LastFetched = DateTime.Now;
|
||||
if (pass >= _correctionQuality)
|
||||
{
|
||||
@@ -949,7 +1200,16 @@ namespace CUETools.Ripper.SCSI
|
||||
//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));
|
||||
{
|
||||
progressArgs.Action = "Ripping";
|
||||
progressArgs.Position = sector + Sectors2Read;
|
||||
progressArgs.Pass = pass;
|
||||
progressArgs.PassStart = _currentStart;
|
||||
progressArgs.PassEnd = _currentEnd;
|
||||
progressArgs.ErrorsCount = _currentErrorsCount;
|
||||
progressArgs.PassTime = PassTime;
|
||||
ReadProgress(this, progressArgs);
|
||||
}
|
||||
}
|
||||
//System.Console.WriteLine();
|
||||
//if (CorrectSectorsTest(start, _currentEnd, 10, realData) == 0)
|
||||
@@ -970,6 +1230,7 @@ namespace CUETools.Ripper.SCSI
|
||||
{
|
||||
for (int i = 0; i < buff.ByteLength; i++)
|
||||
buff.Bytes[i] = 0;
|
||||
_sampleOffset += buff.Length;
|
||||
return buff.Length; // == Remaining
|
||||
}
|
||||
if (_sampleOffset < 0)
|
||||
@@ -977,9 +1238,10 @@ namespace CUETools.Ripper.SCSI
|
||||
buff.Length = Math.Min(buff.Length, -_sampleOffset);
|
||||
for (int i = 0; i < buff.ByteLength; i++)
|
||||
buff.Bytes[i] = 0;
|
||||
_sampleOffset += buff.Length;
|
||||
return buff.Length;
|
||||
}
|
||||
PrefetchSector(_sampleOffset / 588);
|
||||
PrefetchSector(/*(int)_toc[_toc.FirstAudio][0].Start +*/ (_sampleOffset / 588));
|
||||
buff.Length = Math.Min(buff.Length, (int)Length - _sampleOffset);
|
||||
buff.Length = Math.Min(buff.Length, _currentEnd * 588 - _sampleOffset);
|
||||
if ((_sampleOffset - _currentStart * 588) == 0 && (maxLength < 0 || (_currentEnd - _currentStart) * 588 <= buff.Length))
|
||||
@@ -1101,7 +1363,7 @@ namespace CUETools.Ripper.SCSI
|
||||
{
|
||||
get
|
||||
{
|
||||
return "CUERipper v2.0.5 Copyright (C) 2008-10 Gregory S. Chudov";
|
||||
return "CUERipper v2.0.6 Copyright (C) 2008-10 Gregory S. Chudov";
|
||||
// ripper.GetName().Name + " " + ripper.GetName().Version;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user