From b84f1de1181c4328be06de509e54bd9b0490631a Mon Sep 17 00:00:00 2001 From: chudov Date: Thu, 27 Oct 2011 20:50:11 +0000 Subject: [PATCH] Preparing for next version of CTDB --- CUETools.AccurateRip/AccurateRip.cs | 7 - CUETools.AccurateRip/CDRepair.cs | 265 ++---------------- CUETools.CTDB/CUETools.CTDB.csproj | 4 + CUETools.CTDB/CUEToolsDB.cs | 55 ++-- CUETools.CTDB/DBEntry.cs | 20 +- CUETools.Parity/Galois.cs | Bin 22478 -> 24158 bytes CUETools.Parity/Parity2Syndrome.cs | 18 +- CUETools.TestHelpers/TestImageGenerator.cs | 4 +- .../CUETools.TestParity/CDRepairDecodeTest.cs | 136 +++++---- 9 files changed, 154 insertions(+), 355 deletions(-) diff --git a/CUETools.AccurateRip/AccurateRip.cs b/CUETools.AccurateRip/AccurateRip.cs index 8cf808f..59faac1 100644 --- a/CUETools.AccurateRip/AccurateRip.cs +++ b/CUETools.AccurateRip/AccurateRip.cs @@ -330,13 +330,6 @@ namespace CUETools.AccurateRip return ParityToSyndrome.Parity2Syndrome(stride, npar, maxNpar, parity); } - public unsafe byte[] GetSyndromeBytes(int npar = maxNpar) - { - if (!calcParity) - throw new InvalidOperationException(); - return ParityToSyndrome.Parity2SyndromeBytes(stride, npar, maxNpar, parity); - } - private byte[] parity; internal ushort[, ,] encodeTable; private int maxOffset; diff --git a/CUETools.AccurateRip/CDRepair.cs b/CUETools.AccurateRip/CDRepair.cs index c791edf..968e515 100644 --- a/CUETools.AccurateRip/CDRepair.cs +++ b/CUETools.AccurateRip/CDRepair.cs @@ -14,47 +14,27 @@ namespace CUETools.AccurateRip protected int sampleCount; protected int finalSampleCount; internal Galois galois; - protected RsDecode rs; - //protected uint crc; - protected int[] encodeGx; internal int stride; internal int laststride; internal int stridecount; - internal int npar; - public CDRepair(int finalSampleCount, int stride, int npar) + public CDRepair(int finalSampleCount, int stride) { - this.npar = npar; this.stride = stride; this.finalSampleCount = finalSampleCount; sampleCount = 0; galois = Galois16.instance; - rs = new RsDecode16(npar, galois); - //crc32 = new Crc32(); - //crc = 0xffffffff; - encodeGx = galois.makeEncodeGxLog(npar); laststride = stride + (finalSampleCount * 2) % stride; stridecount = (finalSampleCount * 2) / stride - 2; // minus one for leadin and one for leadout - if ((finalSampleCount * 2 + stride - 1) / stride + npar > galois.Max) + if ((finalSampleCount * 2 + stride - 1) / stride + AccurateRipVerify.maxNpar > galois.Max) throw new Exception("invalid stride"); } public CDRepair(CDRepair src) - : this(src.finalSampleCount, src.stride, src.npar) + : this(src.finalSampleCount, src.stride) { } - //public unsafe void Write(AudioBuffer sampleBuffer) - //{ - // throw new Exception("unsupported"); - //} - - //public unsafe void Close() - //{ - // if (sampleCount != finalSampleCount) - // throw new Exception("sampleCount != finalSampleCount"); - //} - public long FinalSampleCount { get @@ -69,14 +49,6 @@ namespace CUETools.AccurateRip } } - public int NPAR - { - get - { - return npar; - } - } - public int Stride { get @@ -90,183 +62,13 @@ namespace CUETools.AccurateRip { protected AccurateRipVerify ar; - public CDRepairEncode(AccurateRipVerify ar, int stride, int npar) - : base ((int)ar.FinalSampleCount, stride, npar) + public CDRepairEncode(AccurateRipVerify ar, int stride) + : base ((int)ar.FinalSampleCount, stride) { this.ar = ar; ar.InitCDRepair(stride, laststride, stridecount, true); } - //private unsafe void ProcessStride(int currentStride, int currentPart, int count, ushort* data) - //{ - // fixed (uint* crct = Crc32.table) - // fixed (byte* bpar = parity) - // fixed (ushort* exp = galois.ExpTbl, log = galois.LogTbl, synptr = syndrome) - // fixed (int* gx = encodeGx) - // for (int pos = 0; pos < count; pos++) - // { - // ushort* par = (ushort*)bpar; - // int part = currentPart + pos; - // ushort* wr = ((ushort*)par) + part * npar; - // ushort dd = data[pos]; - - // //crc = (crc >> 8) ^ crct[(byte)(crc ^ dd)]; - // //crc = (crc >> 8) ^ crct[(byte)(crc ^ (dd >> 8))]; - - // if (verify) - // { - // ushort* syn = synptr + part * npar; - // syn[0] ^= dd; // wk += data - // for (int i = 1; i < npar; i++) - // syn[i] = (ushort)(dd ^ galois.mulExp(syn[i], i)); // wk = data + wk * α^i - // } - - // int ib = wr[0] ^ dd; - // if (ib != 0) - // { - // ushort* myexp = exp + log[ib]; - // for (int i = 0; i < npar - 1; i++) - // wr[i] = (ushort)(wr[i + 1] ^ myexp[gx[i]]); - // wr[npar - 1] = myexp[gx[npar - 1]]; - // } - // else - // { - // for (int i = 0; i < npar - 1; i++) - // wr[i] = wr[i + 1]; - // wr[npar - 1] = 0; - // } - // } - //} - - //private unsafe void ProcessStride16(int currentStride, int currentPart, int count, ushort* data) - //{ - // fixed (uint* crct = Crc32.table) - // fixed (byte* bpar = parity) - // fixed (ushort* exp = galois.ExpTbl, log = galois.LogTbl, synptr = syndrome) - // for (int pos = 0; pos < count; pos++) - // { - // ushort* par = (ushort*)bpar; - // int part = currentPart + pos; - // ushort* wr = par + part * 16; - // ushort dd = data[pos]; - - // //crc = (crc >> 8) ^ crct[(byte)(crc ^ dd)]; - // //crc = (crc >> 8) ^ crct[(byte)(crc ^ (dd >> 8))]; - - // int ib = wr[0] ^ dd; - // if (ib != 0) - // { - // ushort* myexp = exp + log[ib]; - // wr[0] = (ushort)(wr[1] ^ myexp[0x000059f1]); - // wr[1] = (ushort)(wr[2] ^ myexp[0x0000608f]); - // wr[2] = (ushort)(wr[3] ^ myexp[0x0000918b]); - // wr[3] = (ushort)(wr[4] ^ myexp[0x00004487]); - // wr[4] = (ushort)(wr[5] ^ myexp[0x0000a151]); - // wr[5] = (ushort)(wr[6] ^ myexp[0x0000c074]); - // wr[6] = (ushort)(wr[7] ^ myexp[0x00004178]); - // wr[7] = (ushort)(wr[8] ^ myexp[0x00004730]); - // wr[8] = (ushort)(wr[9] ^ myexp[0x00004187]); - // wr[9] = (ushort)(wr[10] ^ myexp[0x0000c092]); - // wr[10] = (ushort)(wr[11] ^ myexp[0x0000a17e]); - // wr[11] = (ushort)(wr[12] ^ myexp[0x000044c3]); - // wr[12] = (ushort)(wr[13] ^ myexp[0x000091d6]); - // wr[13] = (ushort)(wr[14] ^ myexp[0x000060e9]); - // wr[14] = (ushort)(wr[15] ^ myexp[0x00005a5a]); - // wr[15] = myexp[0x00000078]; - // } - // else - // { - // wr[0] = wr[1]; - // wr[1] = wr[2]; - // wr[2] = wr[3]; - // wr[3] = wr[4]; - // wr[4] = wr[5]; - // wr[5] = wr[6]; - // wr[6] = wr[7]; - // wr[7] = wr[8]; - // wr[8] = wr[9]; - // wr[9] = wr[10]; - // wr[10] = wr[11]; - // wr[11] = wr[12]; - // wr[12] = wr[13]; - // wr[13] = wr[14]; - // wr[14] = wr[15]; - // wr[15] = 0; - // } - - // // syn[i] += data[pos] * α^(n*i) - // if (verify && dd != 0) - // { - // int n = stridecount - currentStride; - // ushort* syn = synptr + part * 16; - // syn[0] ^= dd; - // int idx = log[dd]; - // idx += n; syn[1] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[2] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[3] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[4] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[5] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[6] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[7] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[8] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[9] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[10] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[11] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[12] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[13] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[14] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // idx += n; syn[15] ^= exp[(idx & 0xffff) + (idx >> 16)]; - // } - // } - //} - - //new public unsafe void Write(AudioBuffer sampleBuffer) - //{ - // if (!verify && !encode) - // return; - - // sampleBuffer.Prepare(this); - - // if ((sampleBuffer.ByteLength & 1) != 0 || sampleCount + sampleBuffer.Length > finalSampleCount) - // throw new Exception("sampleCount > finalSampleCount"); - - // fixed (byte* bytes = sampleBuffer.Bytes) - // { - // int offs = 0; - // while (offs < sampleBuffer.Length) - // { - // int currentPart = (sampleCount * 2) % stride; - // int currentStride = (sampleCount * 2) / stride; - // // Process no more than there is in the buffer, and no more than up to a stride boundary. - // int copyCount = Math.Min((sampleBuffer.Length - offs) * 2, stride - currentPart); - // ushort* data = ((ushort*)bytes) + offs * 2; - - // if (currentStride < 2) - // for (int pos = 0; pos < copyCount; pos++) - // leadin[sampleCount * 2 + pos] = data[pos]; - - // if (currentStride >= stridecount) - // for (int pos = 0; pos < copyCount; pos++) - // { - // int remaining = (finalSampleCount - sampleCount) * 2 - pos - 1; - // if (remaining < stride + laststride) - // leadout[remaining] = data[pos]; - // } - - // if (currentStride >= 1 && currentStride <= stridecount) - // { - // if (npar == 16) - // ProcessStride16(currentStride, currentPart, copyCount, data); - // else if (npar != 8) - // ProcessStride(currentStride, currentPart, copyCount, data); - // } - - // sampleCount += copyCount >> 1; - // offs += copyCount >> 1; - // } - // } - //} - public AccurateRipVerify AR { get @@ -294,21 +96,17 @@ namespace CUETools.AccurateRip } } - public unsafe bool FindOffset(int npar2, byte[] parity2, int pos, uint expectedCRC, out int actualOffset, out bool hasErrors) - { - var syn2 = ParityToSyndrome.Parity2Syndrome(1, npar2, npar2, parity2, pos); - return FindOffset(syn2, expectedCRC, out actualOffset, out hasErrors); - } - public unsafe bool FindOffset(ushort[,] syn2, uint expectedCRC, out int actualOffset, out bool hasErrors) { int npar2 = syn2.GetLength(1); + int npar = Math.Min(AccurateRipVerify.maxNpar, npar2); if (npar2 != npar) throw new Exception("npar mismatch"); if (ar.Position != ar.FinalSampleCount) 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]) @@ -366,19 +164,12 @@ namespace CUETools.AccurateRip return false; } - public unsafe CDRepairFix VerifyParity(int npar2, byte[] parity2, int pos, int len, int actualOffset) - { - if (len != stride * npar2 * 2) - throw new Exception("wrong size"); - var syn2 = ParityToSyndrome.Parity2Syndrome(stride, npar2, npar2, parity2, pos); - return VerifyParity(syn2, actualOffset); - } - public unsafe CDRepairFix VerifyParity(ushort[,] syn2, int actualOffset) { int npar2 = syn2.GetLength(1); + int npar = Math.Min(AccurateRipVerify.maxNpar, npar2); - CDRepairFix fix = new CDRepairFix(this); + CDRepairFix fix = new CDRepairFix(this, npar); fix.actualOffset = actualOffset; fix.correctableErrors = 0; fix.hasErrors = false; @@ -391,12 +182,16 @@ namespace CUETools.AccurateRip fix.errors = new int[stride]; var syn1 = ar.GetSyndrome(npar); + var rs = new RsDecode16(npar, this.galois); //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) { - int* syn = stackalloc int[npar]; + int sfLen = fix.sigma.GetLength(1); + int ofLen = fix.omega.GetLength(1); + int efLen = fix.errpos.GetLength(1); + int* syn = stackalloc int[npar]; int offset = fix.actualOffset; for (int part = 0; part < stride; part++) @@ -442,9 +237,9 @@ namespace CUETools.AccurateRip if (err != 0) { - int* s = sf + part * fix.sigma.GetLength(1); - int* o = of + part * fix.omega.GetLength(1); - int* e = ef + part * fix.errpos.GetLength(1); + 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); @@ -453,7 +248,7 @@ namespace CUETools.AccurateRip if (fix.errors[part] <= 0 || !rs.chienSearch(e, stridecount + npar, fix.errors[part], s, chT)) fix.canRecover = false; else - galois.mulPoly(o, s, syn, npar / 2 + 1, npar, npar); + galois.mulPoly(o, s, syn, ofLen, sfLen, npar); } } else @@ -471,22 +266,6 @@ namespace CUETools.AccurateRip return ar.OffsetSafeCRC.Base64; } } - - public ushort[,] Syndrome - { - get - { - return this.ar.GetSyndrome(this.npar); - } - } - - public byte[] Parity - { - get - { - return this.ar.GetParity(this.npar); - } - } } public class CDRepairFix : CDRepair, IAudioDest @@ -503,11 +282,13 @@ namespace CUETools.AccurateRip internal int[] errors; private BitArray affectedSectorArray; private int nexterroff; + private int npar; uint crc = 0; - internal CDRepairFix(CDRepairEncode decode) + internal CDRepairFix(CDRepairEncode decode, int npar) : base(decode) { + this.npar = npar; } public string AffectedSectors @@ -561,7 +342,7 @@ namespace CUETools.AccurateRip 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++) + 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++) @@ -569,7 +350,7 @@ namespace CUETools.AccurateRip erroffsorted[erroffcount] = GetErrOff(part, i); if (erroffsorted[erroffcount] >= 0 && erroffsorted[erroffcount] < finalSampleCount * 2) { - forneysorted[erroffcount] = (ushort)rs.doForney(errors[part], errpos[part, i], s, o); + forneysorted[erroffcount] = (ushort)this.galois.doForney(errors[part], errpos[part, i], s, o); erroffcount++; } } diff --git a/CUETools.CTDB/CUETools.CTDB.csproj b/CUETools.CTDB/CUETools.CTDB.csproj index c8d0f13..907075b 100644 --- a/CUETools.CTDB/CUETools.CTDB.csproj +++ b/CUETools.CTDB/CUETools.CTDB.csproj @@ -89,6 +89,10 @@ {6458A13A-30EF-45A9-9D58-E5031B17BEE2} CUETools.Codecs + + {ECEB839C-171B-4535-958F-9899310A0342} + CUETools.Parity + diff --git a/CUETools.CTDB/CUEToolsDB.cs b/CUETools.CTDB/CUEToolsDB.cs index 5a28ff0..96bb257 100644 --- a/CUETools.CTDB/CUEToolsDB.cs +++ b/CUETools.CTDB/CUEToolsDB.cs @@ -10,6 +10,7 @@ using System.Text; using System.Xml.Serialization; using CUETools.AccurateRip; using CUETools.CDImage; +using CUETools.Parity; using Krystalware.UploadHelper; namespace CUETools.CTDB @@ -101,13 +102,16 @@ namespace CUETools.CTDB var parity = Convert.FromBase64String(ctdbRespEntry.parity); var entry_toc = CDImageLayout.FromString(ctdbRespEntry.toc); this.total += ctdbRespEntry.confidence; + + if (parity.Length != ctdbRespEntry.npar * 2) + throw new Exception("invalid parity length"); + //if (verify.Stride != ctdbRespEntry.stride * 2) + // throw new Exception("invalid stride length"); + var syndrome = ParityToSyndrome.Parity2Syndrome(1, ctdbRespEntry.npar, ctdbRespEntry.npar, parity); var entry = new DBEntry( - parity, - 0, - parity.Length, + syndrome, ctdbRespEntry.confidence, - ctdbRespEntry.npar, - ctdbRespEntry.stride, + ctdbRespEntry.stride * 2, uint.Parse(ctdbRespEntry.crc32, NumberStyles.HexNumber), ctdbRespEntry.id, entry_toc, @@ -165,8 +169,8 @@ namespace CUETools.CTDB if (entry.httpStatus == HttpStatusCode.OK) { - if (resp.ContentLength < entry.npar * entry.stride * 4 || - resp.ContentLength > entry.npar * entry.stride * 8) + if (resp.ContentLength < entry.Npar * entry.stride * 2 || + resp.ContentLength > entry.Npar * entry.stride * 4) { entry.httpStatus = HttpStatusCode.PartialContent; } @@ -230,13 +234,15 @@ namespace CUETools.CTDB return this.DBStatus; DBEntry confirm = this.MatchingEntry; if (confirm != null) confidence = 1; - DoSubmit(confidence, quality, artist, title, barcode, false, confirm); + int npar = AccurateRipVerify.maxNpar; + var parity = verify.AR.GetParity(npar); + DoSubmit(confidence, quality, artist, title, barcode, false, confirm, parity, npar); if (subResult == "parity needed") - DoSubmit(confidence, quality, artist, title, barcode, true, confirm); + DoSubmit(confidence, quality, artist, title, barcode, true, confirm, parity, npar); return subResult; } - protected string DoSubmit(int confidence, int quality, string artist, string title, string barcode, bool upload, DBEntry confirm) + protected string DoSubmit(int confidence, int quality, string artist, string title, string barcode, bool upload, DBEntry confirm, byte[] parity, int npar) { UploadFile[] files; if (upload) @@ -253,9 +259,9 @@ namespace CUETools.CTDB using (DBHDR DISC = CTDB.HDR("DISC")) { using (DBHDR CONF = DISC.HDR("CONF")) CONF.Write(confidence); - using (DBHDR NPAR = DISC.HDR("NPAR")) NPAR.Write(verify.NPAR); + using (DBHDR NPAR = DISC.HDR("NPAR")) NPAR.Write(npar); using (DBHDR CRC_ = DISC.HDR("CRC ")) CRC_.Write(verify.CRC); - using (DBHDR PAR_ = DISC.HDR("PAR ")) PAR_.Write(verify.Parity); + using (DBHDR PAR_ = DISC.HDR("PAR ")) PAR_.Write(parity); } } newcontents.Position = 0; @@ -278,7 +284,7 @@ namespace CUETools.CTDB form.Add("toc", toc.ToString()); form.Add("crc32", ((int)verify.CRC).ToString()); form.Add("trackcrcs", verify.TrackCRCs); - form.Add("parity", Convert.ToBase64String(verify.Parity, 0, 16)); + form.Add("parity", Convert.ToBase64String(parity, 0, npar * 2)); form.Add("confidence", confidence.ToString()); form.Add("userid", GetUUID()); form.Add("quality", quality.ToString()); @@ -327,11 +333,9 @@ namespace CUETools.CTDB private bool Parse(byte[] contents, DBEntry entry) { - if (contents.Length == entry.npar * entry.stride * 4) + if (contents.Length == entry.Npar * entry.stride * 2) { - entry.parity = contents; - entry.pos = 0; - entry.len = contents.Length; + entry.syndrome = ParityToSyndrome.Parity2Syndrome(entry.stride, entry.Npar, entry.Npar, contents); return true; } @@ -377,9 +381,9 @@ namespace CUETools.CTDB } if (parPos != 0) { - entry.parity = contents; - entry.pos = parPos; - entry.len = parLen; + if (parLen != entry.Npar * entry.stride * 2) + return false; + entry.syndrome = ParityToSyndrome.Parity2Syndrome(entry.stride, entry.Npar, entry.Npar, contents, parPos); return true; } } @@ -392,13 +396,13 @@ namespace CUETools.CTDB return; foreach (DBEntry entry in entries) { - if (entry.toc.Pregap != toc.Pregap || entry.toc.AudioLength != toc.AudioLength || entry.stride != verify.Stride / 2) + if (entry.toc.Pregap != toc.Pregap || entry.toc.AudioLength != toc.AudioLength || entry.stride != verify.Stride) { entry.hasErrors = true; entry.canRecover = false; continue; } - if (!verify.FindOffset(entry.npar, entry.parity, entry.pos, entry.crc, out entry.offset, out entry.hasErrors)) + if (!verify.FindOffset(entry.syndrome, entry.crc, out entry.offset, out entry.hasErrors)) entry.canRecover = false; else if (entry.hasErrors) { @@ -411,7 +415,7 @@ namespace CUETools.CTDB entry.canRecover = false; else { - entry.repair = verify.VerifyParity(entry.npar, entry.parity, entry.pos, entry.len, entry.offset); + entry.repair = verify.VerifyParity(entry.syndrome, entry.offset); entry.canRecover = entry.repair.CanRecover; } } @@ -448,10 +452,7 @@ namespace CUETools.CTDB public void Init(AccurateRipVerify ar) { - int npar = 8; - foreach (DBEntry entry in entries) - npar = Math.Max(npar, entry.npar); - verify = new CDRepairEncode(ar, 10 * 588 * 2, npar); + verify = new CDRepairEncode(ar, 10 * 588 * 2); } public CDImageLayout TOC diff --git a/CUETools.CTDB/DBEntry.cs b/CUETools.CTDB/DBEntry.cs index 86bdc7e..6c135cb 100644 --- a/CUETools.CTDB/DBEntry.cs +++ b/CUETools.CTDB/DBEntry.cs @@ -6,11 +6,8 @@ namespace CUETools.CTDB { public class DBEntry { - public byte[] parity; - public int pos; - public int len; + public ushort[,] syndrome; public int conf; - public int npar; public int stride; public int offset; public uint crc; @@ -22,20 +19,25 @@ namespace CUETools.CTDB public CDImageLayout toc; public string hasParity; - public DBEntry(byte[] parity, int pos, int len, int conf, int npar, int stride, uint crc, string id, CDImageLayout toc, string hasParity) + public DBEntry(ushort[,] syndrome, int conf, int stride, uint crc, string id, CDImageLayout toc, string hasParity) { - this.parity = parity; + this.syndrome = syndrome; this.id = id; - this.pos = pos; - this.len = len; this.conf = conf; this.crc = crc; - this.npar = npar; this.stride = stride; this.toc = toc; this.hasParity = hasParity; } + public int Npar + { + get + { + return syndrome.GetLength(1); + } + } + public string Status { get diff --git a/CUETools.Parity/Galois.cs b/CUETools.Parity/Galois.cs index 2ce39819cb60d550b43c5c0394512275ddba7cf0..6bea292ddd38ee4690d1a66784ab017db96d86bd 100644 GIT binary patch delta 1249 zcmX@Np7Guu#tr*ICQlGx;a6Zlfs-pWWa~2-@)$}O6c|z%@)_J1@)?R4@)%MXDj75w zU@}<@nGD4Yr3^X@3UILkhGHbX7J~vqF+(OpIzui)BAR$ULoP!qLpnnugC+wn0~e|b z7!=qTszJh&4P_;BVHQ>~NDswC@@qp|P+$OQuVRQ}$bxx_vlhexVUUAOAsP=et22Ns z1qGH$z$9>hX)qjy2Vhb>e|$^Xx_GuAaBPEg!UHk|9*~H%63t+UEg-dx@C2j+1H|D* zID(U_9u#5t0~6T=py<+OPyo9Gl*U2+BPCEFAp`Lp*kv*dhnZ~{vKX`(3>oYQ2Q9lk zgBC29ogopiq^rw-sVg~Kfx(p_jv*78{x&j0*r2F_rC9}V`bIEZjfc*0#m~YQlk%ZeQps$DnkiFDYy_p&bg4349TCMAV%cr6oyQO kGH~iH1E*+EFlsV@QY$E*q7+vQ3Jj1W2^HPEKZKtd0D9itfB*mh delta 18 acmcb&hw diff --git a/CUETools.Parity/Parity2Syndrome.cs b/CUETools.Parity/Parity2Syndrome.cs index 7e6fea8..9733757 100644 --- a/CUETools.Parity/Parity2Syndrome.cs +++ b/CUETools.Parity/Parity2Syndrome.cs @@ -39,6 +39,16 @@ namespace CUETools.Parity erasure_diff = Galois16.instance.gfdiff(erasure_loc_pol); } + public static unsafe string ToBase64String(ushort[,] inArray, int offset, int length) + { + var outBuf = new byte[inArray.GetLength(1) * length * 2]; + fixed (ushort* inPtr = &inArray[offset, 0]) + fixed (byte* outPtr = outBuf) + for (int i = 0; i < inArray.GetLength(1) * length; i++) + ((ushort*)outPtr)[i] = inPtr[i]; + return Convert.ToBase64String(outBuf); + } + public static unsafe byte[] Syndrome2Parity(ushort[,] syndrome, byte[] parity = null) { var stride = syndrome.GetLength(0); @@ -65,14 +75,6 @@ namespace CUETools.Parity return syndrome; } - public static unsafe byte[] Parity2SyndromeBytes(int stride, int npar, int npar2, byte[] parity) - { - var syndrome = new byte[stride * npar * 2]; - fixed (byte* pbpar = parity, psyn = syndrome) - Parity2Syndrome((ushort*)pbpar, (ushort*)psyn, stride, npar, npar2); - return syndrome; - } - public static unsafe void Parity2Syndrome(ushort *ppar, ushort *psyn, int stride, int npar, int npar2) { if (npar > npar2) diff --git a/CUETools.TestHelpers/TestImageGenerator.cs b/CUETools.TestHelpers/TestImageGenerator.cs index 014e1d1..2c2ab12 100644 --- a/CUETools.TestHelpers/TestImageGenerator.cs +++ b/CUETools.TestHelpers/TestImageGenerator.cs @@ -70,10 +70,10 @@ namespace CUETools.TestHelpers return ar; } - public CDRepairEncode CreateCDRepairEncode(int stride, int npar) + public CDRepairEncode CreateCDRepairEncode(int stride) { var ar = new AccurateRipVerify(toc, null); - var encode = new CDRepairEncode(ar, stride, npar); + var encode = new CDRepairEncode(ar, stride); ar.Position = start; Write(ar); //ar.Close(); diff --git a/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs b/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs index d8fa906..5485470 100644 --- a/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs +++ b/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs @@ -27,7 +27,6 @@ namespace CUETools.TestParity // but it probably should still be a multiple of 588 * 2; // (or the size of CD CIRC buffer?) const int stride = 10 * 588 * 2; - const int npar = 8; const int errors = stride / 4; const int offset = 48; const int seed = 2423; @@ -36,7 +35,10 @@ namespace CUETools.TestParity private static TestImageGenerator generator; private static CDRepairEncode encode; - private TestContext testContextInstance; + private static string[] encodeSyndrome = new string[33]; + private static string[] encodeParity = new string[33]; + private static string[] encodeParity1 = new string[33]; + private TestContext testContextInstance; /// ///Gets or sets the test context which provides @@ -63,8 +65,15 @@ namespace CUETools.TestParity public static void MyClassInitialize(TestContext testContext) { generator = new TestImageGenerator("0 9801", seed, 32 * 588, 0); - encode = generator.CreateCDRepairEncode(stride, npar); - } + encode = generator.CreateCDRepairEncode(stride); + encodeSyndrome[4] = "DP7tAM2tuWBe7kb/A3o5hcS+o59uoT1ckHh9Am+wZxA="; + encodeSyndrome[8] = "DP7tAM2tuWCBRjyLjt6a+l7uRv8DejmFzRtv3ofeEWzEvqOfbqE9XFOz/6WaYU+lkHh9Am+wZxCw3m1Y7zKctw=="; + encodeSyndrome[16] = "DP7tAM2tuWCBRjyLjt6a+lr7hvwnJWrfZ0MGKOYwFmVe7kb/A3o5hc0bb96H3hFsIcjxCpERbjnJjVvLc5NDJcS+o59uoT1cU7P/pZphT6WaQ4f3L/ImdyD5psk3fWRvkHh9Am+wZxCw3m1Y7zKct8QUsJHnLA6wcmxT/LmmQdE="; + encodeParity[8] = "jvR9QJ1cSWpqbyP0I0tBrBkQRjCDTDDQkttZGj14ROvsXyg+AnnxVKxL7gwLZbrQmTw5ZPps1Q3744g94qaOOQ=="; + encodeParity[16] = "gwln1GxlYWH/Jn74PreMLv4aFF2glkScSWVFlxMBx94v5D3/3wPx+2guRLquED0s9tOFikPLiSnAv0Xq8aIQ6Q=="; + encodeParity1[8] = "CWgEDNLjSi22nIOyaeyp+12R3UCVWlzIb+nbv8XWXg9YEhkHxYr8xqrr1+hIbFwKNEXnj0esJrKbiW3XGbHsYw=="; + encodeParity1[16] = "BdvaDZCGCVEggrcfscGQWdfSXnCSrOcpD6NfKZGYraK80J2a+v/zkDPWePOQ9k0u0WdWNJ9hQKvPJD0wf2MN+g=="; + } // //Use ClassCleanup to run code after all tests in a class have run //[ClassCleanup()] @@ -86,20 +95,25 @@ namespace CUETools.TestParity // #endregion + [TestMethod()] + public void CDRepairEncodeSyndromeTest() + { + for (int n = 4; n <= AccurateRipVerify.maxNpar; n *= 2) + { + Assert.AreEqual(encodeSyndrome[n], ParityToSyndrome.ToBase64String(encode.AR.GetSyndrome(n), 0, 4)); + } + Assert.AreEqual(377539636, encode.CRC); + } + /// ///A test for Write /// [TestMethod()] - public void CDRepairEncodeWriteTest() + public void CDRepairEncodeParityTest() { - Assert.AreEqual("jvR9QJ1cSWpqbyP0I0tBrBkQRjCDTDDQkttZGj14ROvsXyg+AnnxVKxL7gwLZbrQmTw5ZPps1Q3744g94qaOOQ==", - Convert.ToBase64String(encode.AR.GetParity(8), 0, 64)); - Assert.AreEqual("DP7tAM2tuWCBRjyLjt6a+l7uRv8DejmFzRtv3ofeEWzEvqOfbqE9XFOz/6WaYU+lkHh9Am+wZxCw3m1Y7zKctw==", - Convert.ToBase64String(encode.AR.GetSyndromeBytes(8), 0, 64)); - if (AccurateRipVerify.maxNpar >= 16) + for (int n = 8; n <= AccurateRipVerify.maxNpar; n *= 2) { - Assert.AreEqual("gwln1GxlYWH/Jn74PreMLv4aFF2glkScSWVFlxMBx94v5D3/3wPx+2guRLquED0s9tOFikPLiSnAv0Xq8aIQ6Q==", - Convert.ToBase64String(encode.AR.GetParity(16), 0, 64)); + Assert.AreEqual(encodeParity[n], Convert.ToBase64String(encode.AR.GetParity(n), 0, 64)); } Assert.AreEqual(377539636, encode.CRC); } @@ -110,13 +124,16 @@ namespace CUETools.TestParity [TestMethod()] public void CDRepairDecodeOriginalTest() { - var decode = generator.CreateCDRepairEncode(stride, npar); + var decode = generator.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsTrue(decode.FindOffset(encode.AR.GetSyndrome(), encode.CRC, out actualOffset, out hasErrors)); Assert.IsFalse(hasErrors, "has errors"); Assert.AreEqual(0, actualOffset, "wrong offset"); - } + Assert.IsTrue(decode.FindOffset(encode.AR.GetSyndrome(8), encode.CRC, out actualOffset, out hasErrors)); + Assert.IsFalse(hasErrors, "has errors"); + Assert.AreEqual(0, actualOffset, "wrong offset"); + } /// ///Verifying rip that is accurate with pregap @@ -125,13 +142,13 @@ namespace CUETools.TestParity public void CDRepairDecodeOriginalWithPregapTest() { var generator2 = new TestImageGenerator("32 9833", seed, 0, 0); - var decode = generator2.CreateCDRepairEncode(stride, npar); + var decode = generator2.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsTrue(decode.FindOffset(encode.AR.GetSyndrome(), encode.CRC, out actualOffset, out hasErrors)); Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(-1176, actualOffset, "wrong offset"); - CDRepairFix fix = decode.VerifyParity(encode.Syndrome, actualOffset); + CDRepairFix fix = decode.VerifyParity(encode.AR.GetSyndrome(), actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); } @@ -143,13 +160,13 @@ namespace CUETools.TestParity public void CDRepairDecodeModifiedTest() { var generator2 = new TestImageGenerator("0 9801", seed, 32 * 588, errors); - var decode = generator2.CreateCDRepairEncode(stride, npar); + var decode = generator2.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsTrue(decode.FindOffset(encode.AR.GetSyndrome(), encode.CRC, out actualOffset, out hasErrors)); Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(0, actualOffset, "wrong offset"); - CDRepairFix fix = decode.VerifyParity(encode.Syndrome, actualOffset); + CDRepairFix fix = decode.VerifyParity(encode.AR.GetSyndrome(), actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); generator2.Write(fix); @@ -163,10 +180,10 @@ namespace CUETools.TestParity public void CDRepairDecodePositiveOffsetTest() { var generator2 = new TestImageGenerator("0 9801", seed, 32 * 588 + offset, 0); - var decode = generator2.CreateCDRepairEncode(stride, npar); + var decode = generator2.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsTrue(decode.FindOffset(encode.AR.GetSyndrome(), encode.CRC, out actualOffset, out hasErrors)); Assert.IsFalse(hasErrors, "has errors"); Assert.AreEqual(offset, actualOffset, "wrong offset"); } @@ -178,10 +195,10 @@ namespace CUETools.TestParity public void CDRepairDecodeNegativeOffsetTest() { var generator2 = new TestImageGenerator("0 9801", seed, 32 * 588 - offset, 0); - var decode = generator2.CreateCDRepairEncode(stride, npar); + var decode = generator2.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsTrue(decode.FindOffset(encode.AR.GetSyndrome(), encode.CRC, out actualOffset, out hasErrors)); Assert.IsFalse(hasErrors, "has errors"); Assert.AreEqual(-offset, actualOffset, "wrong offset"); } @@ -193,10 +210,10 @@ namespace CUETools.TestParity public void CDRepairDecodePositiveOffsetErrorsTest() { var generator2 = new TestImageGenerator("0 9801", seed, 32 * 588 + offset, errors); - var decode = generator2.CreateCDRepairEncode(stride, npar); + var decode = generator2.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - var syn = encode.AR.GetSyndrome(encode.NPAR); + var syn = encode.AR.GetSyndrome(); Assert.IsTrue(decode.FindOffset(syn, encode.CRC, out actualOffset, out hasErrors)); Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(offset, actualOffset, "wrong offset"); @@ -214,18 +231,27 @@ namespace CUETools.TestParity public void CDRepairDecodeNegativeOffsetErrorsTest() { var generator2 = new TestImageGenerator("0 999 9801", seed, 32 * 588 - offset, errors); - var decode = generator2.CreateCDRepairEncode(stride, npar); + var decode = generator2.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors), "couldn't find offset"); + Assert.IsTrue(decode.FindOffset(encode.AR.GetSyndrome(), encode.CRC, out actualOffset, out hasErrors), "couldn't find offset"); Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(-offset, actualOffset, "wrong offset"); - CDRepairFix fix = decode.VerifyParity(encode.Syndrome, actualOffset); + var fix = decode.VerifyParity(encode.AR.GetSyndrome(), actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); generator2.Write(fix); Assert.AreEqual(encode.CRC, fix.CRC); - } + + if (AccurateRipVerify.maxNpar > 8) + { + fix = decode.VerifyParity(encode.AR.GetSyndrome(8), actualOffset); + Assert.IsTrue(fix.HasErrors, "doesn't have errors"); + Assert.IsTrue(fix.CanRecover, "cannot recover"); + generator2.Write(fix); + Assert.AreEqual(encode.CRC, fix.CRC); + } + } [TestMethod] public void GFMiscTest() @@ -274,16 +300,16 @@ namespace CUETools.TestParity public void CDRepairSplitTest() { var seed = 723722; - var ar0 = new TestImageGenerator("13 68 99 136", seed, 0, 0).CreateCDRepairEncode(stride, npar); + var ar0 = new TestImageGenerator("13 68 99 136", seed, 0, 0).CreateCDRepairEncode(stride); var splits = new int[] { 1, 13 * 588 - 1, 13 * 588, 13 * 588 + 1, 30 * 588 - 1, 30 * 588, 30 * 588 + 1, 68 * 588 - 1, 68 * 588, 68 * 588 + 1 }; foreach (int split in splits) { - var ar1 = new TestImageGenerator("13 68 99 136", seed, 0, 0, 0, split).CreateCDRepairEncode(stride, npar); - var ar2 = new TestImageGenerator("13 68 99 136", seed, 0, 0, split, (int)ar0.FinalSampleCount).CreateCDRepairEncode(stride, npar); + var ar1 = new TestImageGenerator("13 68 99 136", seed, 0, 0, 0, split).CreateCDRepairEncode(stride); + var ar2 = new TestImageGenerator("13 68 99 136", seed, 0, 0, split, (int)ar0.FinalSampleCount).CreateCDRepairEncode(stride); ar1.AR.Combine(ar2.AR, split, (int)ar0.FinalSampleCount); string message = "split = " + CDImageLayout.TimeToString((uint)split / 588) + "." + (split % 588).ToString(); Assert.AreEqual(ar0.CRC, ar1.CRC, "CRC was not set correctly, " + message); - CollectionAssert.AreEqual(ar0.Parity, ar1.Parity, "Parity was not set correctly, " + message); + CollectionAssert.AreEqual(ar0.AR.GetParity(), ar1.AR.GetParity(), "Parity was not set correctly, " + message); } } @@ -295,8 +321,8 @@ namespace CUETools.TestParity { var seed = 723722; var split = 20 * 588; - var ar1 = new TestImageGenerator("13 68 99 136", seed, 0, 0, 0, split).CreateCDRepairEncode(stride, npar); - var ar2 = new TestImageGenerator("13 68 99 136", seed, 0, 0, split, (int)ar1.FinalSampleCount).CreateCDRepairEncode(stride, npar); + var ar1 = new TestImageGenerator("13 68 99 136", seed, 0, 0, 0, split).CreateCDRepairEncode(stride); + var ar2 = new TestImageGenerator("13 68 99 136", seed, 0, 0, split, (int)ar1.FinalSampleCount).CreateCDRepairEncode(stride); for (int i = 0; i < 20; i++) ar1.AR.Combine(ar2.AR, split, (int)ar1.FinalSampleCount); } @@ -307,37 +333,26 @@ namespace CUETools.TestParity [TestMethod()] public unsafe void CDRepairSyndrome2ParitySpeedTest() { - byte[] parityCopy = new byte[encode.Parity.Length]; - var syndrome = encode.Syndrome; + byte[] parityCopy = new byte[encode.AR.GetParity().Length]; + var syndrome = encode.AR.GetSyndrome(); for (int t = 0; t < 100; t++) ParityToSyndrome.Syndrome2Parity(syndrome, parityCopy); - CollectionAssert.AreEqual(encode.Parity, parityCopy); + CollectionAssert.AreEqual(encode.AR.GetParity(), parityCopy); } [TestMethod] public unsafe void CDRepairEncodeSynParTest() { - var parityCopy = ParityToSyndrome.Syndrome2Parity(encode.Syndrome); - CollectionAssert.AreEqual(encode.Parity, parityCopy); + var parityCopy = ParityToSyndrome.Syndrome2Parity(encode.AR.GetSyndrome()); + CollectionAssert.AreEqual(encode.AR.GetParity(), parityCopy); } [TestMethod] public void CDRepairEncodeSpeedTest() { var generator = new TestImageGenerator("0 75000", seed, 0, 0); - var encode = generator.CreateCDRepairEncode(stride, npar); - Assert.AreEqual("CWgEDNLjSi22nIOyaeyp+12R3UCVWlzIb+nbv8XWXg9YEhkHxYr8xqrr1+hIbFwKNEXnj0esJrKbiW3XGbHsYw==", - Convert.ToBase64String(encode.Parity, 0, 64)); - var syndrome = encode.Syndrome; - var bsyn = new byte[64]; - for (int i = 0; i < 4; i++) - for (int j = 0; j < 8; j++) - { - bsyn[(i * 8 + j) * 2] = (byte)syndrome[i, j]; - bsyn[(i * 8 + j) * 2 + 1] = (byte)(syndrome[i, j] >> 8); - } - Assert.AreEqual("YJPyo4+KY35P+DpljMplMGbMWXmpvhkdDOCKeEo4NDoRPPW7D0cv8hmLb7yZujp0sVg/6AEWKY5QrDKkiYp0Zw==", - Convert.ToBase64String(bsyn)); + var encode = generator.CreateCDRepairEncode(stride); + Assert.AreEqual(encodeParity1[AccurateRipVerify.maxNpar], Convert.ToBase64String(encode.AR.GetParity(), 0, 64), "parity mismatch"); } /// @@ -348,17 +363,18 @@ namespace CUETools.TestParity public void CDRepairVerifyParitySpeedTest() { var generator1 = new TestImageGenerator("0 98011", seed, 32 * 588, 0); - var encode1 = generator1.CreateCDRepairEncode(stride, npar); + var encode1 = generator1.CreateCDRepairEncode(stride); var generator2 = new TestImageGenerator("0 98011", seed, 32 * 588, errors/2); - var decode = generator2.CreateCDRepairEncode(stride, npar); + var decode = generator2.CreateCDRepairEncode(stride); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode1.NPAR, encode1.Parity, 0, encode1.CRC, out actualOffset, out hasErrors)); + var syndrome = encode1.AR.GetSyndrome(); + Assert.IsTrue(decode.FindOffset(syndrome, encode1.CRC, out actualOffset, out hasErrors)); Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(0, actualOffset, "wrong offset"); for (int t = 0; t < 1000; t++) - decode.VerifyParity(encode1.Syndrome, actualOffset); - CDRepairFix fix = decode.VerifyParity(encode1.Syndrome, actualOffset); + decode.VerifyParity(syndrome, actualOffset); + CDRepairFix fix = decode.VerifyParity(syndrome, actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); generator2.Write(fix);