From 2299e5f920c02128d28461b00645867afac50abb Mon Sep 17 00:00:00 2001 From: chudov Date: Wed, 26 Oct 2011 05:09:37 +0000 Subject: [PATCH] Preparing for next version of CTDB --- CUETools.AccurateRip/AccurateRip.cs | 9 +- CUETools.AccurateRip/CDRepair.cs | 173 +++++++++--------- CUETools.Codecs.LAME/LameWriterCBR.cs | 2 +- CUETools.Codecs.LAME/LameWriterVBR.cs | 2 +- CUETools.Parity/Parity2Syndrome.cs | 25 ++- .../CUETools.TestParity/CDRepairDecodeTest.cs | 54 +++--- 6 files changed, 147 insertions(+), 118 deletions(-) diff --git a/CUETools.AccurateRip/AccurateRip.cs b/CUETools.AccurateRip/AccurateRip.cs index c7b1a9f..8cf808f 100644 --- a/CUETools.AccurateRip/AccurateRip.cs +++ b/CUETools.AccurateRip/AccurateRip.cs @@ -13,7 +13,7 @@ namespace CUETools.AccurateRip { public class AccurateRipVerify : IAudioDest { - const int maxNpar = 8; + public const int maxNpar = 8; public AccurateRipVerify(CDImageLayout toc, IWebProxy proxy) { @@ -330,6 +330,13 @@ 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 e8fca95..c791edf 100644 --- a/CUETools.AccurateRip/CDRepair.cs +++ b/CUETools.AccurateRip/CDRepair.cs @@ -267,11 +267,6 @@ namespace CUETools.AccurateRip // } //} - public unsafe CDRepairFix VerifyParity(byte[] parity2, int actualOffset) - { - return VerifyParity(npar, parity2, 0, parity2.Length, actualOffset); - } - public AccurateRipVerify AR { get @@ -299,80 +294,89 @@ namespace CUETools.AccurateRip } } - public unsafe bool FindOffset(int npar2, byte[] parity2, int pos, uint expectedCRC, out int actualOffset, out bool hasErrors) - { - if (npar2 != npar) - throw new Exception("npar mismatch"); - if (ar.Position != ar.FinalSampleCount) - throw new Exception("ar.Position != ar.FinalSampleCount"); + 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); + } - // find offset - fixed (byte* par2ptr = &parity2[pos]) - fixed (ushort* chT = rs.chienTable) - { - ushort* par2 = (ushort*)par2ptr; - int* _sigma = stackalloc int[npar]; - int* _errpos = stackalloc int[npar]; - int* syn = stackalloc int[npar]; - bool foundOffset = false; - var arSyndrome = ar.GetSyndrome(npar); + public unsafe bool FindOffset(ushort[,] syn2, uint expectedCRC, out int actualOffset, out bool hasErrors) + { + int npar2 = syn2.GetLength(1); - for (int allowed_errors = 0; allowed_errors < npar / 2 && !foundOffset; allowed_errors++) - { - int part2 = 0; - ushort* wr = par2 + part2 * npar; + if (npar2 != npar) + throw new Exception("npar mismatch"); + if (ar.Position != ar.FinalSampleCount) + throw new Exception("ar.Position != ar.FinalSampleCount"); - // 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++) - { - int err = 0; - int part = (part2 + stride - offset * 2) % stride; + int part2 = 0; + // find offset + fixed (ushort* chT = rs.chienTable, syn2part = &syn2[part2, 0]) + { + int* _sigma = stackalloc int[npar]; + int* _errpos = stackalloc int[npar]; + int* syn = stackalloc int[npar]; + bool foundOffset = false; + var arSyndrome = ar.GetSyndrome(npar); - for (int i = 0; i < npar; i++) - { - int synI = arSyndrome[part, i]; + for (int allowed_errors = 0; allowed_errors < npar / 2 && !foundOffset; allowed_errors++) + { + // 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++) + { + int err = 0; + int part = (part2 + stride - offset * 2) % stride; - // 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); - } + for (int i = 0; i < npar; i++) + { + int synI = arSyndrome[part, i]; - for (int j = 0; j < npar; j++) - synI = wr[j] ^ galois.mulExp(synI, 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); + } - 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; - } - } - } - } - actualOffset = 0; - hasErrors = true; - return false; - } + 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; + } + } + } + } + actualOffset = 0; + hasErrors = true; + return false; + } - public unsafe CDRepairFix VerifyParity(int npar2, byte[] parity2, int pos, int len, int actualOffset) - { - if (len != stride * npar * 2) + 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); CDRepairFix fix = new CDRepairFix(this); fix.actualOffset = actualOffset; @@ -386,43 +390,42 @@ namespace CUETools.AccurateRip //fix.erroff = new int[stride, npar / 2]; fix.errors = new int[stride]; - fixed (byte* par = &parity2[pos]) - fixed (ushort* exp = galois.ExpTbl, log = galois.LogTbl, chT = rs.chienTable) + var syn1 = ar.GetSyndrome(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) { int* syn = stackalloc int[npar]; int offset = fix.actualOffset; - var arSyndrome = ar.GetSyndrome(npar); for (int part = 0; part < stride; part++) { int part2 = (part + offset * 2 + stride) % stride; - ushort* wr = (ushort*)par + part2 * npar; + ushort* syn1part = psyn1 + part * npar; + ushort* syn2part = psyn2 + part2 * npar; int err = 0; for (int i = 0; i < npar; i++) { - syn[i] = arSyndrome[part, i]; + int synI = syn1part[i]; // offset < 0 if (part < -offset * 2) { - syn[i] ^= galois.mulExp(ar.leadin[stride + part], (i * (stridecount - 1)) % galois.Max); - syn[i] = ar.leadout[laststride - part - 1] ^ galois.mulExp(syn[i], i); + 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) { - syn[i] = galois.divExp(syn[i] ^ ar.leadout[laststride + stride - part - 1], i); - syn[i] ^= galois.mulExp(ar.leadin[part], (i * (stridecount - 1)) % galois.Max); + synI = galois.divExp(synI ^ ar.leadout[laststride + stride - part - 1], i); + synI ^= galois.mulExp(ar.leadin[part], (i * (stridecount - 1)) % galois.Max); } - //syn[i] = galois.mulExp(syn[i], i * npar); - - for (int j = 0; j < npar; j++) - syn[i] = wr[j] ^ galois.mulExp(syn[i], i); // wk = data + wk * α^i - - err |= syn[i]; + synI = galois.mulExp(synI ^ syn2part[i], i * npar); + syn[i] = synI; + err |= synI; } //for (int j = 0; j < npar; j++) diff --git a/CUETools.Codecs.LAME/LameWriterCBR.cs b/CUETools.Codecs.LAME/LameWriterCBR.cs index 850f1f3..bf73b06 100644 --- a/CUETools.Codecs.LAME/LameWriterCBR.cs +++ b/CUETools.Codecs.LAME/LameWriterCBR.cs @@ -3,7 +3,7 @@ using System.IO; namespace CUETools.Codecs.LAME { - [AudioEncoderClass("lame2 CBR", "mp3", false, "96 128 192 256 320", "256", 2, typeof(LameWriterCBRSettings))] + [AudioEncoderClass("libmp3lame CBR", "mp3", false, "96 128 192 256 320", "256", 2, typeof(LameWriterCBRSettings))] public class LameWriterCBR : LameWriter { private static readonly int[] bps_table = new int[] { 96, 128, 192, 256, 320 }; diff --git a/CUETools.Codecs.LAME/LameWriterVBR.cs b/CUETools.Codecs.LAME/LameWriterVBR.cs index 2a68378..bf93915 100644 --- a/CUETools.Codecs.LAME/LameWriterVBR.cs +++ b/CUETools.Codecs.LAME/LameWriterVBR.cs @@ -3,7 +3,7 @@ using System.IO; namespace CUETools.Codecs.LAME { - [AudioEncoderClass("lame2 VBR", "mp3", false, "V9 V8 V7 V6 V5 V4 V3 V2 V1 V0", "V2", 2, typeof(LameWriterVBRSettings))] + [AudioEncoderClass("libmp3lame VBR", "mp3", false, "V9 V8 V7 V6 V5 V4 V3 V2 V1 V0", "V2", 2, typeof(LameWriterVBRSettings))] public class LameWriterVBR : LameWriter { private int quality = 0; diff --git a/CUETools.Parity/Parity2Syndrome.cs b/CUETools.Parity/Parity2Syndrome.cs index cd205d1..7e6fea8 100644 --- a/CUETools.Parity/Parity2Syndrome.cs +++ b/CUETools.Parity/Parity2Syndrome.cs @@ -56,15 +56,29 @@ namespace CUETools.Parity return parity; } - public static unsafe ushort[,] Parity2Syndrome(int stride, int npar, int npar2, byte[] parity) + public static unsafe ushort[,] Parity2Syndrome(int stride, int npar, int npar2, byte[] parity, int pos = 0) + { + var syndrome = new ushort[stride, npar]; + fixed (byte* pbpar = &parity[pos]) + fixed (ushort* psyn = syndrome) + Parity2Syndrome((ushort*)pbpar, psyn, stride, npar, npar2); + 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) throw new InvalidOperationException(); - var syndrome = new ushort[stride, npar]; - fixed (byte* pbpar = parity) - fixed (ushort* psyn = syndrome, plog = Galois16.instance.LogTbl, pexp = Galois16.instance.ExpTbl) + fixed (ushort *plog = Galois16.instance.LogTbl, pexp = Galois16.instance.ExpTbl) { - ushort* ppar = (ushort*)pbpar; for (int y = 0; y < stride; y++) { ushort* syn = psyn + y * npar; @@ -81,7 +95,6 @@ namespace CUETools.Parity } } } - return syndrome; } public unsafe void Syndrome2Parity(ushort* syndrome, ushort* parity) diff --git a/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs b/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs index 7fa9345..d8fa906 100644 --- a/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs +++ b/CUETools/CUETools.TestParity/CDRepairDecodeTest.cs @@ -94,8 +94,13 @@ namespace CUETools.TestParity { Assert.AreEqual("jvR9QJ1cSWpqbyP0I0tBrBkQRjCDTDDQkttZGj14ROvsXyg+AnnxVKxL7gwLZbrQmTw5ZPps1Q3744g94qaOOQ==", Convert.ToBase64String(encode.AR.GetParity(8), 0, 64)); - //Assert.AreEqual("gwln1GxlYWH/Jn74PreMLv4aFF2glkScSWVFlxMBx94v5D3/3wPx+2guRLquED0s9tOFikPLiSnAv0Xq8aIQ6Q==", - // Convert.ToBase64String(encode.AR.GetParity(16), 0, 64)); + Assert.AreEqual("DP7tAM2tuWCBRjyLjt6a+l7uRv8DejmFzRtv3ofeEWzEvqOfbqE9XFOz/6WaYU+lkHh9Am+wZxCw3m1Y7zKctw==", + Convert.ToBase64String(encode.AR.GetSyndromeBytes(8), 0, 64)); + if (AccurateRipVerify.maxNpar >= 16) + { + Assert.AreEqual("gwln1GxlYWH/Jn74PreMLv4aFF2glkScSWVFlxMBx94v5D3/3wPx+2guRLquED0s9tOFikPLiSnAv0Xq8aIQ6Q==", + Convert.ToBase64String(encode.AR.GetParity(16), 0, 64)); + } Assert.AreEqual(377539636, encode.CRC); } @@ -108,9 +113,9 @@ namespace CUETools.TestParity var decode = generator.CreateCDRepairEncode(stride, npar); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); - Assert.IsFalse(hasErrors, "has errors"); - Assert.AreEqual(0, actualOffset, "wrong offset"); + Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsFalse(hasErrors, "has errors"); + Assert.AreEqual(0, actualOffset, "wrong offset"); } /// @@ -126,7 +131,7 @@ namespace CUETools.TestParity Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(-1176, actualOffset, "wrong offset"); - CDRepairFix fix = decode.VerifyParity(encode.Parity, actualOffset); + CDRepairFix fix = decode.VerifyParity(encode.Syndrome, actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); } @@ -144,7 +149,7 @@ namespace CUETools.TestParity Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(0, actualOffset, "wrong offset"); - CDRepairFix fix = decode.VerifyParity(encode.Parity, actualOffset); + CDRepairFix fix = decode.VerifyParity(encode.Syndrome, actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); generator2.Write(fix); @@ -161,9 +166,9 @@ namespace CUETools.TestParity var decode = generator2.CreateCDRepairEncode(stride, npar); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); - Assert.IsFalse(hasErrors, "has errors"); - Assert.AreEqual(offset, actualOffset, "wrong offset"); + Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsFalse(hasErrors, "has errors"); + Assert.AreEqual(offset, actualOffset, "wrong offset"); } /// @@ -176,9 +181,9 @@ namespace CUETools.TestParity var decode = generator2.CreateCDRepairEncode(stride, npar); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); - Assert.IsFalse(hasErrors, "has errors"); - Assert.AreEqual(-offset, actualOffset, "wrong offset"); + Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsFalse(hasErrors, "has errors"); + Assert.AreEqual(-offset, actualOffset, "wrong offset"); } /// @@ -191,14 +196,15 @@ namespace CUETools.TestParity var decode = generator2.CreateCDRepairEncode(stride, npar); int actualOffset; bool hasErrors; - Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, encode.CRC, out actualOffset, out hasErrors)); - Assert.IsTrue(hasErrors, "doesn't have errors"); - Assert.AreEqual(offset, actualOffset, "wrong offset"); - CDRepairFix fix = decode.VerifyParity(encode.Parity, actualOffset); - Assert.IsTrue(fix.HasErrors, "doesn't have errors"); - Assert.IsTrue(fix.CanRecover, "cannot recover"); - generator2.Write(fix); - Assert.AreEqual(encode.CRC, fix.CRC); + var syn = encode.AR.GetSyndrome(encode.NPAR); + Assert.IsTrue(decode.FindOffset(syn, encode.CRC, out actualOffset, out hasErrors)); + Assert.IsTrue(hasErrors, "doesn't have errors"); + Assert.AreEqual(offset, actualOffset, "wrong offset"); + CDRepairFix fix = decode.VerifyParity(syn, actualOffset); + Assert.IsTrue(fix.HasErrors, "doesn't have errors"); + Assert.IsTrue(fix.CanRecover, "cannot recover"); + generator2.Write(fix); + Assert.AreEqual(encode.CRC, fix.CRC); } /// @@ -214,7 +220,7 @@ namespace CUETools.TestParity Assert.IsTrue(decode.FindOffset(encode.NPAR, encode.Parity, 0, 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.Parity, actualOffset); + CDRepairFix fix = decode.VerifyParity(encode.Syndrome, actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); generator2.Write(fix); @@ -351,8 +357,8 @@ namespace CUETools.TestParity Assert.IsTrue(hasErrors, "doesn't have errors"); Assert.AreEqual(0, actualOffset, "wrong offset"); for (int t = 0; t < 1000; t++) - decode.VerifyParity(encode1.Parity, actualOffset); - CDRepairFix fix = decode.VerifyParity(encode1.Parity, actualOffset); + decode.VerifyParity(encode1.Syndrome, actualOffset); + CDRepairFix fix = decode.VerifyParity(encode1.Syndrome, actualOffset); Assert.IsTrue(fix.HasErrors, "doesn't have errors"); Assert.IsTrue(fix.CanRecover, "cannot recover"); generator2.Write(fix);