2008-11-28 22:13:06 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.IO;
|
2010-02-10 03:51:39 +00:00
|
|
|
using System.Net;
|
|
|
|
|
using System.Text;
|
2008-11-28 22:13:06 +00:00
|
|
|
using CUETools.CDImage;
|
2010-02-10 03:51:39 +00:00
|
|
|
using CUETools.Codecs;
|
2008-11-28 22:13:06 +00:00
|
|
|
|
|
|
|
|
namespace CUETools.AccurateRip
|
|
|
|
|
{
|
|
|
|
|
public class AccurateRipVerify : IAudioDest
|
|
|
|
|
{
|
2010-02-23 15:15:08 +00:00
|
|
|
public AccurateRipVerify(CDImageLayout toc, IWebProxy proxy)
|
2008-11-28 22:13:06 +00:00
|
|
|
{
|
2010-02-23 15:15:08 +00:00
|
|
|
this.proxy = proxy;
|
2008-11-28 22:13:06 +00:00
|
|
|
_toc = toc;
|
|
|
|
|
_accDisks = new List<AccDisk>();
|
2009-01-17 04:09:38 +00:00
|
|
|
_crc32 = new Crc32();
|
2009-02-23 03:59:50 +00:00
|
|
|
_hasLogCRC = false;
|
2009-01-28 04:53:13 +00:00
|
|
|
_CRCLOG = new uint[_toc.AudioTracks + 1];
|
|
|
|
|
for (int i = 0; i <= _toc.AudioTracks; i++)
|
|
|
|
|
_CRCLOG[i] = 0;
|
2008-11-28 22:13:06 +00:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-04 21:30:56 +00:00
|
|
|
public uint Confidence(int iTrack)
|
|
|
|
|
{
|
|
|
|
|
if (ARStatus != null)
|
|
|
|
|
return 0U;
|
|
|
|
|
uint conf = 0;
|
|
|
|
|
for (int di = 0; di < (int)AccDisks.Count; di++)
|
|
|
|
|
if (CRC(iTrack) == AccDisks[di].tracks[iTrack].CRC)
|
|
|
|
|
conf += AccDisks[di].tracks[iTrack].count;
|
|
|
|
|
return conf;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-28 03:57:49 +00:00
|
|
|
public uint WorstTotal()
|
|
|
|
|
{
|
|
|
|
|
uint worstTotal = 0;
|
|
|
|
|
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
|
|
|
|
{
|
|
|
|
|
uint sumTotal = Total(iTrack);
|
|
|
|
|
if (iTrack == 0 || worstTotal > sumTotal)
|
|
|
|
|
worstTotal = sumTotal;
|
|
|
|
|
}
|
|
|
|
|
return worstTotal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint WorstConfidence()
|
|
|
|
|
{
|
|
|
|
|
uint worstConfidence = 0;
|
|
|
|
|
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
|
|
|
|
{
|
|
|
|
|
uint sumConfidence = SumConfidence(iTrack);
|
|
|
|
|
if (iTrack == 0 || worstConfidence > sumConfidence)
|
|
|
|
|
worstConfidence = sumConfidence;
|
|
|
|
|
}
|
|
|
|
|
return worstConfidence;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint SumConfidence(int iTrack)
|
|
|
|
|
{
|
|
|
|
|
if (ARStatus != null)
|
|
|
|
|
return 0U;
|
|
|
|
|
uint conf = 0;
|
|
|
|
|
for (int iDisk = 0; iDisk < AccDisks.Count; iDisk++)
|
|
|
|
|
for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++)
|
|
|
|
|
if (CRC(iTrack, oi) == AccDisks[iDisk].tracks[iTrack].CRC)
|
|
|
|
|
conf += AccDisks[iDisk].tracks[iTrack].count;
|
|
|
|
|
return conf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint Confidence(int iTrack, int oi)
|
|
|
|
|
{
|
|
|
|
|
if (ARStatus != null)
|
|
|
|
|
return 0U;
|
|
|
|
|
uint conf = 0;
|
|
|
|
|
for (int di = 0; di < (int)AccDisks.Count; di++)
|
|
|
|
|
if (CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC)
|
|
|
|
|
conf += AccDisks[di].tracks[iTrack].count;
|
|
|
|
|
return conf;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-04 21:30:56 +00:00
|
|
|
public uint Total(int iTrack)
|
|
|
|
|
{
|
|
|
|
|
if (ARStatus != null)
|
|
|
|
|
return 0U;
|
|
|
|
|
uint total = 0;
|
|
|
|
|
for (int di = 0; di < (int)AccDisks.Count; di++)
|
|
|
|
|
total += AccDisks[di].tracks[iTrack].count;
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint DBCRC(int iTrack)
|
|
|
|
|
{
|
|
|
|
|
return ARStatus == null ? AccDisks[0].tracks[iTrack].CRC : 0U;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-10 02:15:36 +00:00
|
|
|
public uint CRC(int iTrack)
|
|
|
|
|
{
|
|
|
|
|
return CRC(iTrack, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 22:13:06 +00:00
|
|
|
public uint CRC(int iTrack, int oi)
|
|
|
|
|
{
|
2010-02-10 04:53:03 +00:00
|
|
|
int offs0 = iTrack == 0 ? 5 * 588 + oi - 1 : oi;
|
|
|
|
|
int offs1 = iTrack == _toc.AudioTracks - 1 ? 20 * 588 - 5 * 588 + oi : (oi >= 0 ? 0 : 20 * 588 + oi);
|
|
|
|
|
uint crcA = _CRCAR[iTrack + 1, offs1] - (offs0 > 0 ? _CRCAR[iTrack + 1, offs0] : 0);
|
|
|
|
|
uint sumA = _CRCSM[iTrack + 1, offs1] - (offs0 > 0 ? _CRCSM[iTrack + 1, offs0] : 0);
|
|
|
|
|
uint crc = crcA - sumA * (uint)oi;
|
|
|
|
|
if (oi < 0 && iTrack > 0)
|
2010-02-10 02:15:36 +00:00
|
|
|
{
|
2010-02-10 04:53:03 +00:00
|
|
|
uint crcB = _CRCAR[iTrack, 0] - _CRCAR[iTrack, 20 * 588 + oi];
|
|
|
|
|
uint sumB = _CRCSM[iTrack, 0] - _CRCSM[iTrack, 20 * 588 + oi];
|
|
|
|
|
uint posB = _toc[iTrack + _toc.FirstAudio - 1].Length * 588 + (uint)oi;
|
|
|
|
|
crc += crcB - sumB * posB;
|
2010-02-10 02:15:36 +00:00
|
|
|
}
|
2010-02-10 04:53:03 +00:00
|
|
|
if (oi > 0 && iTrack < _toc.AudioTracks - 1)
|
2010-02-10 02:15:36 +00:00
|
|
|
{
|
2010-02-10 04:53:03 +00:00
|
|
|
uint crcB = _CRCAR[iTrack + 2, oi];
|
|
|
|
|
uint sumB = _CRCSM[iTrack + 2, oi];
|
|
|
|
|
uint posB = _toc[iTrack + _toc.FirstAudio].Length * 588 + (uint)-oi;
|
|
|
|
|
crc += crcB + sumB * posB;
|
2010-02-10 02:15:36 +00:00
|
|
|
}
|
2010-02-10 04:53:03 +00:00
|
|
|
return crc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint CRC450(int iTrack, int oi)
|
|
|
|
|
{
|
|
|
|
|
uint crca = _CRCAR[iTrack + 1, 20 * 588 + 5 * 588 + oi];
|
|
|
|
|
uint crcb = _CRCAR[iTrack + 1, 20 * 588 + 6 * 588 + oi];
|
|
|
|
|
uint suma = _CRCSM[iTrack + 1, 20 * 588 + 5 * 588 + oi];
|
|
|
|
|
uint sumb = _CRCSM[iTrack + 1, 20 * 588 + 6 * 588 + oi];
|
|
|
|
|
uint offs = 450 * 588 + (uint)oi;
|
|
|
|
|
return crcb - crca - offs * (sumb - suma);
|
2008-11-28 22:13:06 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-17 04:09:38 +00:00
|
|
|
public uint CRC32(int iTrack)
|
|
|
|
|
{
|
2010-02-09 07:40:37 +00:00
|
|
|
return CRC32(iTrack, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint CRC32(int iTrack, int oi)
|
|
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
if (_CacheCRC32[iTrack, _arOffsetRange + oi] == 0)
|
2010-02-09 07:40:37 +00:00
|
|
|
{
|
|
|
|
|
uint crc = 0xffffffff;
|
|
|
|
|
if (iTrack == 0)
|
|
|
|
|
{
|
|
|
|
|
for (iTrack = 0; iTrack <= _toc.AudioTracks; iTrack++)
|
|
|
|
|
{
|
|
|
|
|
int trackLength = (int)(iTrack > 0 ? _toc[iTrack + _toc.FirstAudio - 1].Length : _toc[_toc.FirstAudio].Pregap) * 588 * 4;
|
2010-02-09 20:05:54 +00:00
|
|
|
if (oi < 0 && iTrack == 0)
|
|
|
|
|
crc = _crc32.Combine(crc, 0, -oi * 4);
|
|
|
|
|
if (trackLength == 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (oi > 0 && (iTrack == 0 || (iTrack == 1 && _toc[_toc.FirstAudio].Pregap == 0)))
|
|
|
|
|
{
|
|
|
|
|
// Calculate track CRC skipping first oi samples by 'subtracting' their CRC
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(_CRC32[iTrack, oi], _CRC32[iTrack, 0], trackLength - oi * 4);
|
2010-02-09 20:05:54 +00:00
|
|
|
// Use 0xffffffff as an initial state
|
|
|
|
|
crc = _crc32.Combine(0xffffffff, crc, trackLength - oi * 4);
|
|
|
|
|
}
|
|
|
|
|
else if (oi < 0 && iTrack == _toc.AudioTracks)
|
|
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(crc, _CRC32[iTrack, 20 * 588 + oi], trackLength + oi * 4);
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(crc, _CRC32[iTrack, 0], trackLength);
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
if (oi > 0 && iTrack == _toc.AudioTracks)
|
|
|
|
|
crc = _crc32.Combine(crc, 0, oi * 4);
|
2010-02-09 07:40:37 +00:00
|
|
|
}
|
|
|
|
|
iTrack = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int trackLength = (int)(iTrack > 0 ? _toc[iTrack + _toc.FirstAudio - 1].Length : _toc[_toc.FirstAudio].Pregap) * 588 * 4;
|
|
|
|
|
if (oi > 0)
|
|
|
|
|
{
|
|
|
|
|
// Calculate track CRC skipping first oi samples by 'subtracting' their CRC
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(_CRC32[iTrack, oi], _CRC32[iTrack, 0], trackLength - oi * 4);
|
2010-02-09 07:40:37 +00:00
|
|
|
// Use 0xffffffff as an initial state
|
|
|
|
|
crc = _crc32.Combine(0xffffffff, crc, trackLength - oi * 4);
|
|
|
|
|
// Add oi samples from next track CRC
|
|
|
|
|
if (iTrack < _toc.AudioTracks)
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(crc, _CRC32[iTrack + 1, oi], oi * 4);
|
2010-02-09 07:40:37 +00:00
|
|
|
else
|
|
|
|
|
crc = _crc32.Combine(crc, 0, oi * 4);
|
|
|
|
|
}
|
|
|
|
|
else if (oi < 0)
|
|
|
|
|
{
|
|
|
|
|
// Calculate CRC of previous track's last oi samples by 'subtracting' it's last CRCs
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(_CRC32[iTrack - 1, 20 * 588 + oi], _CRC32[iTrack - 1, 0], -oi * 4);
|
2010-02-09 07:40:37 +00:00
|
|
|
// Use 0xffffffff as an initial state
|
|
|
|
|
crc = _crc32.Combine(0xffffffff, crc, -oi * 4);
|
|
|
|
|
// Add this track's CRC without last oi samples
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(crc, _CRC32[iTrack, 20 * 588 + oi], trackLength + oi * 4);
|
2010-02-09 07:40:37 +00:00
|
|
|
}
|
|
|
|
|
else // oi == 0
|
|
|
|
|
{
|
|
|
|
|
// Use 0xffffffff as an initial state
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(0xffffffff, _CRC32[iTrack, 0], trackLength);
|
2010-02-09 07:40:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-10 03:51:39 +00:00
|
|
|
_CacheCRC32[iTrack, _arOffsetRange + oi] = crc ^ 0xffffffff;
|
2010-02-09 07:40:37 +00:00
|
|
|
}
|
2010-02-10 03:51:39 +00:00
|
|
|
return _CacheCRC32[iTrack, _arOffsetRange + oi];
|
2009-01-28 04:53:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint CRCWONULL(int iTrack)
|
|
|
|
|
{
|
2010-02-10 02:15:36 +00:00
|
|
|
return CRCWONULL(iTrack, 0);
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint CRCWONULL(int iTrack, int oi)
|
|
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
if (_CacheCRCWN[iTrack, _arOffsetRange + oi] == 0)
|
2010-02-09 20:05:54 +00:00
|
|
|
{
|
|
|
|
|
uint crc = 0xffffffff;
|
|
|
|
|
if (iTrack == 0)
|
|
|
|
|
{
|
|
|
|
|
for (iTrack = 0; iTrack <= _toc.AudioTracks; iTrack++)
|
|
|
|
|
{
|
|
|
|
|
int trackLength = (int)(iTrack > 0 ? _toc[iTrack + _toc.FirstAudio - 1].Length : _toc[_toc.FirstAudio].Pregap) * 588 * 4
|
2010-02-10 03:51:39 +00:00
|
|
|
- _CRCNL[iTrack, 0] * 2;
|
|
|
|
|
crc = _crc32.Combine(crc, _CRCWN[iTrack, 0], trackLength);
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
iTrack = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int trackLength = (int)(iTrack > 0 ? _toc[iTrack + _toc.FirstAudio - 1].Length : _toc[_toc.FirstAudio].Pregap) * 588 * 4;
|
|
|
|
|
if (oi > 0)
|
|
|
|
|
{
|
2010-02-10 02:15:36 +00:00
|
|
|
int nonzeroPrevLength = trackLength - oi * 4 -
|
2010-02-10 03:51:39 +00:00
|
|
|
(_CRCNL[iTrack, 0] - _CRCNL[iTrack, oi]) * 2;
|
2010-02-09 20:05:54 +00:00
|
|
|
// Calculate track CRC skipping first oi samples by 'subtracting' their CRC
|
|
|
|
|
crc = _crc32.Combine(
|
2010-02-10 03:51:39 +00:00
|
|
|
_CRCWN[iTrack, oi],
|
|
|
|
|
_CRCWN[iTrack, 0],
|
2010-02-09 20:05:54 +00:00
|
|
|
nonzeroPrevLength);
|
|
|
|
|
// Use 0xffffffff as an initial state
|
|
|
|
|
crc = _crc32.Combine(0xffffffff, crc, nonzeroPrevLength);
|
|
|
|
|
// Add oi samples from next track CRC
|
|
|
|
|
if (iTrack < _toc.AudioTracks)
|
2010-02-10 02:15:36 +00:00
|
|
|
crc = _crc32.Combine(crc,
|
2010-02-10 03:51:39 +00:00
|
|
|
_CRCWN[iTrack + 1, oi],
|
|
|
|
|
oi * 4 - _CRCNL[iTrack + 1, oi] * 2);
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
else if (oi < 0)
|
|
|
|
|
{
|
2010-02-10 02:15:36 +00:00
|
|
|
int nonzeroPrevLength = -oi * 4 -
|
2010-02-10 03:51:39 +00:00
|
|
|
(_CRCNL[iTrack - 1, 0] - _CRCNL[iTrack - 1, 20 * 588 + oi]) * 2;
|
2010-02-09 20:05:54 +00:00
|
|
|
// Calculate CRC of previous track's last oi samples by 'subtracting' it's last CRCs
|
|
|
|
|
crc = _crc32.Combine(
|
2010-02-10 03:51:39 +00:00
|
|
|
_CRCWN[iTrack - 1, 20 * 588 + oi],
|
|
|
|
|
_CRCWN[iTrack - 1, 0],
|
2010-02-09 20:05:54 +00:00
|
|
|
nonzeroPrevLength);
|
|
|
|
|
// Use 0xffffffff as an initial state
|
|
|
|
|
crc = _crc32.Combine(0xffffffff, crc, nonzeroPrevLength);
|
|
|
|
|
// Add this track's CRC without last oi samples
|
2010-02-10 02:15:36 +00:00
|
|
|
crc = _crc32.Combine(crc,
|
2010-02-10 03:51:39 +00:00
|
|
|
_CRCWN[iTrack, 20 * 588 + oi],
|
|
|
|
|
trackLength + oi * 4 - _CRCNL[iTrack, 20 * 588 + oi] * 2);
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
else // oi == 0
|
|
|
|
|
{
|
|
|
|
|
// Use 0xffffffff as an initial state
|
2010-02-10 03:51:39 +00:00
|
|
|
crc = _crc32.Combine(0xffffffff, _CRCWN[iTrack, 0], trackLength - _CRCNL[iTrack, 0] * 2);
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-10 03:51:39 +00:00
|
|
|
_CacheCRCWN[iTrack, _arOffsetRange + oi] = crc ^ 0xffffffff;
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
2010-02-10 03:51:39 +00:00
|
|
|
return _CacheCRCWN[iTrack, _arOffsetRange + oi];
|
2009-01-28 04:53:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint CRCLOG(int iTrack)
|
|
|
|
|
{
|
|
|
|
|
return _CRCLOG[iTrack];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CRCLOG(int iTrack, uint value)
|
|
|
|
|
{
|
2009-02-23 03:59:50 +00:00
|
|
|
_hasLogCRC = true;
|
2009-01-28 04:53:13 +00:00
|
|
|
_CRCLOG[iTrack] = value;
|
2009-01-17 04:09:38 +00:00
|
|
|
}
|
|
|
|
|
|
2010-02-10 03:51:39 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// This function calculates three different CRCs and also
|
|
|
|
|
/// collects some additional information for the purposes of
|
|
|
|
|
/// offset detection.
|
|
|
|
|
///
|
|
|
|
|
/// crcar is AccurateRip CRC
|
|
|
|
|
/// crc32 is CRC32
|
|
|
|
|
/// crcwn is CRC32 without null samples (EAC)
|
|
|
|
|
/// crcsm is sum of samples
|
2010-02-10 04:53:03 +00:00
|
|
|
/// crcnl is a count of null samples
|
2010-02-10 03:51:39 +00:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="pSampleBuff"></param>
|
|
|
|
|
/// <param name="count"></param>
|
|
|
|
|
/// <param name="currentOffset"></param>
|
|
|
|
|
/// <param name="offs"></param>
|
2010-02-23 15:15:08 +00:00
|
|
|
public unsafe void CalculateCRCs(uint* pSampleBuff, int count, int currentOffset, int offs)
|
2010-02-09 07:40:37 +00:00
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
uint crcar = _CRCAR[_currentTrack, 0];
|
|
|
|
|
uint crcsm = _CRCSM[_currentTrack, 0];
|
|
|
|
|
uint crc32 = _CRC32[_currentTrack, 0];
|
|
|
|
|
uint crcwn = _CRCWN[_currentTrack, 0];
|
2010-02-10 04:53:03 +00:00
|
|
|
int crcnl = _CRCNL[_currentTrack, 0];
|
2010-02-09 07:40:37 +00:00
|
|
|
fixed (uint* t = _crc32.table)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
if (offs >= 0)
|
2010-02-09 20:05:54 +00:00
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
_CRCAR[_currentTrack, offs + i] = crcar;
|
|
|
|
|
_CRCSM[_currentTrack, offs + i] = crcsm;
|
|
|
|
|
_CRC32[_currentTrack, offs + i] = crc32;
|
|
|
|
|
_CRCWN[_currentTrack, offs + i] = crcwn;
|
2010-02-10 04:53:03 +00:00
|
|
|
_CRCNL[_currentTrack, offs + i] = crcnl;
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
2010-02-09 07:40:37 +00:00
|
|
|
|
2010-02-23 15:15:08 +00:00
|
|
|
uint sample = *(pSampleBuff++);
|
|
|
|
|
crcsm += sample;
|
|
|
|
|
crcar += sample * (uint)(currentOffset + i + 1);
|
|
|
|
|
|
|
|
|
|
uint lo = sample & 0xffff;
|
2010-02-10 03:51:39 +00:00
|
|
|
crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ lo)];
|
|
|
|
|
crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ (lo >> 8))];
|
2010-02-10 02:15:36 +00:00
|
|
|
if (lo != 0)
|
2010-02-09 20:05:54 +00:00
|
|
|
{
|
2010-02-10 02:15:36 +00:00
|
|
|
crcwn = (crcwn >> 8) ^ t[(byte)(crcwn ^ lo)];
|
|
|
|
|
crcwn = (crcwn >> 8) ^ t[(byte)(crcwn ^ (lo >> 8))];
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
2010-02-10 04:53:03 +00:00
|
|
|
else crcnl++;
|
2010-02-09 07:40:37 +00:00
|
|
|
|
2010-02-23 15:15:08 +00:00
|
|
|
uint hi = sample >> 16;
|
2010-02-10 03:51:39 +00:00
|
|
|
crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ hi)];
|
|
|
|
|
crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ (hi >> 8))];
|
2010-02-10 02:15:36 +00:00
|
|
|
if (hi != 0)
|
2010-02-09 20:05:54 +00:00
|
|
|
{
|
2010-02-10 02:15:36 +00:00
|
|
|
crcwn = (crcwn >> 8) ^ t[(byte)(crcwn ^ hi)];
|
|
|
|
|
crcwn = (crcwn >> 8) ^ t[(byte)(crcwn ^ (hi >> 8))];
|
2010-02-09 20:05:54 +00:00
|
|
|
}
|
2010-02-10 04:53:03 +00:00
|
|
|
else crcnl++;
|
2010-02-09 07:40:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-10 03:51:39 +00:00
|
|
|
|
|
|
|
|
_CRCAR[_currentTrack, 0] = crcar;
|
|
|
|
|
_CRCSM[_currentTrack, 0] = crcsm;
|
|
|
|
|
_CRC32[_currentTrack, 0] = crc32;
|
|
|
|
|
_CRCWN[_currentTrack, 0] = crcwn;
|
2010-02-10 04:53:03 +00:00
|
|
|
_CRCNL[_currentTrack, 0] = crcnl;
|
2010-02-06 23:17:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Write(AudioBuffer sampleBuffer)
|
|
|
|
|
{
|
|
|
|
|
sampleBuffer.Prepare(this);
|
|
|
|
|
|
|
|
|
|
int pos = 0;
|
|
|
|
|
while (pos < sampleBuffer.Length)
|
2008-11-28 22:13:06 +00:00
|
|
|
{
|
2010-02-09 07:40:37 +00:00
|
|
|
// Process no more than there is in the buffer, no more than there is in this track, and no more than up to a sector boundary.
|
|
|
|
|
int copyCount = Math.Min(Math.Min(sampleBuffer.Length - pos, (int)_samplesRemTrack), 588 - (int)_sampleCount % 588);
|
|
|
|
|
// Calculate offset within a track
|
|
|
|
|
int currentOffset = (int)_sampleCount - (int)(_currentTrack > 0 ? _toc[_currentTrack + _toc.FirstAudio - 1].Start * 588 : 0);
|
|
|
|
|
int currentSector = currentOffset / 588;
|
|
|
|
|
int remaingSectors = (int)(_samplesRemTrack - 1) / 588;
|
2010-02-10 02:15:36 +00:00
|
|
|
|
2009-01-17 04:09:38 +00:00
|
|
|
unsafe
|
2008-11-28 22:13:06 +00:00
|
|
|
{
|
2010-02-23 15:15:08 +00:00
|
|
|
fixed (byte* pSampleBuff = &sampleBuffer.Bytes[pos * 4])
|
2008-11-28 22:13:06 +00:00
|
|
|
{
|
2010-02-23 15:15:08 +00:00
|
|
|
uint* samples = (uint*)pSampleBuff;
|
2010-02-10 03:51:39 +00:00
|
|
|
if (currentSector < 10)
|
2010-02-23 15:15:08 +00:00
|
|
|
CalculateCRCs(samples, copyCount, currentOffset, currentOffset);
|
2010-02-10 03:51:39 +00:00
|
|
|
else if (remaingSectors < 10)
|
2010-02-23 15:15:08 +00:00
|
|
|
CalculateCRCs(samples, copyCount, currentOffset, 20 * 588 - (int)_samplesRemTrack);
|
2010-02-10 03:51:39 +00:00
|
|
|
else if (currentSector >= 445 && currentSector <= 455)
|
2010-02-23 15:15:08 +00:00
|
|
|
CalculateCRCs(samples, copyCount, currentOffset, 20 * 588 + currentOffset - 445 * 588);
|
2010-02-10 02:15:36 +00:00
|
|
|
else
|
2010-02-23 15:15:08 +00:00
|
|
|
CalculateCRCs(samples, copyCount, currentOffset, -1);
|
2008-11-28 22:13:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pos += copyCount;
|
|
|
|
|
_samplesRemTrack -= copyCount;
|
|
|
|
|
_sampleCount += copyCount;
|
|
|
|
|
CheckPosition();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Init()
|
|
|
|
|
{
|
2010-02-10 03:51:39 +00:00
|
|
|
_CRCAR = new uint[_toc.AudioTracks + 1, 31 * 588];
|
|
|
|
|
_CRCSM = new uint[_toc.AudioTracks + 1, 31 * 588];
|
|
|
|
|
_CRC32 = new uint[_toc.AudioTracks + 1, 31 * 588];
|
|
|
|
|
_CacheCRC32 = new uint[_toc.AudioTracks + 1, 31 * 588];
|
|
|
|
|
_CRCWN = new uint[_toc.AudioTracks + 1, 31 * 588];
|
|
|
|
|
_CacheCRCWN = new uint[_toc.AudioTracks + 1, 31 * 588];
|
|
|
|
|
_CRCNL = new int[_toc.AudioTracks + 1, 31 * 588];
|
2008-11-28 22:13:06 +00:00
|
|
|
_currentTrack = 0;
|
2009-01-28 04:53:13 +00:00
|
|
|
_sampleCount = _toc[_toc.FirstAudio][0].Start * 588;
|
|
|
|
|
_samplesRemTrack = _toc[_toc.FirstAudio].Pregap * 588;
|
2008-11-28 22:13:06 +00:00
|
|
|
CheckPosition();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CheckPosition()
|
|
|
|
|
{
|
|
|
|
|
while (_samplesRemTrack <= 0)
|
|
|
|
|
{
|
|
|
|
|
if (++_currentTrack > _toc.AudioTracks)
|
|
|
|
|
return;
|
2009-01-28 04:53:13 +00:00
|
|
|
_samplesRemTrack = _toc[_currentTrack + _toc.FirstAudio - 1].Length * 588;
|
2008-11-28 22:13:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private uint readIntLE(byte[] data, int pos)
|
|
|
|
|
{
|
|
|
|
|
return (uint)(data[pos] + (data[pos + 1] << 8) + (data[pos + 2] << 16) + (data[pos + 3] << 24));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ContactAccurateRip(string accurateRipId)
|
|
|
|
|
{
|
|
|
|
|
// Calculate the three disc ids used by AR
|
|
|
|
|
uint discId1 = 0;
|
|
|
|
|
uint discId2 = 0;
|
|
|
|
|
uint cddbDiscId = 0;
|
|
|
|
|
|
|
|
|
|
string[] n = accurateRipId.Split('-');
|
|
|
|
|
if (n.Length != 3)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Invalid accurateRipId.");
|
|
|
|
|
}
|
|
|
|
|
discId1 = UInt32.Parse(n[0], NumberStyles.HexNumber);
|
|
|
|
|
discId2 = UInt32.Parse(n[1], NumberStyles.HexNumber);
|
|
|
|
|
cddbDiscId = UInt32.Parse(n[2], NumberStyles.HexNumber);
|
|
|
|
|
|
|
|
|
|
string url = String.Format("http://www.accuraterip.com/accuraterip/{0:x}/{1:x}/{2:x}/dBAR-{3:d3}-{4:x8}-{5:x8}-{6:x8}.bin",
|
|
|
|
|
discId1 & 0xF, discId1 >> 4 & 0xF, discId1 >> 8 & 0xF, _toc.AudioTracks, discId1, discId2, cddbDiscId);
|
|
|
|
|
|
|
|
|
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
|
|
|
|
req.Method = "GET";
|
2010-02-23 15:15:08 +00:00
|
|
|
req.Proxy = proxy;
|
2008-11-28 22:13:06 +00:00
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
|
|
|
|
|
_accResult = resp.StatusCode;
|
|
|
|
|
|
|
|
|
|
if (_accResult == HttpStatusCode.OK)
|
|
|
|
|
{
|
|
|
|
|
// Retrieve response stream and wrap in StreamReader
|
|
|
|
|
Stream respStream = resp.GetResponseStream();
|
|
|
|
|
|
|
|
|
|
// Allocate byte buffer to hold stream contents
|
|
|
|
|
byte[] urlData = new byte[13];
|
|
|
|
|
int urlDataLen, bytesRead;
|
|
|
|
|
|
|
|
|
|
_accDisks.Clear();
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
for (urlDataLen = 0; urlDataLen < 13; urlDataLen += bytesRead)
|
|
|
|
|
{
|
|
|
|
|
bytesRead = respStream.Read(urlData, urlDataLen, 13 - urlDataLen);
|
|
|
|
|
if (0 == bytesRead)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (urlDataLen == 0)
|
|
|
|
|
break;
|
|
|
|
|
if (urlDataLen < 13)
|
|
|
|
|
{
|
|
|
|
|
_accResult = HttpStatusCode.PartialContent;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
AccDisk dsk = new AccDisk();
|
|
|
|
|
dsk.count = urlData[0];
|
|
|
|
|
dsk.discId1 = readIntLE(urlData, 1);
|
|
|
|
|
dsk.discId2 = readIntLE(urlData, 5);
|
|
|
|
|
dsk.cddbDiscId = readIntLE(urlData, 9);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < dsk.count; i++)
|
|
|
|
|
{
|
|
|
|
|
for (urlDataLen = 0; urlDataLen < 9; urlDataLen += bytesRead)
|
|
|
|
|
{
|
|
|
|
|
bytesRead = respStream.Read(urlData, urlDataLen, 9 - urlDataLen);
|
|
|
|
|
if (0 == bytesRead)
|
|
|
|
|
{
|
|
|
|
|
_accResult = HttpStatusCode.PartialContent;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AccTrack trk = new AccTrack();
|
|
|
|
|
trk.count = urlData[0];
|
|
|
|
|
trk.CRC = readIntLE(urlData, 1);
|
|
|
|
|
trk.Frame450CRC = readIntLE(urlData, 5);
|
|
|
|
|
dsk.tracks.Add(trk);
|
|
|
|
|
}
|
|
|
|
|
_accDisks.Add(dsk);
|
|
|
|
|
}
|
|
|
|
|
respStream.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (WebException ex)
|
|
|
|
|
{
|
|
|
|
|
if (ex.Status == WebExceptionStatus.ProtocolError)
|
|
|
|
|
_accResult = ((HttpWebResponse)ex.Response).StatusCode;
|
|
|
|
|
else
|
|
|
|
|
_accResult = HttpStatusCode.BadRequest;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Close()
|
|
|
|
|
{
|
|
|
|
|
if (_sampleCount != _finalSampleCount)
|
|
|
|
|
throw new Exception("_sampleCount != _finalSampleCount");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Delete()
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("unsupported");
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-06 23:17:07 +00:00
|
|
|
public int CompressionLevel
|
2008-11-28 22:13:06 +00:00
|
|
|
{
|
2010-02-06 23:17:07 +00:00
|
|
|
get { return 0; }
|
|
|
|
|
set { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Options
|
|
|
|
|
{
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (value == null || value == "") return;
|
|
|
|
|
throw new Exception("Unsupported options " + value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AudioPCMConfig PCM
|
|
|
|
|
{
|
|
|
|
|
get { return AudioPCMConfig.RedBook; }
|
2008-11-28 22:13:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public long FinalSampleCount
|
|
|
|
|
{
|
2010-02-06 23:17:07 +00:00
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (value < 0) // != _toc.Length?
|
|
|
|
|
throw new Exception("invalid FinalSampleCount");
|
|
|
|
|
_finalSampleCount = value;
|
|
|
|
|
}
|
2008-11-28 22:13:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public long BlockSize
|
|
|
|
|
{
|
|
|
|
|
set { throw new Exception("unsupported"); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Path
|
|
|
|
|
{
|
|
|
|
|
get { throw new Exception("unsupported"); }
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-30 00:03:49 +00:00
|
|
|
public void GenerateLog(TextWriter sw, int oi)
|
2008-11-28 22:13:06 +00:00
|
|
|
{
|
|
|
|
|
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
|
|
|
|
{
|
|
|
|
|
uint count = 0;
|
|
|
|
|
uint partials = 0;
|
|
|
|
|
uint conf = 0;
|
|
|
|
|
for (int di = 0; di < (int)AccDisks.Count; di++)
|
|
|
|
|
{
|
|
|
|
|
count += AccDisks[di].tracks[iTrack].count;
|
|
|
|
|
if (CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC)
|
|
|
|
|
conf += AccDisks[di].tracks[iTrack].count;
|
|
|
|
|
if (CRC450(iTrack, oi) == AccDisks[di].tracks[iTrack].Frame450CRC)
|
|
|
|
|
partials += AccDisks[di].tracks[iTrack].count;
|
|
|
|
|
}
|
|
|
|
|
if (conf > 0)
|
2009-08-06 13:03:02 +00:00
|
|
|
sw.WriteLine(String.Format(" {0:00}\t[{1:x8}] ({3:00}/{2:00}) Accurately ripped", iTrack + 1, CRC(iTrack, oi), count, conf));
|
2008-11-28 22:13:06 +00:00
|
|
|
else if (partials > 0)
|
2009-08-06 13:03:02 +00:00
|
|
|
sw.WriteLine(String.Format(" {0:00}\t[{1:x8}] ({3:00}/{2:00}) Partial match", iTrack + 1, CRC(iTrack, oi), count, partials));
|
2008-11-28 22:13:06 +00:00
|
|
|
else
|
|
|
|
|
sw.WriteLine(String.Format(" {0:00}\t[{1:x8}] (00/{2:00}) No matches", iTrack + 1, CRC(iTrack, oi), count));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-01 15:16:26 +00:00
|
|
|
public void GenerateFullLog(TextWriter sw, bool verbose)
|
2008-11-30 00:03:49 +00:00
|
|
|
{
|
|
|
|
|
if (AccResult == HttpStatusCode.NotFound)
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("Disk not present in database.");
|
|
|
|
|
//for (iTrack = 0; iTrack < TrackCount; iTrack++)
|
|
|
|
|
// sw.WriteLine(String.Format(" {0:00}\t[{1:x8}] Disk not present in database", iTrack + 1, _tracks[iTrack].CRC));
|
|
|
|
|
}
|
|
|
|
|
else if (AccResult != HttpStatusCode.OK)
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("Database access error: " + AccResult.ToString());
|
|
|
|
|
//for (iTrack = 0; iTrack < TrackCount; iTrack++)
|
|
|
|
|
// sw.WriteLine(String.Format(" {0:00}\t[{1:x8}] Database access error {2}", iTrack + 1, _tracks[iTrack].CRC, accResult.ToString()));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-05-01 15:16:26 +00:00
|
|
|
if (verbose)
|
2008-11-30 00:03:49 +00:00
|
|
|
{
|
2009-05-01 15:16:26 +00:00
|
|
|
sw.WriteLine("Track\t[ CRC ] Status");
|
|
|
|
|
GenerateLog(sw, 0);
|
|
|
|
|
uint offsets_match = 0;
|
|
|
|
|
for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++)
|
2008-11-30 00:03:49 +00:00
|
|
|
{
|
2009-05-01 15:16:26 +00:00
|
|
|
uint matches = 0;
|
|
|
|
|
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
|
|
|
|
for (int di = 0; di < (int)AccDisks.Count; di++)
|
2009-08-06 13:03:02 +00:00
|
|
|
if ((CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC && AccDisks[di].tracks[iTrack].CRC != 0))
|
|
|
|
|
{
|
2009-05-01 15:16:26 +00:00
|
|
|
matches++;
|
2009-08-06 13:03:02 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (matches == _toc.AudioTracks && oi != 0)
|
2008-11-30 00:03:49 +00:00
|
|
|
{
|
2009-08-06 13:03:02 +00:00
|
|
|
if (offsets_match++ > 16)
|
2009-05-01 15:16:26 +00:00
|
|
|
{
|
2009-08-06 13:03:02 +00:00
|
|
|
sw.WriteLine("More than 16 offsets match!");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sw.WriteLine("Offsetted by {0}:", oi);
|
|
|
|
|
GenerateLog(sw, oi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
offsets_match = 0;
|
|
|
|
|
for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++)
|
|
|
|
|
{
|
|
|
|
|
uint matches = 0, partials = 0;
|
|
|
|
|
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
|
|
|
|
for (int di = 0; di < (int)AccDisks.Count; di++)
|
|
|
|
|
{
|
|
|
|
|
if ((CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC && AccDisks[di].tracks[iTrack].CRC != 0))
|
|
|
|
|
{
|
2010-02-10 02:15:36 +00:00
|
|
|
matches++;
|
2009-08-06 13:03:02 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ((CRC450(iTrack, oi) == AccDisks[di].tracks[iTrack].Frame450CRC && AccDisks[di].tracks[iTrack].Frame450CRC != 0))
|
|
|
|
|
partials++;
|
|
|
|
|
}
|
|
|
|
|
if (matches != _toc.AudioTracks && oi != 0 && matches + partials != 0)
|
|
|
|
|
{
|
|
|
|
|
if (offsets_match++ > 16)
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("More than 16 offsets match!");
|
2009-05-01 15:16:26 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sw.WriteLine("Offsetted by {0}:", oi);
|
|
|
|
|
GenerateLog(sw, oi);
|
2008-11-30 00:03:49 +00:00
|
|
|
}
|
2009-05-01 15:16:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sw.WriteLine("Track\t Status");
|
|
|
|
|
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
|
|
|
|
{
|
|
|
|
|
uint total = Total(iTrack);
|
2009-08-06 13:03:02 +00:00
|
|
|
uint conf = 0;
|
2009-05-01 15:16:26 +00:00
|
|
|
bool zeroOffset = false;
|
2009-05-10 18:34:49 +00:00
|
|
|
StringBuilder pressings = new StringBuilder();
|
|
|
|
|
for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++)
|
|
|
|
|
for (int iDisk = 0; iDisk < AccDisks.Count; iDisk++)
|
2009-05-01 15:16:26 +00:00
|
|
|
{
|
2009-05-10 18:34:49 +00:00
|
|
|
if (CRC(iTrack, oi) == AccDisks[iDisk].tracks[iTrack].CRC && (AccDisks[iDisk].tracks[iTrack].CRC != 0 || oi == 0))
|
2009-05-01 15:16:26 +00:00
|
|
|
{
|
|
|
|
|
conf += AccDisks[iDisk].tracks[iTrack].count;
|
|
|
|
|
if (oi == 0)
|
|
|
|
|
zeroOffset = true;
|
2009-05-10 18:34:49 +00:00
|
|
|
pressings.AppendFormat("{0}{1}({2})", pressings.Length > 0 ? "," : "", oi, AccDisks[iDisk].tracks[iTrack].count);
|
|
|
|
|
}
|
2009-05-01 15:16:26 +00:00
|
|
|
}
|
2009-08-06 13:03:02 +00:00
|
|
|
if (conf > 0 && zeroOffset && pressings.Length == 0)
|
2009-05-01 15:16:26 +00:00
|
|
|
sw.WriteLine(String.Format(" {0:00}\t ({2:00}/{1:00}) Accurately ripped", iTrack + 1, total, conf));
|
2009-08-06 13:03:02 +00:00
|
|
|
else if (conf > 0 && zeroOffset)
|
|
|
|
|
sw.WriteLine(String.Format(" {0:00}\t ({2:00}/{1:00}) Accurately ripped, all offset(s) {3}", iTrack + 1, total, conf, pressings));
|
2009-05-01 15:16:26 +00:00
|
|
|
else if (conf > 0)
|
|
|
|
|
sw.WriteLine(String.Format(" {0:00}\t ({2:00}/{1:00}) Accurately ripped with offset(s) {3}", iTrack + 1, total, conf, pressings));
|
|
|
|
|
else if (total > 0)
|
2009-08-06 13:03:02 +00:00
|
|
|
sw.WriteLine(String.Format(" {0:00}\t (00/{1:00}) NOT ACCURATE", iTrack + 1, total));
|
2009-05-01 15:16:26 +00:00
|
|
|
else
|
|
|
|
|
sw.WriteLine(String.Format(" {0:00}\t (00/00) Track not present in database", iTrack + 1));
|
2008-11-30 00:03:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-05-01 15:16:26 +00:00
|
|
|
if (CRC32(0) != 0 && (_hasLogCRC || verbose))
|
2009-01-17 04:09:38 +00:00
|
|
|
{
|
|
|
|
|
sw.WriteLine("");
|
2009-02-23 03:59:50 +00:00
|
|
|
sw.WriteLine("Track\t[ CRC32 ]\t[W/O NULL]\t{0:10}", _hasLogCRC ? "[ LOG ]" : "");
|
2010-02-09 20:05:54 +00:00
|
|
|
for (int iTrack = 0; iTrack <= _toc.AudioTracks; iTrack++)
|
2009-05-10 18:34:49 +00:00
|
|
|
{
|
|
|
|
|
string inLog, extra = "";
|
2010-02-09 07:40:37 +00:00
|
|
|
if (CRCLOG(iTrack) == 0)
|
|
|
|
|
inLog = "";
|
|
|
|
|
else if (CRCLOG(iTrack) == CRC32(iTrack))
|
2009-05-10 18:34:49 +00:00
|
|
|
inLog = " CRC32 ";
|
|
|
|
|
else if (CRCLOG(iTrack) == CRCWONULL(iTrack))
|
|
|
|
|
inLog = " W/O NULL ";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
inLog = String.Format("[{0:X8}]", CRCLOG(iTrack));
|
|
|
|
|
for (int jTrack = 1; jTrack <= _toc.AudioTracks; jTrack++)
|
|
|
|
|
{
|
|
|
|
|
if (CRCLOG(iTrack) == CRC32(jTrack))
|
|
|
|
|
{
|
|
|
|
|
extra = string.Format(": CRC32 for track {0}", jTrack);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (CRCLOG(iTrack) == CRCWONULL(jTrack))
|
|
|
|
|
{
|
2010-02-09 07:40:37 +00:00
|
|
|
extra = string.Format(": W/O NULL for track {0}", jTrack);
|
2009-05-10 18:34:49 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-09 07:40:37 +00:00
|
|
|
if (extra == "")
|
|
|
|
|
for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++)
|
|
|
|
|
if (CRCLOG(iTrack) == CRC32(iTrack, oi))
|
|
|
|
|
{
|
|
|
|
|
inLog = " CRC32 ";
|
|
|
|
|
extra = string.Format(": offset {0}", oi);
|
2010-02-09 20:05:54 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (extra == "")
|
|
|
|
|
for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++)
|
|
|
|
|
if (CRCLOG(iTrack) == CRCWONULL(iTrack, oi))
|
|
|
|
|
{
|
|
|
|
|
inLog = " W/O NULL ";
|
|
|
|
|
if (extra == "")
|
|
|
|
|
extra = string.Format(": offset {0}", oi);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
extra = string.Format(": with offset");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-09 07:40:37 +00:00
|
|
|
}
|
2009-05-10 18:34:49 +00:00
|
|
|
}
|
2010-02-09 20:05:54 +00:00
|
|
|
sw.WriteLine(String.Format(" {0}\t[{1:X8}]\t[{2:X8}]\t{3:10}{4}", iTrack == 0 ? "--" : string.Format("{0:00}", iTrack), CRC32(iTrack), CRCWONULL(iTrack), inLog, extra));
|
2009-05-10 18:34:49 +00:00
|
|
|
}
|
2009-01-17 04:09:38 +00:00
|
|
|
}
|
2008-11-30 00:03:49 +00:00
|
|
|
}
|
|
|
|
|
|
2008-11-28 23:07:43 +00:00
|
|
|
private static uint sumDigits(uint n)
|
|
|
|
|
{
|
|
|
|
|
uint r = 0;
|
|
|
|
|
while (n > 0)
|
|
|
|
|
{
|
|
|
|
|
r = r + (n % 10);
|
|
|
|
|
n = n / 10;
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-01 21:54:55 +00:00
|
|
|
static string CachePath
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
string cache = System.IO.Path.Combine(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CUE Tools"), "AccurateRipCache");
|
|
|
|
|
if (!Directory.Exists(cache))
|
|
|
|
|
Directory.CreateDirectory(cache);
|
|
|
|
|
return cache;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool FindDriveReadOffset(string driveName, out int driveReadOffset)
|
|
|
|
|
{
|
|
|
|
|
string fileName = System.IO.Path.Combine(CachePath, "DriveOffsets.bin");
|
|
|
|
|
if (!File.Exists(fileName))
|
|
|
|
|
{
|
|
|
|
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://www.accuraterip.com/accuraterip/DriveOffsets.bin");
|
|
|
|
|
req.Method = "GET";
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
|
|
|
|
|
if (resp.StatusCode != HttpStatusCode.OK)
|
|
|
|
|
{
|
|
|
|
|
driveReadOffset = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Stream respStream = resp.GetResponseStream();
|
|
|
|
|
FileStream myOffsetsSaved = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write);
|
2010-02-10 02:15:36 +00:00
|
|
|
byte[] buff = new byte[0x8000];
|
2008-12-01 21:54:55 +00:00
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
int count = respStream.Read(buff, 0, buff.Length);
|
|
|
|
|
if (count == 0) break;
|
|
|
|
|
myOffsetsSaved.Write(buff, 0, count);
|
|
|
|
|
} while (true);
|
|
|
|
|
respStream.Close();
|
|
|
|
|
myOffsetsSaved.Close();
|
|
|
|
|
}
|
|
|
|
|
catch (WebException ex)
|
|
|
|
|
{
|
|
|
|
|
driveReadOffset = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FileStream myOffsets = new FileStream(fileName, FileMode.Open, FileAccess.Read);
|
|
|
|
|
BinaryReader offsetReader = new BinaryReader(myOffsets);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
short readOffset = offsetReader.ReadInt16();
|
|
|
|
|
byte[] name = offsetReader.ReadBytes(0x21);
|
|
|
|
|
byte[] misc = offsetReader.ReadBytes(0x22);
|
|
|
|
|
int len = name.Length;
|
|
|
|
|
while (len > 0 && name[len - 1] == '\0') len--;
|
2010-02-10 02:15:36 +00:00
|
|
|
string strname = Encoding.ASCII.GetString(name, 0, len);
|
2008-12-01 21:54:55 +00:00
|
|
|
if (strname == driveName)
|
|
|
|
|
{
|
|
|
|
|
driveReadOffset = readOffset;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} while (myOffsets.Position + 0x45 <= myOffsets.Length);
|
|
|
|
|
offsetReader.Close();
|
|
|
|
|
driveReadOffset = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-10 19:44:09 +00:00
|
|
|
public static string CalculateCDDBQuery(CDImageLayout toc)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder query = new StringBuilder(CalculateCDDBId(toc));
|
|
|
|
|
query.AppendFormat("+{0}", toc.TrackCount);
|
|
|
|
|
for (int iTrack = 1; iTrack <= toc.TrackCount; iTrack++)
|
|
|
|
|
query.AppendFormat("+{0}", toc[iTrack].Start + 150);
|
|
|
|
|
query.AppendFormat("+{0}", toc.Length / 75 - toc[1].Start / 75);
|
|
|
|
|
return query.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 23:07:43 +00:00
|
|
|
public static string CalculateCDDBId(CDImageLayout toc)
|
|
|
|
|
{
|
|
|
|
|
uint cddbDiscId = 0;
|
|
|
|
|
for (int iTrack = 1; iTrack <= toc.TrackCount; iTrack++)
|
2009-01-17 04:09:38 +00:00
|
|
|
cddbDiscId += sumDigits(toc[iTrack].Start / 75 + 2); // !!!!!!!!!!!!!!!!! %255 !!
|
|
|
|
|
return string.Format("{0:X8}", (((cddbDiscId % 255) << 24) + ((toc.Length / 75 - toc[1].Start / 75) << 8) + (uint)toc.TrackCount) & 0xFFFFFFFF);
|
2008-11-28 23:07:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string CalculateAccurateRipId(CDImageLayout toc)
|
|
|
|
|
{
|
|
|
|
|
// Calculate the three disc ids used by AR
|
|
|
|
|
uint discId1 = 0;
|
|
|
|
|
uint discId2 = 0;
|
2009-01-28 04:53:13 +00:00
|
|
|
uint num = 0;
|
|
|
|
|
|
2008-11-28 23:07:43 +00:00
|
|
|
for (int iTrack = 1; iTrack <= toc.TrackCount; iTrack++)
|
|
|
|
|
if (toc[iTrack].IsAudio)
|
|
|
|
|
{
|
|
|
|
|
discId1 += toc[iTrack].Start;
|
2009-01-28 04:53:13 +00:00
|
|
|
discId2 += Math.Max(toc[iTrack].Start, 1) * (++num);
|
2008-11-28 23:07:43 +00:00
|
|
|
}
|
|
|
|
|
discId1 += toc.Length;
|
2009-01-28 04:53:13 +00:00
|
|
|
discId2 += Math.Max(toc.Length, 1) * (++num);
|
2008-11-28 23:07:43 +00:00
|
|
|
discId1 &= 0xFFFFFFFF;
|
|
|
|
|
discId2 &= 0xFFFFFFFF;
|
|
|
|
|
return string.Format("{0:x8}-{1:x8}-{2}", discId1, discId2, CalculateCDDBId(toc).ToLower());
|
|
|
|
|
}
|
2008-11-28 22:13:06 +00:00
|
|
|
|
|
|
|
|
public List<AccDisk> AccDisks
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _accDisks;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public HttpStatusCode AccResult
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _accResult;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string ARStatus
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _accResult == HttpStatusCode.NotFound ? "disk not present in database" :
|
|
|
|
|
_accResult == HttpStatusCode.OK ? null
|
|
|
|
|
: _accResult.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CDImageLayout _toc;
|
|
|
|
|
long _sampleCount, _finalSampleCount, _samplesRemTrack;
|
|
|
|
|
int _currentTrack;
|
|
|
|
|
private List<AccDisk> _accDisks;
|
|
|
|
|
private HttpStatusCode _accResult;
|
2010-02-10 03:51:39 +00:00
|
|
|
private uint[,] _CRCAR;
|
|
|
|
|
private uint[,] _CRCSM;
|
|
|
|
|
private uint[,] _CRC32;
|
|
|
|
|
private uint[,] _CRCWN;
|
|
|
|
|
private int[,] _CRCNL;
|
|
|
|
|
private uint[,] _CacheCRCWN;
|
|
|
|
|
private uint[,] _CacheCRC32;
|
2010-02-09 20:05:54 +00:00
|
|
|
private uint[] _CRCLOG;
|
2010-02-23 15:15:08 +00:00
|
|
|
private IWebProxy proxy;
|
2008-11-28 22:13:06 +00:00
|
|
|
|
2009-01-17 04:09:38 +00:00
|
|
|
Crc32 _crc32;
|
|
|
|
|
|
2009-02-23 03:59:50 +00:00
|
|
|
private bool _hasLogCRC;
|
|
|
|
|
|
2008-11-28 22:13:06 +00:00
|
|
|
private const int _arOffsetRange = 5 * 588 - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public struct AccTrack
|
|
|
|
|
{
|
|
|
|
|
public uint count;
|
|
|
|
|
public uint CRC;
|
|
|
|
|
public uint Frame450CRC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class AccDisk
|
|
|
|
|
{
|
|
|
|
|
public uint count;
|
|
|
|
|
public uint discId1;
|
|
|
|
|
public uint discId2;
|
|
|
|
|
public uint cddbDiscId;
|
|
|
|
|
public List<AccTrack> tracks;
|
|
|
|
|
|
|
|
|
|
public AccDisk()
|
|
|
|
|
{
|
|
|
|
|
tracks = new List<AccTrack>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|