mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
Preparing for next version of CTDB
This commit is contained in:
@@ -5,153 +5,16 @@ using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml.Serialization;
|
||||
using CUETools.Parity;
|
||||
using CUETools.CDImage;
|
||||
using CUETools.Codecs;
|
||||
|
||||
namespace CUETools.AccurateRip
|
||||
{
|
||||
[Serializable]
|
||||
public class OffsetSafeCRCRecord
|
||||
{
|
||||
private uint[] val;
|
||||
|
||||
public OffsetSafeCRCRecord()
|
||||
{
|
||||
this.val = new uint[1];
|
||||
}
|
||||
|
||||
public OffsetSafeCRCRecord(AccurateRipVerify ar)
|
||||
: this(new uint[64 + 64])
|
||||
{
|
||||
int offset = 64 * 64;
|
||||
for (int i = 0; i < 64; i++)
|
||||
this.val[i] = ar.CTDBCRC(0, (i + 1) * 64, offset, 2 * offset);
|
||||
for (int i = 0; i < 64; i++)
|
||||
this.val[i + 64] = ar.CTDBCRC(0, 63 - i, offset, 2 * offset);
|
||||
}
|
||||
|
||||
public OffsetSafeCRCRecord(uint[] val)
|
||||
{
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public uint[] Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe string Base64
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] res = new byte[val.Length * 4];
|
||||
fixed (byte* pres = &res[0])
|
||||
fixed (uint* psrc = &val[0])
|
||||
AudioSamples.MemCpy(pres, (byte*)psrc, res.Length);
|
||||
var b64 = new char[res.Length * 2 + 4];
|
||||
int b64len = Convert.ToBase64CharArray(res, 0, res.Length, b64, 0);
|
||||
StringBuilder sb = new StringBuilder(b64len + b64len / 4 + 1);
|
||||
for (int i = 0; i < b64len; i += 64)
|
||||
{
|
||||
sb.Append(b64, i, Math.Min(64, b64len - i));
|
||||
sb.AppendLine();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException();
|
||||
byte[] bytes = Convert.FromBase64String(value);
|
||||
if (bytes.Length % 4 != 0)
|
||||
throw new InvalidDataException();
|
||||
val = new uint[bytes.Length / 4];
|
||||
fixed (byte* pb = &bytes[0])
|
||||
fixed (uint* pv = &val[0])
|
||||
AudioSamples.MemCpy((byte*)pv, pb, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is OffsetSafeCRCRecord && this == (OffsetSafeCRCRecord)obj;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)val[0];
|
||||
}
|
||||
|
||||
public static bool operator ==(OffsetSafeCRCRecord x, OffsetSafeCRCRecord y)
|
||||
{
|
||||
if (x as object == null || y as object == null) return x as object == null && y as object == null;
|
||||
if (x.Value.Length != y.Value.Length) return false;
|
||||
for (int i = 0; i < x.Value.Length; i++)
|
||||
if (x.Value[i] != y.Value[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator !=(OffsetSafeCRCRecord x, OffsetSafeCRCRecord y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
public bool DifferByOffset(OffsetSafeCRCRecord rec)
|
||||
{
|
||||
int offset;
|
||||
return FindOffset(rec, out offset);
|
||||
}
|
||||
|
||||
public bool FindOffset(OffsetSafeCRCRecord rec, out int offset)
|
||||
{
|
||||
if (this.Value.Length != 128 || rec.Value.Length != 128)
|
||||
{
|
||||
offset = 0;
|
||||
return false;
|
||||
//throw new InvalidDataException("Unsupported OffsetSafeCRCRecord");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (rec.Value[0] == Value[i])
|
||||
{
|
||||
offset = i * 64;
|
||||
return true;
|
||||
}
|
||||
if (Value[0] == rec.Value[i])
|
||||
{
|
||||
offset = -i * 64;
|
||||
return true;
|
||||
}
|
||||
for (int j = 0; j < 64; j++)
|
||||
{
|
||||
if (rec.Value[i] == Value[64 + j])
|
||||
{
|
||||
offset = i * 64 + j + 1;
|
||||
return true;
|
||||
}
|
||||
if (Value[i] == rec.Value[64 + j])
|
||||
{
|
||||
offset = -i * 64 - j - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
offset = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class AccurateRipVerify : IAudioDest
|
||||
{
|
||||
const int maxNpar = 8;
|
||||
|
||||
public AccurateRipVerify(CDImageLayout toc, IWebProxy proxy)
|
||||
{
|
||||
this.proxy = proxy;
|
||||
@@ -451,62 +314,37 @@ namespace CUETools.AccurateRip
|
||||
_CRCLOG[iTrack] = value;
|
||||
}
|
||||
|
||||
public unsafe ushort[,] GetSyndrome()
|
||||
public unsafe byte[] GetParity(int npar = maxNpar)
|
||||
{
|
||||
if (npar == maxNpar)
|
||||
return this.parity;
|
||||
|
||||
var synShort = this.GetSyndrome(npar);
|
||||
return ParityToSyndrome.Syndrome2Parity(synShort);
|
||||
}
|
||||
|
||||
public unsafe ushort[,] GetSyndrome(int npar = maxNpar)
|
||||
{
|
||||
if (!calcParity)
|
||||
throw new InvalidOperationException();
|
||||
var syndrome = new ushort[stride, npar];
|
||||
fixed (byte* pbpar = parity)
|
||||
fixed (ushort* psyn0 = syndrome, plog = Galois16.instance.LogTbl, pexp = Galois16.instance.ExpTbl)
|
||||
{
|
||||
ushort* ppar = (ushort*)pbpar;
|
||||
for (int y = 0; y < stride; y++)
|
||||
{
|
||||
ushort* syn = psyn0 + y * npar;
|
||||
for (int x1 = 0; x1 < npar; x1++)
|
||||
{
|
||||
ushort lo = ppar[y * npar + x1];
|
||||
if (lo != 0)
|
||||
{
|
||||
var llo = plog[lo] + 0xffff;
|
||||
for (int x = 0; x < npar; x++)
|
||||
syn[x] ^= pexp[llo - (1 + x1) * x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return syndrome;
|
||||
return ParityToSyndrome.Parity2Syndrome(stride, npar, maxNpar, parity);
|
||||
}
|
||||
|
||||
public unsafe ushort[,] Syndrome
|
||||
{
|
||||
get
|
||||
{
|
||||
if (syndrome == null)
|
||||
syndrome = GetSyndrome();
|
||||
return syndrome;
|
||||
}
|
||||
}
|
||||
|
||||
private ushort[,] syndrome;
|
||||
internal byte[] parity;
|
||||
private byte[] parity;
|
||||
internal ushort[, ,] encodeTable;
|
||||
private int maxOffset;
|
||||
internal ushort[] leadin;
|
||||
internal ushort[] leadout;
|
||||
private int stride = 1, laststride = 1, stridecount = 1, npar = 1;
|
||||
private int stride = 1, laststride = 1, stridecount = 1;
|
||||
private bool calcParity = false;
|
||||
|
||||
internal void InitCDRepair(int stride, int laststride, int stridecount, int npar, bool calcParity)
|
||||
internal void InitCDRepair(int stride, int laststride, int stridecount, bool calcParity)
|
||||
{
|
||||
if (npar != 8)
|
||||
throw new ArgumentOutOfRangeException("npar");
|
||||
if (stride % 2 != 0 || laststride % 2 != 0)
|
||||
throw new ArgumentOutOfRangeException("stride");
|
||||
this.stride = stride;
|
||||
this.laststride = laststride;
|
||||
this.stridecount = stridecount;
|
||||
this.npar = npar;
|
||||
this.calcParity = calcParity;
|
||||
Init(_toc);
|
||||
}
|
||||
@@ -572,20 +410,37 @@ namespace CUETools.AccurateRip
|
||||
// ((ulong*)wr)[1] = (((ulong*)(wr))[1] >> 16) ^ ((ulong*)ptiblo0)[1] ^ ((ulong*)ptiblo1)[1];
|
||||
//}
|
||||
|
||||
private unsafe static void CalcPar8(ushort* pt, ushort* wr, uint lo, uint hi)
|
||||
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[8] ^ hi;
|
||||
ushort* ptiblo0 = pt + (wrlo & 255) * 16;
|
||||
ushort* ptiblo1 = pt + (wrlo >> 8) * 16 + 8;
|
||||
ushort* ptibhi0 = pt + (wrhi & 255) * 16;
|
||||
ushort* ptibhi1 = pt + (wrhi >> 8) * 16 + 8;
|
||||
wr[8] = 0;
|
||||
uint wrhi = wr[maxNpar] ^ hi;
|
||||
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;
|
||||
|
||||
@@ -665,7 +520,7 @@ namespace CUETools.AccurateRip
|
||||
}
|
||||
|
||||
uint hi = sample >> 16;
|
||||
if (doPar) CalcPar8(pte, wr + i * 16, lo, hi);
|
||||
if (doPar) CalcPar(pte, wr + i * maxNpar * 2, lo, hi);
|
||||
//if (doPar) CalcPar8(pte, wr + i * 16, lo);
|
||||
//uint hi = sample >> 16;
|
||||
|
||||
@@ -738,7 +593,7 @@ namespace CUETools.AccurateRip
|
||||
uint* samples = ((uint*)pSampleBuff) + pos;
|
||||
int currentPart = ((int)_sampleCount * 2) % stride;
|
||||
//ushort* synptr = synptr1 + npar * currentPart;
|
||||
ushort* wr = ((ushort*)bpar) + npar * currentPart;
|
||||
ushort* wr = ((ushort*)bpar) + maxNpar * currentPart;
|
||||
int currentStride = ((int)_sampleCount * 2) / stride;
|
||||
|
||||
for (int i = 0; i < Math.Min(leadin.Length - (int)_sampleCount * 2, copyCount * 2); i++)
|
||||
@@ -887,18 +742,13 @@ namespace CUETools.AccurateRip
|
||||
var imax = Math.Max(i1s, i2s);
|
||||
var diff1 = diff + (imin < i2s ? 1 : 0) - (imin < i1s ? 1 : 0);
|
||||
for (int i = 0; i < stride; i++)
|
||||
for (int j = 0; j < npar; j++)
|
||||
for (int j = 0; j < maxNpar; j++)
|
||||
{
|
||||
var d1 = j * (i >= imin && i < imax ? diff1 : diff);
|
||||
newSyndrome1[i, j] = (ushort)(newSyndrome2[i, j] ^ Galois16.instance.mulExp(newSyndrome1[i, j], (d1 & 0xffff) + (d1 >> 16)));
|
||||
}
|
||||
fixed (byte* p = this.parity)
|
||||
fixed (ushort* syn = newSyndrome1)
|
||||
{
|
||||
ushort* p1 = (ushort*)p;
|
||||
for (int i = 0; i < stride; i++)
|
||||
Galois16.instance.Syndrome2Parity(syn + i * npar, p1 + i * npar, npar);
|
||||
}
|
||||
|
||||
ParityToSyndrome.Syndrome2Parity(newSyndrome1, this.parity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,10 +774,12 @@ namespace CUETools.AccurateRip
|
||||
_CRCV2 = new uint[_toc.AudioTracks + 1, 3 * maxOffset];
|
||||
|
||||
_Peak = new int[_toc.AudioTracks + 1];
|
||||
syndrome = null;
|
||||
parity = calcParity ? new byte[stride * npar * 2] : null;
|
||||
if (calcParity && npar == 8)
|
||||
encodeTable = Galois16.instance.makeEncodeTable(npar);
|
||||
parity = null;
|
||||
if (calcParity)
|
||||
{
|
||||
parity = new byte[stride * maxNpar * 2];
|
||||
encodeTable = Galois16.instance.makeEncodeTable(maxNpar);
|
||||
}
|
||||
|
||||
int leadin_len = Math.Max(4096 * 4, calcParity ? stride * 2 : 0);
|
||||
int leadout_len = Math.Max(4096 * 4, calcParity ? stride + laststride : 0);
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace CUETools.AccurateRip
|
||||
: base ((int)ar.FinalSampleCount, stride, npar)
|
||||
{
|
||||
this.ar = ar;
|
||||
ar.InitCDRepair(stride, laststride, stridecount, npar, true);
|
||||
ar.InitCDRepair(stride, laststride, stridecount, true);
|
||||
}
|
||||
|
||||
//private unsafe void ProcessStride(int currentStride, int currentPart, int count, ushort* data)
|
||||
@@ -315,7 +315,7 @@ namespace CUETools.AccurateRip
|
||||
int* _errpos = stackalloc int[npar];
|
||||
int* syn = stackalloc int[npar];
|
||||
bool foundOffset = false;
|
||||
var arSyndrome = ar.Syndrome;
|
||||
var arSyndrome = ar.GetSyndrome(npar);
|
||||
|
||||
for (int allowed_errors = 0; allowed_errors < npar / 2 && !foundOffset; allowed_errors++)
|
||||
{
|
||||
@@ -392,7 +392,7 @@ namespace CUETools.AccurateRip
|
||||
{
|
||||
int* syn = stackalloc int[npar];
|
||||
int offset = fix.actualOffset;
|
||||
var arSyndrome = ar.Syndrome;
|
||||
var arSyndrome = ar.GetSyndrome(npar);
|
||||
|
||||
for (int part = 0; part < stride; part++)
|
||||
{
|
||||
@@ -473,7 +473,7 @@ namespace CUETools.AccurateRip
|
||||
{
|
||||
get
|
||||
{
|
||||
return ar.Syndrome;
|
||||
return this.ar.GetSyndrome(this.npar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,7 +481,7 @@ namespace CUETools.AccurateRip
|
||||
{
|
||||
get
|
||||
{
|
||||
return ar.parity;
|
||||
return this.ar.GetParity(this.npar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="AccurateRip.cs" />
|
||||
<Compile Include="CDRepair.cs" />
|
||||
<Compile Include="OffsetSafeCRCRecord.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
147
CUETools.AccurateRip/OffsetSafeCRCRecord.cs
Normal file
147
CUETools.AccurateRip/OffsetSafeCRCRecord.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using CUETools.Codecs;
|
||||
|
||||
namespace CUETools.AccurateRip
|
||||
{
|
||||
[Serializable]
|
||||
public class OffsetSafeCRCRecord
|
||||
{
|
||||
private uint[] val;
|
||||
|
||||
public OffsetSafeCRCRecord()
|
||||
{
|
||||
this.val = new uint[1];
|
||||
}
|
||||
|
||||
public OffsetSafeCRCRecord(AccurateRipVerify ar)
|
||||
: this(new uint[64 + 64])
|
||||
{
|
||||
int offset = 64 * 64;
|
||||
for (int i = 0; i < 64; i++)
|
||||
this.val[i] = ar.CTDBCRC(0, (i + 1) * 64, offset, 2 * offset);
|
||||
for (int i = 0; i < 64; i++)
|
||||
this.val[i + 64] = ar.CTDBCRC(0, 63 - i, offset, 2 * offset);
|
||||
}
|
||||
|
||||
public OffsetSafeCRCRecord(uint[] val)
|
||||
{
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public uint[] Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe string Base64
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] res = new byte[val.Length * 4];
|
||||
fixed (byte* pres = &res[0])
|
||||
fixed (uint* psrc = &val[0])
|
||||
AudioSamples.MemCpy(pres, (byte*)psrc, res.Length);
|
||||
var b64 = new char[res.Length * 2 + 4];
|
||||
int b64len = Convert.ToBase64CharArray(res, 0, res.Length, b64, 0);
|
||||
StringBuilder sb = new StringBuilder(b64len + b64len / 4 + 1);
|
||||
for (int i = 0; i < b64len; i += 64)
|
||||
{
|
||||
sb.Append(b64, i, Math.Min(64, b64len - i));
|
||||
sb.AppendLine();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException();
|
||||
byte[] bytes = Convert.FromBase64String(value);
|
||||
if (bytes.Length % 4 != 0)
|
||||
throw new InvalidDataException();
|
||||
val = new uint[bytes.Length / 4];
|
||||
fixed (byte* pb = &bytes[0])
|
||||
fixed (uint* pv = &val[0])
|
||||
AudioSamples.MemCpy((byte*)pv, pb, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is OffsetSafeCRCRecord && this == (OffsetSafeCRCRecord)obj;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)val[0];
|
||||
}
|
||||
|
||||
public static bool operator ==(OffsetSafeCRCRecord x, OffsetSafeCRCRecord y)
|
||||
{
|
||||
if (x as object == null || y as object == null) return x as object == null && y as object == null;
|
||||
if (x.Value.Length != y.Value.Length) return false;
|
||||
for (int i = 0; i < x.Value.Length; i++)
|
||||
if (x.Value[i] != y.Value[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator !=(OffsetSafeCRCRecord x, OffsetSafeCRCRecord y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
public bool DifferByOffset(OffsetSafeCRCRecord rec)
|
||||
{
|
||||
int offset;
|
||||
return FindOffset(rec, out offset);
|
||||
}
|
||||
|
||||
public bool FindOffset(OffsetSafeCRCRecord rec, out int offset)
|
||||
{
|
||||
if (this.Value.Length != 128 || rec.Value.Length != 128)
|
||||
{
|
||||
offset = 0;
|
||||
return false;
|
||||
//throw new InvalidDataException("Unsupported OffsetSafeCRCRecord");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (rec.Value[0] == Value[i])
|
||||
{
|
||||
offset = i * 64;
|
||||
return true;
|
||||
}
|
||||
if (Value[0] == rec.Value[i])
|
||||
{
|
||||
offset = -i * 64;
|
||||
return true;
|
||||
}
|
||||
for (int j = 0; j < 64; j++)
|
||||
{
|
||||
if (rec.Value[i] == Value[64 + j])
|
||||
{
|
||||
offset = i * 64 + j + 1;
|
||||
return true;
|
||||
}
|
||||
if (Value[i] == rec.Value[64 + j])
|
||||
{
|
||||
offset = -i * 64 - j - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
offset = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using CUETools.Codecs;
|
||||
using System.IO;
|
||||
|
||||
namespace CUETools.Codecs.LAME
|
||||
{
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Galois.cs" />
|
||||
<Compile Include="Parity2Syndrome.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RsDecode.cs" />
|
||||
<Compile Include="RsEncode.cs" />
|
||||
|
||||
Binary file not shown.
159
CUETools.Parity/Parity2Syndrome.cs
Normal file
159
CUETools.Parity/Parity2Syndrome.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Parity
|
||||
{
|
||||
public class ParityToSyndrome
|
||||
{
|
||||
private int[] erasures_pos;
|
||||
private int[] erasure_loc_pol;
|
||||
private int[] erasure_diff;
|
||||
private int npar;
|
||||
const int w = 16;
|
||||
const int max = (1 << w) - 1;
|
||||
|
||||
public ParityToSyndrome(int npar)
|
||||
{
|
||||
this.npar = npar;
|
||||
this.InitTables();
|
||||
}
|
||||
|
||||
private void InitTables()
|
||||
{
|
||||
var num_erasures = this.npar;
|
||||
|
||||
// Compute the erasure locator polynomial:
|
||||
erasures_pos = new int[num_erasures];
|
||||
for (int x = 0; x < num_erasures; x++)
|
||||
erasures_pos[x] = x;
|
||||
|
||||
//%Compute the erasure-locator polynomial
|
||||
// Optimized version
|
||||
var erasure_loc_pol_exp = new int[num_erasures + 1];
|
||||
erasure_loc_pol_exp[0] = 1;
|
||||
for (int i = 0; i < num_erasures; i++)
|
||||
for (int x = num_erasures; x > 0; x--)
|
||||
erasure_loc_pol_exp[x] ^= Galois16.instance.mulExp(erasure_loc_pol_exp[x - 1], erasures_pos[i]);
|
||||
erasure_loc_pol = Galois16.instance.toLog(erasure_loc_pol_exp);
|
||||
erasure_diff = Galois16.instance.gfdiff(erasure_loc_pol);
|
||||
}
|
||||
|
||||
public static unsafe byte[] Syndrome2Parity(ushort[,] syndrome, byte[] parity = null)
|
||||
{
|
||||
var stride = syndrome.GetLength(0);
|
||||
var npar = syndrome.GetLength(1);
|
||||
var converter = new ParityToSyndrome(npar);
|
||||
if (parity == null)
|
||||
parity = new byte[npar * stride * 2];
|
||||
fixed (byte* bpar = parity)
|
||||
fixed (ushort* syn = syndrome)
|
||||
{
|
||||
ushort* par = (ushort*)bpar;
|
||||
for (int i = 0; i < stride; i++)
|
||||
converter.Syndrome2Parity(syn + i * npar, par + i * npar);
|
||||
}
|
||||
return parity;
|
||||
}
|
||||
|
||||
public static unsafe ushort[,] Parity2Syndrome(int stride, int npar, int npar2, byte[] parity)
|
||||
{
|
||||
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)
|
||||
{
|
||||
ushort* ppar = (ushort*)pbpar;
|
||||
for (int y = 0; y < stride; y++)
|
||||
{
|
||||
ushort* syn = psyn + y * npar;
|
||||
ushort* par = ppar + y * npar2;
|
||||
for (int x1 = 0; x1 < npar2; x1++)
|
||||
{
|
||||
ushort lo = par[x1];
|
||||
if (lo != 0)
|
||||
{
|
||||
var llo = plog[lo] + 0xffff;
|
||||
for (int x = 0; x < npar; x++)
|
||||
syn[x] ^= pexp[llo - (1 + x1) * x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return syndrome;
|
||||
}
|
||||
|
||||
public unsafe void Syndrome2Parity(ushort* syndrome, ushort* parity)
|
||||
{
|
||||
// Advance syndrome by npar zeroes (for npar 'erased' parity symbols)
|
||||
var S_pol = new int[npar + 1];
|
||||
S_pol[0] = -1;
|
||||
for (int i = 0; i < npar; i++)
|
||||
{
|
||||
if (syndrome[i] == 0)
|
||||
S_pol[i + 1] = -1;
|
||||
else
|
||||
{
|
||||
var exp = Galois16.instance.LogTbl[syndrome[i]] + npar * i;
|
||||
S_pol[i + 1] = (exp & max) + (exp >> w);
|
||||
}
|
||||
}
|
||||
var mod_syn = Galois16.instance.gfconv(erasure_loc_pol, S_pol, npar + 1);
|
||||
|
||||
//%Calculate remaining errors (non-erasures)
|
||||
//
|
||||
//S_M = [];
|
||||
//for i = 1:h - num_erasures
|
||||
// S_M(i) = mod_syn(i + num_erasures + 1);
|
||||
//end
|
||||
//flag = 0;
|
||||
//if isempty(S_M) == 1
|
||||
// flag = 0;
|
||||
//else
|
||||
// for i = 1:length(S_M)
|
||||
// if (S_M(i) ~= -Inf)
|
||||
// flag = 1; %Other errors occured in conjunction with erasures
|
||||
// end
|
||||
// end
|
||||
//end
|
||||
//%Find error-location polynomial sigma (Berlekamp's iterative algorithm -
|
||||
//if (flag == 1)
|
||||
//{
|
||||
// ...
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// sigma = 0;
|
||||
// comp_error_locs = [];
|
||||
//}
|
||||
|
||||
#if kjsljdf
|
||||
var sigma = new int[1] { 0 };
|
||||
var omega = gfconv(sigma, gfadd(mod_syn, 0), npar + 1);
|
||||
var tsi = gfconv(sigma, erasure_loc_pol);
|
||||
var tsi_diff = gfdiff(tsi);
|
||||
//var e_e_places = [erasures_pos comp_error_locs];
|
||||
#else
|
||||
var omega = mod_syn;
|
||||
var tsi_diff = erasure_diff;
|
||||
var e_e_places = erasures_pos;
|
||||
#endif
|
||||
|
||||
//%Calculate the error magnitudes
|
||||
//%Substitute the inverse into sigma_diff
|
||||
//var ERR = new int[e_e_places.Length];
|
||||
for (int ii = 0; ii < e_e_places.Length; ii++)
|
||||
{
|
||||
var point = max - e_e_places[ii];
|
||||
var ERR_DEN = Galois16.instance.gfsubstitute(tsi_diff, point, tsi_diff.Length);
|
||||
var ERR_NUM = Galois16.instance.gfsubstitute(omega, point, omega.Length);
|
||||
// Additional +ii because we use slightly different syndrome
|
||||
var pow = ERR_NUM + e_e_places[ii] + ii + max - ERR_DEN;
|
||||
|
||||
//ERR[ii] = ERR_NUM == -1 ? 0 : expTbl[(pow & max) + (pow >> w)];
|
||||
parity[npar - 1 - ii] = ERR_NUM == -1 ? (ushort)0 : Galois16.instance.ExpTbl[(pow & max) + (pow >> w)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,6 +97,29 @@ namespace CUETools.TestCodecs
|
||||
CollectionAssert.AreEqual(File.ReadAllBytes("alac.m4a"), File.ReadAllBytes("alacwriter0.m4a"), "alacwriter0.m4a doesn't match.");
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void SeekTest()
|
||||
{
|
||||
var r = new ALACReader("alac.m4a", null);
|
||||
var buff1 = new AudioBuffer(r, 16536);
|
||||
var buff2 = new AudioBuffer(r, 16536);
|
||||
Assert.AreEqual(0, r.Position);
|
||||
r.Read(buff1, 7);
|
||||
Assert.AreEqual(7, r.Position);
|
||||
r.Position = 0;
|
||||
Assert.AreEqual(0, r.Position);
|
||||
r.Read(buff2, 7);
|
||||
Assert.AreEqual(7, r.Position);
|
||||
AudioBufferTest.AreEqual(buff1, buff2);
|
||||
r.Read(buff1, 7);
|
||||
Assert.AreEqual(7 + 7, r.Position);
|
||||
r.Position = 7;
|
||||
Assert.AreEqual(7, r.Position);
|
||||
r.Read(buff2, 7);
|
||||
Assert.AreEqual(7 + 7, r.Position);
|
||||
AudioBufferTest.AreEqual(buff1, buff2);
|
||||
r.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -93,7 +93,9 @@ namespace CUETools.TestParity
|
||||
public void CDRepairEncodeWriteTest()
|
||||
{
|
||||
Assert.AreEqual<string>("jvR9QJ1cSWpqbyP0I0tBrBkQRjCDTDDQkttZGj14ROvsXyg+AnnxVKxL7gwLZbrQmTw5ZPps1Q3744g94qaOOQ==",
|
||||
Convert.ToBase64String(encode.Parity, 0, 64));
|
||||
Convert.ToBase64String(encode.AR.GetParity(8), 0, 64));
|
||||
//Assert.AreEqual<string>("gwln1GxlYWH/Jn74PreMLv4aFF2glkScSWVFlxMBx94v5D3/3wPx+2guRLquED0s9tOFikPLiSnAv0Xq8aIQ6Q==",
|
||||
// Convert.ToBase64String(encode.AR.GetParity(16), 0, 64));
|
||||
Assert.AreEqual<uint>(377539636, encode.CRC);
|
||||
}
|
||||
|
||||
@@ -262,6 +264,7 @@ namespace CUETools.TestParity
|
||||
///A test for CRC parralelism
|
||||
///</summary>
|
||||
[TestMethod()]
|
||||
//[Ignore]
|
||||
public void CDRepairSplitTest()
|
||||
{
|
||||
var seed = 723722;
|
||||
@@ -272,7 +275,6 @@ namespace CUETools.TestParity
|
||||
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);
|
||||
ar1.AR.Combine(ar2.AR, split, (int)ar0.FinalSampleCount);
|
||||
var offsets = new int[] { 0, -1, 1, -2, 2, -3, 3, -4, 4, -11, 11, -256, 256, -588, 588, 1 - 588 * 5, 588 * 5 - 1 };
|
||||
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);
|
||||
@@ -300,30 +302,16 @@ namespace CUETools.TestParity
|
||||
public unsafe void CDRepairSyndrome2ParitySpeedTest()
|
||||
{
|
||||
byte[] parityCopy = new byte[encode.Parity.Length];
|
||||
var syndrome = encode.Syndrome;
|
||||
for (int t = 0; t < 100; t++)
|
||||
{
|
||||
fixed (byte* p = encode.Parity, p1 = parityCopy)
|
||||
fixed (ushort* syn = encode.Syndrome)
|
||||
{
|
||||
ushort* p2 = (ushort*)p1;
|
||||
for (int i = 0; i < stride; i++)
|
||||
Galois16.instance.Syndrome2Parity(syn + i * npar, p2 + i * npar, npar);
|
||||
}
|
||||
}
|
||||
ParityToSyndrome.Syndrome2Parity(syndrome, parityCopy);
|
||||
CollectionAssert.AreEqual(encode.Parity, parityCopy);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public unsafe void CDRepairEncodeSynParTest()
|
||||
{
|
||||
byte[] parityCopy = new byte[encode.Parity.Length];
|
||||
fixed(byte * p = encode.Parity, p1 = parityCopy)
|
||||
fixed (ushort *syn = encode.Syndrome)
|
||||
{
|
||||
ushort* p2 = (ushort*)p1;
|
||||
for (int i = 0; i < stride; i++)
|
||||
Galois16.instance.Syndrome2Parity(syn + i * npar, p2 + i * npar, npar);
|
||||
}
|
||||
var parityCopy = ParityToSyndrome.Syndrome2Parity(encode.Syndrome);
|
||||
CollectionAssert.AreEqual(encode.Parity, parityCopy);
|
||||
}
|
||||
|
||||
@@ -350,7 +338,7 @@ namespace CUETools.TestParity
|
||||
///Verifying rip that has errors
|
||||
///</summary>
|
||||
[TestMethod()]
|
||||
//[Ignore]
|
||||
[Ignore]
|
||||
public void CDRepairVerifyParitySpeedTest()
|
||||
{
|
||||
var generator1 = new TestImageGenerator("0 98011", seed, 32 * 588, 0);
|
||||
|
||||
Reference in New Issue
Block a user