CUERipper update;

CTDB xml interface;
Minor bugfixes;
Version 2.0.6-2.0.7
This commit is contained in:
chudov
2010-03-20 07:09:07 +00:00
parent ff3259e08a
commit f01d0b5241
74 changed files with 4203 additions and 1392 deletions

View File

@@ -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;
}
}