This commit is contained in:
chudov
2011-11-15 10:56:49 +00:00
parent 18af0c595d
commit 4520762a72
25 changed files with 1958 additions and 780 deletions

View File

@@ -13,7 +13,7 @@ namespace CUETools.AccurateRip
{
public class AccurateRipVerify : IAudioDest
{
public const int maxNpar = 8;
public const int maxNpar = 16;
public AccurateRipVerify(CDImageLayout toc, IWebProxy proxy)
{
@@ -314,21 +314,68 @@ namespace CUETools.AccurateRip
_CRCLOG[iTrack] = value;
}
public unsafe byte[] GetParity(int npar = maxNpar)
public unsafe ushort[,] GetSyndrome(int npar = maxNpar, int strides = -1, int offset = 0)
{
if (npar == maxNpar)
return this.parity;
var synShort = this.GetSyndrome(npar);
return ParityToSyndrome.Syndrome2Parity(synShort);
}
public unsafe ushort[,] GetSyndrome(int npar = maxNpar)
{
// We can only use offset if Abs(offset * 2) < stride,
// else we might need to add/remove more than one sample
// from syndrome calculations, and that would be too difficult
// and will probably require longer leadin/leadout.
if (!calcParity)
throw new InvalidOperationException();
return ParityToSyndrome.Parity2Syndrome(stride, npar, maxNpar, parity);
}
if (strides == -1)
strides = stride;
var syn = ParityToSyndrome.Parity2Syndrome(strides, stride, npar, maxNpar, parity, 0, -offset * 2);
var galois = Galois16.instance;
for (int part2 = 0; part2 < strides; part2++)
{
int part = (part2 + offset * 2 + stride) % stride;
if (part < offset * 2)
{
for (int i = 0; i < npar; i++)
{
int synI = syn[part2, i];
synI = galois.mulExp(synI, i);
synI ^= leadout[laststride - part - 1] ^ galois.mulExp(leadin[stride + part], (i * stridecount) % galois.Max);
syn[part2, i] = (ushort)synI;
}
}
if (part >= stride + offset * 2)
{
for (int i = 0; i < npar; i++)
{
int synI = syn[part2, i];
synI ^= leadout[laststride + stride - part - 1] ^ galois.mulExp(leadin[part], (i * stridecount) % galois.Max);
synI = galois.divExp(synI, i);
syn[part2, i] = (ushort)synI;
}
}
}
//for (int part = 0; part < offset * 2; part++)
//{
// int part2 = (part - offset * 2 + stride) % stride;
// if (part2 < strides)
// for (int i = 0; i < npar; i++)
// {
// int synI = syn[part2, i];
// synI = galois.mulExp(synI, i);
// synI ^= leadout[laststride - part - 1] ^ galois.mulExp(leadin[stride + part], (i * stridecount) % galois.Max);
// syn[part2, i] = (ushort)synI;
// }
//}
//for (int part = stride + offset * 2; part < stride; part++)
//{
// int part2 = (part - offset * 2 + stride) % stride;
// if (part2 < strides)
// for (int i = 0; i < npar; i++)
// {
// int synI = syn[part2, i];
// synI ^= leadout[laststride + stride - part - 1] ^ galois.mulExp(leadin[part], (i * stridecount) % galois.Max);
// synI = galois.divExp(synI, i);
// syn[part2, i] = (ushort)synI;
// }
//}
return syn;
}
private byte[] parity;
internal ushort[, ,] encodeTable;
@@ -401,69 +448,37 @@ namespace CUETools.AccurateRip
return CTDBCRC(0, offset, stride / 2, laststride / 2);
}
//private unsafe static void CalcPar8(ushort* pt, ushort* wr, uint lo)
//{
// uint wrlo = wr[0] ^ lo;
// ushort* ptiblo0 = pt + (wrlo & 255) * 16;
// ushort* ptiblo1 = pt + (wrlo >> 8) * 16 + 8;
// ((ulong*)wr)[0] = ((ulong*)(wr + 1))[0] ^ ((ulong*)ptiblo0)[0] ^ ((ulong*)ptiblo1)[0];
// ((ulong*)wr)[1] = (((ulong*)(wr))[1] >> 16) ^ ((ulong*)ptiblo0)[1] ^ ((ulong*)ptiblo1)[1];
//}
// pt = &encodeTable
private unsafe delegate void SyndromeCalc(ushort* pt, ushort* wr, ushort lo);
private unsafe static void CalcPar(ushort* pt, ushort* wr, uint lo, uint hi)
{
// pt = &encodeTable
#if !sdfs
uint wrlo = wr[0] ^ lo;
uint wrhi = wr[maxNpar] ^ hi;
ushort* ptiblo0 = pt + (wrlo & 255) * maxNpar * 2;
private unsafe static void SyndromeCalcDummy(ushort* pt, ushort* wr, ushort lo)
{
}
private unsafe static void SyndromeCalc8(ushort* pt, ushort* wr, ushort lo)
{
ushort wrlo = (ushort)(wr[0] ^ lo);
ushort* ptiblo0 = pt + (wrlo & 255) * maxNpar * 2;
ushort* ptiblo1 = pt + (wrlo >> 8) * maxNpar * 2 + maxNpar;
ushort* ptibhi0 = pt + (wrhi & 255) * maxNpar * 2;
ushort* ptibhi1 = pt + (wrhi >> 8) * maxNpar * 2 + maxNpar;
wr[maxNpar] = 0;
if (maxNpar == 16)
{
((ulong*)wr)[0] = ((ulong*)(wr + 1))[0] ^ ((ulong*)ptiblo0)[0] ^ ((ulong*)ptiblo1)[0];
((ulong*)wr)[1] = ((ulong*)(wr + 1))[1] ^ ((ulong*)ptiblo0)[1] ^ ((ulong*)ptiblo1)[1];
((ulong*)wr)[2] = ((ulong*)(wr + 1))[2] ^ ((ulong*)ptiblo0)[2] ^ ((ulong*)ptiblo1)[2];
((ulong*)wr)[3] = ((ulong*)(wr + 1))[3] ^ ((ulong*)ptiblo0)[3] ^ ((ulong*)ptiblo1)[3];
((ulong*)wr)[4] = ((ulong*)(wr + 1))[4] ^ ((ulong*)ptibhi0)[0] ^ ((ulong*)ptibhi1)[0];
((ulong*)wr)[5] = ((ulong*)(wr + 1))[5] ^ ((ulong*)ptibhi0)[1] ^ ((ulong*)ptibhi1)[1];
((ulong*)wr)[6] = ((ulong*)(wr + 1))[6] ^ ((ulong*)ptibhi0)[2] ^ ((ulong*)ptibhi1)[2];
((ulong*)wr)[7] = (((ulong*)(wr))[7] >> 16) ^ ((ulong*)ptibhi0)[3] ^ ((ulong*)ptibhi1)[3];
}
else if (maxNpar == 8)
{
((ulong*)wr)[0] = ((ulong*)(wr + 1))[0] ^ ((ulong*)ptiblo0)[0] ^ ((ulong*)ptiblo1)[0];
((ulong*)wr)[1] = ((ulong*)(wr + 1))[1] ^ ((ulong*)ptiblo0)[1] ^ ((ulong*)ptiblo1)[1];
((ulong*)wr)[2] = ((ulong*)(wr + 1))[2] ^ ((ulong*)ptibhi0)[0] ^ ((ulong*)ptibhi1)[0];
((ulong*)wr)[3] = (((ulong*)(wr))[3] >> 16) ^ ((ulong*)ptibhi0)[1] ^ ((ulong*)ptibhi1)[1];
}
else
throw new InvalidOperationException();
#else
const int npar = 8;
((ulong*)wr)[0] = ((ulong*)(wr + 1))[0] ^ ((ulong*)ptiblo0)[0] ^ ((ulong*)ptiblo1)[0];
((ulong*)wr)[1] = (((ulong*)(wr))[1] >> 16) ^ ((ulong*)ptiblo0)[1] ^ ((ulong*)ptiblo1)[1];
}
uint s = wr[0] ^ lo;
ushort* ptib0 = pt + (s & 255) * 16;
ushort* ptib1 = pt + (s >> 8) * 16 + 8;
for (int i = 0; i < npar - 1; i++)
wr[i] = (ushort)(wr[i + 1] ^ ptib0[i] ^ ptib1[i]);
wr[npar - 1] = (ushort)(ptib0[npar - 1] ^ ptib1[npar - 1]);
//[System.Runtime.InteropServices.DllImport("CUETools.AVX.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
//private unsafe static extern void SyndromeCalc16AVX(ushort* table, ushort* parity, ushort* samples, int n);
wr += 8;
s = wr[0] ^ hi;
ptib0 = pt + (s & 255) * 16;
ptib1 = pt + (s >> 8) * 16 + 8;
for (int i = 0; i < npar - 1; i++)
wr[i] = (ushort)(wr[i + 1] ^ ptib0[i] ^ ptib1[i]);
wr[npar - 1] = (ushort)(ptib0[npar - 1] ^ ptib1[npar - 1]);
#endif
}
private unsafe static void SyndromeCalc16(ushort* pt, ushort* wr, ushort lo)
{
ushort wrlo = (ushort)(wr[0] ^ lo);
ushort* ptiblo0 = pt + (wrlo & 255) * maxNpar * 2;
ushort* ptiblo1 = pt + (wrlo >> 8) * maxNpar * 2 + maxNpar;
((ulong*)wr)[0] = ((ulong*)(wr + 1))[0] ^ ((ulong*)ptiblo0)[0] ^ ((ulong*)ptiblo1)[0];
((ulong*)wr)[1] = ((ulong*)(wr + 1))[1] ^ ((ulong*)ptiblo0)[1] ^ ((ulong*)ptiblo1)[1];
((ulong*)wr)[2] = ((ulong*)(wr + 1))[2] ^ ((ulong*)ptiblo0)[2] ^ ((ulong*)ptiblo1)[2];
((ulong*)wr)[3] = (((ulong*)(wr))[3] >> 16) ^ ((ulong*)ptiblo0)[3] ^ ((ulong*)ptiblo1)[3];
}
/// <summary>
/// <summary>
/// This function calculates three different CRCs and also
/// collects some additional information for the purposes of
/// offset detection.
@@ -481,6 +496,7 @@ namespace CUETools.AccurateRip
{
int currentStride = ((int)_sampleCount * 2) / stride;
bool doPar = currentStride >= 1 && currentStride <= stridecount && calcParity;
SyndromeCalc syndromeCalc = doPar ? maxNpar == 8 ? (SyndromeCalc)SyndromeCalc8 : (SyndromeCalc)SyndromeCalc16 : (SyndromeCalc)SyndromeCalcDummy;
int crcTrack = _currentTrack + (_samplesDoneTrack == 0 && _currentTrack > 0 ? -1 : 0);
uint crcar = _CRCAR[_currentTrack, 0];
@@ -491,6 +507,8 @@ namespace CUETools.AccurateRip
uint crcv2 = _CRCV2[_currentTrack, 0];
int peak = _Peak[_currentTrack];
//if (doPar) SyndromeCalc16AVX(pte, wr, (ushort*)pSampleBuff, count * 2);
for (int i = 0; i < count; i++)
{
if (offs >= 0)
@@ -518,12 +536,9 @@ namespace CUETools.AccurateRip
crcwn = (crcwn >> 8) ^ t[(byte)(crcwn ^ (lo >> 8))];
crcnl++;
}
syndromeCalc(pte, wr + i * maxNpar * 2, (ushort)lo);
uint hi = sample >> 16;
if (doPar) CalcPar(pte, wr + i * maxNpar * 2, lo, hi);
//if (doPar) CalcPar8(pte, wr + i * 16, lo);
//uint hi = sample >> 16;
crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ hi)];
crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ (hi >> 8))];
if (hi != 0)
@@ -532,7 +547,7 @@ namespace CUETools.AccurateRip
crcwn = (crcwn >> 8) ^ t[(byte)(crcwn ^ (hi >> 8))];
crcnl++;
}
//if (doPar) CalcPar8(pte, wr + i * 16 + 8, hi);
syndromeCalc(pte, wr + i * maxNpar * 2 + maxNpar, (ushort)hi);
int pk = ((int)(lo << 16)) >> 16;
peak = Math.Max(peak, (pk << 1) ^ (pk >> 31));

View File

@@ -56,7 +56,15 @@ namespace CUETools.AccurateRip
return stride;
}
}
}
public int LastStride
{
get
{
return laststride;
}
}
}
public class CDRepairEncode : CDRepair
{
@@ -85,16 +93,18 @@ namespace CUETools.AccurateRip
}
}
public string TrackCRCs
{
get
{
var sb = new StringBuilder();
for (int i = 1; i <= ar.TOC.AudioTracks; i++)
sb.AppendFormat(" {0:x8}", ar.CTDBCRC(i, 0, stride / 2, laststride / 2));
return sb.ToString().Substring(1);
}
}
public string GetTrackCRCs(int oi)
{
var sb = new StringBuilder();
for (int i = 1; i <= ar.TOC.AudioTracks; i++)
sb.AppendFormat(" {0:x8}", this.TrackCRC(i, oi));
return sb.ToString().Substring(1);
}
public uint TrackCRC(int iTrack, int oi)
{
return this.ar.CTDBCRC(iTrack, oi, this.stride / 2, this.laststride / 2);
}
public unsafe bool FindOffset(ushort[,] syn2, uint expectedCRC, out int actualOffset, out bool hasErrors)
{
@@ -107,56 +117,44 @@ namespace CUETools.AccurateRip
throw new Exception("ar.Position != ar.FinalSampleCount");
var rs = new RsDecode16(npar, this.galois);
int part2 = 0;
// find offset
fixed (ushort* chT = rs.chienTable, syn2part = &syn2[part2, 0])
fixed (ushort* syn2part = syn2)
{
int* _sigma = stackalloc int[npar];
int* _errpos = stackalloc int[npar];
int* syn = stackalloc int[npar];
bool foundOffset = false;
var arSyndrome = ar.GetSyndrome(npar);
int bestOffset = 0;
int bestOffsetErrors = npar / 2;
for (int allowed_errors = 0; allowed_errors < npar / 2 && !foundOffset; allowed_errors++)
// fast search
for (int offset = 1 - stride / 2; offset < stride / 2; offset++)
{
// We can only use offset if Abs(offset * 2) < stride,
// else we might need to add/remove more than one sample
// from syndrome calculations, and that would be too difficult
// and will probably require longer leadin/leadout.
for (int offset = 1 - stride / 2; offset < stride / 2; offset++)
var syn1 = ar.GetSyndrome(npar, 1, -offset);
int err = 0;
for (int i = 0; i < npar; i++)
{
int err = 0;
int part = (part2 + stride - offset * 2) % stride;
for (int i = 0; i < npar; i++)
{
int synI = arSyndrome[part, i];
// offset < 0
if (part < -offset * 2)
{
synI ^= galois.mulExp(ar.leadin[stride + part], (i * (stridecount - 1)) % galois.Max);
synI = ar.leadout[laststride - part - 1] ^ galois.mulExp(synI, i);
}
// offset > 0
if (part >= stride - offset * 2)
{
synI = galois.divExp(synI ^ ar.leadout[laststride + stride - part - 1], i);
synI ^= galois.mulExp(ar.leadin[part], (i * (stridecount - 1)) % galois.Max);
}
synI = galois.mulExp(synI ^ syn2part[i], i * npar);
syn[i] = synI;
err |= synI;
}
int err_count = err == 0 ? 0 : rs.calcSigmaMBM(_sigma, syn);
if (err_count == allowed_errors && (err_count == 0 || rs.chienSearch(_errpos, stridecount + npar, err_count, _sigma, chT)))
{
actualOffset = offset;
hasErrors = err_count != 0 || ar.CTDBCRC(-offset) != expectedCRC;
return true;
}
int synI = syn1[0, i] ^ syn2part[i];
syn[i] = synI;
err |= synI;
}
if (err == 0)
{
actualOffset = offset;
hasErrors = ar.CTDBCRC(-offset) != expectedCRC;
return true;
}
int err_count = rs.calcSigmaMBM(_sigma, syn);
if (err_count > 0 && err_count < bestOffsetErrors && rs.chienSearch(_errpos, stridecount, err_count, _sigma))
{
bestOffset = offset;
bestOffsetErrors = err_count;
}
}
if (bestOffsetErrors < npar / 2)
{
actualOffset = bestOffset;
hasErrors = true;
return true;
}
}
actualOffset = 0;
@@ -164,99 +162,92 @@ namespace CUETools.AccurateRip
return false;
}
public unsafe CDRepairFix VerifyParity(ushort[,] syn2, int actualOffset)
public unsafe CDRepairFix VerifyParity(ushort[,] syn2, uint crc, int actualOffset)
{
int npar2 = syn2.GetLength(1);
int npar = Math.Min(AccurateRipVerify.maxNpar, npar2);
CDRepairFix fix = new CDRepairFix(this, npar);
fix.actualOffset = actualOffset;
fix.correctableErrors = 0;
fix.hasErrors = false;
fix.canRecover = true;
fix.sigma = new int[stride, npar / 2 + 2];
fix.omega = new int[stride, npar / 2 + 1];
fix.errpos = new int[stride, npar / 2];
//fix.erroff = new int[stride, npar / 2];
fix.errors = new int[stride];
var syn1 = ar.GetSyndrome(npar);
var erroff = new int[stride * npar / 2];
var forney = new ushort[stride * npar / 2];
var syn1 = ar.GetSyndrome(npar, -1, -actualOffset);
var rs = new RsDecode16(npar, this.galois);
CDRepairFix fix = new CDRepairFix(this, npar);
//fixed (byte* par = &parity2[pos])
fixed (ushort* exp = galois.ExpTbl, log = galois.LogTbl, chT = rs.chienTable, psyn2 = syn2, psyn1 = syn1)
fixed (int* sf = fix.sigma, of = fix.omega, ef = fix.errpos)
fix.actualOffset = actualOffset;
fix.correctableErrors = 0;
fix.hasErrors = false;
fix.canRecover = true;
fixed (ushort *psyn2 = syn2, psyn1 = syn1)
{
int sfLen = fix.sigma.GetLength(1);
int ofLen = fix.omega.GetLength(1);
int efLen = fix.errpos.GetLength(1);
int sfLen = npar / 2 + 2;
int ofLen = npar / 2 + 1;
int efLen = npar / 2;
int* _sigma = stackalloc int[npar / 2 + 2];
int* _omega = stackalloc int[npar / 2 + 1];
int* _errpos = stackalloc int[npar / 2];
int* syn = stackalloc int[npar];
int offset = fix.actualOffset;
for (int part = 0; part < stride; part++)
for (int part2 = 0; part2 < stride; part2++)
{
int part2 = (part + offset * 2 + stride) % stride;
ushort* syn1part = psyn1 + part * npar;
ushort* syn1part = psyn1 + part2 * npar;
ushort* syn2part = psyn2 + part2 * npar;
int err = 0;
for (int i = 0; i < npar; i++)
{
int synI = syn1part[i];
// offset < 0
if (part < -offset * 2)
{
synI ^= galois.mulExp(ar.leadin[stride + part], (i * (stridecount - 1)) % galois.Max);
synI = ar.leadout[laststride - part - 1] ^ galois.mulExp(synI, i);
}
// offset > 0
if (part >= stride - offset * 2)
{
synI = galois.divExp(synI ^ ar.leadout[laststride + stride - part - 1], i);
synI ^= galois.mulExp(ar.leadin[part], (i * (stridecount - 1)) % galois.Max);
}
synI = galois.mulExp(synI ^ syn2part[i], i * npar);
var synI = syn1part[i] ^ syn2part[i];
syn[i] = synI;
err |= synI;
}
//for (int j = 0; j < npar; j++)
// if (wr[j] != 0)
// {
// ushort* myexp = exp + log[wr[j]];
// syn[0] ^= wr[j];
// for (int i = 1; i < npar; i++)
// syn[i] ^= myexp[(npar - j - 1) * i];
// }
if (err != 0)
{
int errcount = rs.calcSigmaMBM(_sigma, syn);
fix.hasErrors = true;
if (errcount <= 0 || errcount > efLen || !rs.chienSearch(_errpos, stridecount, errcount, _sigma))
{
fix.canRecover = false;
return fix;
}
//for (int i = 0; i < npar; i++)
// err |= syn[i];
galois.mulPoly(_omega, _sigma, syn, ofLen, sfLen, npar);
if (err != 0)
{
int* s = sf + part * sfLen;
int* o = of + part * ofLen;
int* e = ef + part * efLen;
//fixed (int* s = &fix.sigma[part, 0], o = &fix.omega[part, 0], e = &fix.errpos[part, 0])
{
fix.errors[part] = rs.calcSigmaMBM(s, syn);
fix.hasErrors = true;
fix.correctableErrors += fix.errors[part];
if (fix.errors[part] <= 0 || !rs.chienSearch(e, stridecount + npar, fix.errors[part], s, chT))
fix.canRecover = false;
else
galois.mulPoly(o, s, syn, ofLen, sfLen, npar);
}
}
else
fix.errors[part] = 0;
for (int i = 0; i < errcount; i++)
{
int pos = galois.toPos(stridecount, _errpos[i]) * stride + part2;
int erroffi = stride + pos - actualOffset * 2;
ushort diff = (ushort)this.galois.doForney(errcount, _errpos[i], _sigma, _omega);
if (erroffi < 0 || erroffi >= finalSampleCount * 2)
{
fix.canRecover = false;
return fix;
}
crc ^= Crc32.Combine(Crc32.ComputeChecksum(Crc32.ComputeChecksum(0, (byte)diff), (byte)(diff >> 8)), 0, (stridecount * stride - pos - 1) * 2);
erroff[fix.correctableErrors] = erroffi;
forney[fix.correctableErrors] = diff;
fix.correctableErrors++;
}
}
}
crc ^= ar.CTDBCRC(-actualOffset);
if (crc != 0)
{
fix.canRecover = false;
return fix;
}
}
return fix;
fix.erroffsorted = new int[fix.correctableErrors];
fix.forneysorted = new ushort[fix.correctableErrors];
for (int i = 0; i < fix.correctableErrors; i++)
{
fix.erroffsorted[i] = erroff[i];
fix.forneysorted[i] = forney[i];
}
Array.Sort<int, ushort>(fix.erroffsorted, fix.forneysorted, 0, fix.correctableErrors);
return fix;
}
public string OffsetSafeCRC
@@ -273,15 +264,10 @@ namespace CUETools.AccurateRip
internal bool hasErrors = false, canRecover = true;
internal int actualOffset = 0;
internal int correctableErrors = 0;
internal int[,] sigma;
internal int[,] omega;
internal int[,] errpos;
internal int[] erroffsorted;
internal int[] erroffsorted;
internal ushort[] forneysorted;
internal int erroffcount;
internal int[] errors;
private BitArray affectedSectorArray;
private int nexterroff;
private int nexterroff = 0;
private int npar;
uint crc = 0;
@@ -289,29 +275,13 @@ namespace CUETools.AccurateRip
: base(decode)
{
this.npar = npar;
}
}
public string AffectedSectors
{
get
{
StringBuilder sb = new StringBuilder();
SortErrors();
for (int i = 0; i < erroffcount; i++)
{
int j;
for (j = i + 1; j < erroffcount; j++)
if (erroffsorted[j] - erroffsorted[j - 1] > 2 * 588 * 5)
break;
uint sec1 = (uint)erroffsorted[i] / 2 / 588;
uint sec2 = (uint)erroffsorted[j - 1] / 2 / 588;
if (sb.Length != 0) sb.Append(",");
sb.Append(CDImageLayout.TimeToString(sec1));
if (sec1 != sec2) sb.Append("-");
if (sec1 != sec2) sb.Append(CDImageLayout.TimeToString(sec2));
i = j - 1;
}
return sb.ToString();
return this.GetAffectedSectors(0, finalSampleCount);
}
}
@@ -322,43 +292,46 @@ namespace CUETools.AccurateRip
if (affectedSectorArray == null)
{
affectedSectorArray = new BitArray(finalSampleCount / 588 + 1);
SortErrors();
for (int i = 0; i < erroffcount; i++)
for (int i = 0; i < correctableErrors; i++)
affectedSectorArray[erroffsorted[i] / 2 / 588] = true;
}
return affectedSectorArray;
}
}
private int GetErrOff(int part, int i)
{
return (2 + galois.toPos(stridecount + npar, errpos[part, i]) - (stride + part + ActualOffset * 2) / stride) * stride + part;
}
public int GetAffectedSectorsCount(int min, int max)
{
min = Math.Max(2 * min, stride - 2 * ActualOffset);
max = Math.Min(2 * max, 2 * finalSampleCount - laststride - 2 * ActualOffset);
int count = 0;
for (int i = 0; i < correctableErrors; i++)
if (erroffsorted[i] >= min && erroffsorted[i] < max)
count++;
return count;
}
private unsafe void SortErrors()
{
if (erroffsorted != null)
return;
erroffcount = 0;
erroffsorted = new int[errpos.GetLength(0) * errpos.GetLength(1)];
forneysorted = new ushort[errpos.GetLength(0) * errpos.GetLength(1)];
for (int part = 0; part < stride; part++)
{
fixed (int* s = &sigma[part, 0], o = &omega[part, 0])
for (int i = 0; i < errors[part]; i++)
{
erroffsorted[erroffcount] = GetErrOff(part, i);
if (erroffsorted[erroffcount] >= 0 && erroffsorted[erroffcount] < finalSampleCount * 2)
{
forneysorted[erroffcount] = (ushort)this.galois.doForney(errors[part], errpos[part, i], s, o);
erroffcount++;
}
}
}
Array.Sort<int, ushort>(erroffsorted, forneysorted, 0, erroffcount);
// assert erroffcount == CorrectableErrors
nexterroff = 0;
}
public string GetAffectedSectors(int min, int max)
{
min = Math.Max(2 * min, stride - 2 * ActualOffset);
max = Math.Min(2 * max, 2 * finalSampleCount - laststride - 2 * ActualOffset);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < correctableErrors; i++)
if (erroffsorted[i] >= min && erroffsorted[i] < max)
{
int j;
for (j = i + 1; j < correctableErrors; j++)
if (erroffsorted[j] - erroffsorted[j - 1] > 2 * 588 * 5)
break;
uint sec1 = (uint)(erroffsorted[i] - min) / 2 / 588;
uint sec2 = (uint)(erroffsorted[j - 1] - min) / 2 / 588;
if (sb.Length != 0) sb.Append(",");
sb.Append(CDImageLayout.TimeToString(sec1));
if (sec1 != sec2) sb.Append("-");
if (sec1 != sec2) sb.Append(CDImageLayout.TimeToString(sec2));
i = j - 1;
}
return sb.ToString();
}
public unsafe void Write(AudioBuffer sampleBuffer)
{
@@ -370,15 +343,13 @@ namespace CUETools.AccurateRip
int firstPos = Math.Max(0, stride - sampleCount * 2 - ActualOffset * 2);
int lastPos = Math.Min(sampleBuffer.ByteLength >> 1, (finalSampleCount - sampleCount) * 2 - laststride - ActualOffset * 2);
SortErrors();
fixed (byte* bytes = sampleBuffer.Bytes)
fixed (uint* t = Crc32.table)
{
ushort* data = (ushort*)bytes;
for (int pos = firstPos; pos < lastPos; pos++)
{
if (sampleCount * 2 + pos == erroffsorted[nexterroff] && nexterroff < erroffsorted.Length)
if (nexterroff < erroffsorted.Length && sampleCount * 2 + pos == erroffsorted[nexterroff])
data[pos] ^= forneysorted[nexterroff++];
ushort dd = data[pos];