mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
seektable support, optimizations
This commit is contained in:
@@ -38,6 +38,17 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
writebits(bits, (uint)val);
|
writebits(bits, (uint)val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writebits64(int bits, ulong val)
|
||||||
|
{
|
||||||
|
if (bits > 32)
|
||||||
|
{
|
||||||
|
writebits(bits - 32, (uint)(val >> 32));
|
||||||
|
val &= 0xffffffffL;
|
||||||
|
bits = 32;
|
||||||
|
}
|
||||||
|
writebits(bits, (uint)val);
|
||||||
|
}
|
||||||
|
|
||||||
public void writebits(int bits, uint val)
|
public void writebits(int bits, uint val)
|
||||||
{
|
{
|
||||||
//assert(bits == 32 || val < (1U << bits));
|
//assert(bits == 32 || val < (1U << bits));
|
||||||
@@ -100,12 +111,26 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void write_unary_signed(int val)
|
||||||
|
{
|
||||||
|
// convert signed to unsigned
|
||||||
|
int v = -2 * val - 1;
|
||||||
|
v ^= (v >> 31);
|
||||||
|
|
||||||
|
// write quotient in unary
|
||||||
|
int q = v + 1;
|
||||||
|
while (q > 31)
|
||||||
|
{
|
||||||
|
writebits(31, 0);
|
||||||
|
q -= 31;
|
||||||
|
}
|
||||||
|
writebits(q, 1);
|
||||||
|
}
|
||||||
|
|
||||||
public void write_rice_signed(int k, int val)
|
public void write_rice_signed(int k, int val)
|
||||||
{
|
{
|
||||||
int v, q;
|
int v, q;
|
||||||
|
|
||||||
if (k < 0) return;
|
|
||||||
|
|
||||||
// convert signed to unsigned
|
// convert signed to unsigned
|
||||||
v = -2 * val - 1;
|
v = -2 * val - 1;
|
||||||
v ^= (v >> 31);
|
v ^= (v >> 31);
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
public const int MAX_PARTITION_ORDER = 8;
|
public const int MAX_PARTITION_ORDER = 8;
|
||||||
public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER;
|
public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER;
|
||||||
|
|
||||||
|
public const int FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
|
||||||
|
public const int FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
|
||||||
|
public const int FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
|
||||||
|
|
||||||
public static readonly int[] flac_samplerates = new int[16] {
|
public static readonly int[] flac_samplerates = new int[16] {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
|
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
|
||||||
@@ -39,59 +43,22 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
public static PredictionType LookupPredictionType(string name)
|
public static PredictionType LookupPredictionType(string name)
|
||||||
{
|
{
|
||||||
switch (name)
|
return (PredictionType)(Enum.Parse(typeof(PredictionType), name, true));
|
||||||
{
|
|
||||||
case "fixed": return PredictionType.Fixed;
|
|
||||||
case "levinson": return PredictionType.Levinson;
|
|
||||||
case "search" : return PredictionType.Search;
|
|
||||||
}
|
|
||||||
return (PredictionType)Int32.Parse(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StereoMethod LookupStereoMethod(string name)
|
public static StereoMethod LookupStereoMethod(string name)
|
||||||
{
|
{
|
||||||
switch (name)
|
return (StereoMethod)(Enum.Parse(typeof(StereoMethod), name, true));
|
||||||
{
|
|
||||||
case "independent": return StereoMethod.Independent;
|
|
||||||
case "estimate": return StereoMethod.Estimate;
|
|
||||||
case "estimate2": return StereoMethod.Estimate2;
|
|
||||||
case "estimate3": return StereoMethod.Estimate3;
|
|
||||||
case "estimate4": return StereoMethod.Estimate4;
|
|
||||||
case "estimate5": return StereoMethod.Estimate5;
|
|
||||||
case "search": return StereoMethod.Search;
|
|
||||||
}
|
|
||||||
return (StereoMethod)Int32.Parse(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OrderMethod LookupOrderMethod(string name)
|
public static OrderMethod LookupOrderMethod(string name)
|
||||||
{
|
{
|
||||||
switch (name)
|
return (OrderMethod)(Enum.Parse(typeof(OrderMethod), name, true));
|
||||||
{
|
|
||||||
case "estimate": return OrderMethod.Estimate;
|
|
||||||
case "logfast": return OrderMethod.LogFast;
|
|
||||||
case "logsearch": return OrderMethod.LogSearch;
|
|
||||||
case "estsearch": return OrderMethod.EstSearch;
|
|
||||||
case "search": return OrderMethod.Search;
|
|
||||||
}
|
|
||||||
return (OrderMethod)Int32.Parse(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WindowFunction LookupWindowFunction(string name)
|
public static WindowFunction LookupWindowFunction(string name)
|
||||||
{
|
{
|
||||||
string[] parts = name.Split(',');
|
return (WindowFunction)(Enum.Parse(typeof(WindowFunction), name, true));
|
||||||
WindowFunction res = (WindowFunction)0;
|
|
||||||
foreach (string part in parts)
|
|
||||||
{
|
|
||||||
switch (part)
|
|
||||||
{
|
|
||||||
case "welch": res |= WindowFunction.Welch; break;
|
|
||||||
case "tukey": res |= WindowFunction.Tukey; break;
|
|
||||||
case "hann": res |= WindowFunction.Hann; break;
|
|
||||||
case "flattop": res |= WindowFunction.Flattop; break;
|
|
||||||
default: res |= (WindowFunction)Int32.Parse(name); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe public static bool memcmp(int* res, int* smp, int n)
|
unsafe public static bool memcmp(int* res, int* smp, int n)
|
||||||
@@ -124,6 +91,14 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
*(res++) = *(src2++);
|
*(res++) = *(src2++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unsafe public static void deinterlace(int* dst1, int* dst2, int* src, int n)
|
||||||
|
{
|
||||||
|
for (int i = n; i > 0; i--)
|
||||||
|
{
|
||||||
|
*(dst1++) = *(src++);
|
||||||
|
*(dst2++) = *(src++);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe struct RiceContext
|
unsafe struct RiceContext
|
||||||
@@ -137,20 +112,28 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
public SubframeType type;
|
public SubframeType type;
|
||||||
public int order;
|
public int order;
|
||||||
public uint obits;
|
|
||||||
public uint wbits;
|
|
||||||
public int cbits;
|
|
||||||
public int shift;
|
|
||||||
public fixed int coefs[lpc.MAX_LPC_ORDER];
|
|
||||||
public int* samples;
|
|
||||||
public int* residual;
|
public int* residual;
|
||||||
public RiceContext rc;
|
public RiceContext rc;
|
||||||
public uint size;
|
public uint size;
|
||||||
public fixed uint done_lpcs[lpc.MAX_LPC_WINDOWS];
|
|
||||||
public uint done_fixed;
|
public int cbits;
|
||||||
|
public int shift;
|
||||||
|
public fixed int coefs[lpc.MAX_LPC_ORDER];
|
||||||
public int window;
|
public int window;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsafe struct FlacSubframeInfo
|
||||||
|
{
|
||||||
|
public FlacSubframe best;
|
||||||
|
public uint obits;
|
||||||
|
public uint wbits;
|
||||||
|
public int* samples;
|
||||||
|
public fixed uint done_lpcs[lpc.MAX_LPC_WINDOWS * 2];
|
||||||
|
public uint done_fixed;
|
||||||
|
public fixed double lpcs_reff[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_WINDOWS];
|
||||||
|
public fixed int lpcs_order[lpc.MAX_LPC_WINDOWS];
|
||||||
|
};
|
||||||
|
|
||||||
unsafe struct FlacFrame
|
unsafe struct FlacFrame
|
||||||
{
|
{
|
||||||
public int blocksize;
|
public int blocksize;
|
||||||
@@ -158,7 +141,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
public ChannelMode ch_mode;
|
public ChannelMode ch_mode;
|
||||||
public int ch_order0, ch_order1;
|
public int ch_order0, ch_order1;
|
||||||
public byte crc8;
|
public byte crc8;
|
||||||
public FlacSubframe* subframes;
|
public FlacSubframeInfo* subframes;
|
||||||
public uint frame_count;
|
public uint frame_count;
|
||||||
public FlacSubframe current;
|
public FlacSubframe current;
|
||||||
}
|
}
|
||||||
@@ -170,6 +153,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
LogFast = 2,
|
LogFast = 2,
|
||||||
LogSearch = 3,
|
LogSearch = 3,
|
||||||
EstSearch = 4,
|
EstSearch = 4,
|
||||||
|
Estimate8 = 6,
|
||||||
Search = 5
|
Search = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,11 +188,8 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
Independent = 0,
|
Independent = 0,
|
||||||
Estimate = 1,
|
Estimate = 1,
|
||||||
Estimate2 = 2,
|
Evaluate = 2,
|
||||||
Estimate3 = 3,
|
Search = 3
|
||||||
Estimate4 = 4,
|
|
||||||
Estimate5 = 5,
|
|
||||||
Search = 9
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SubframeType
|
public enum SubframeType
|
||||||
@@ -233,7 +214,8 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
Welch = 1,
|
Welch = 1,
|
||||||
Tukey = 2,
|
Tukey = 2,
|
||||||
Hann = 4,
|
Hann = 4,
|
||||||
Flattop = 8
|
Flattop = 8,
|
||||||
|
TukeyFlattop = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct SeekPoint
|
public struct SeekPoint
|
||||||
|
|||||||
@@ -118,13 +118,28 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
if (value > _sampleCount)
|
if (value > _sampleCount)
|
||||||
throw new Exception("seeking past end of stream");
|
throw new Exception("seeking past end of stream");
|
||||||
if (value < Position)
|
if (value < Position || value > _sampleOffset)
|
||||||
throw new Exception("backwards seeking not yet supported");
|
|
||||||
if (seek_table != null)
|
|
||||||
{
|
{
|
||||||
|
if (seek_table != null && _IO.CanSeek)
|
||||||
|
{
|
||||||
|
int best_st = -1;
|
||||||
|
for (int st = 0; st < seek_table.Length; st++)
|
||||||
|
{
|
||||||
|
if (seek_table[st].number <= value &&
|
||||||
|
(best_st == -1 || seek_table[st].number > seek_table[best_st].number))
|
||||||
|
best_st = st;
|
||||||
|
}
|
||||||
|
if (best_st != -1)
|
||||||
|
{
|
||||||
|
_framesBufferLength = 0;
|
||||||
|
_samplesInBuffer = 0;
|
||||||
|
_IO.Position = (long)seek_table[best_st].offset + first_frame_offset;
|
||||||
|
_sampleOffset = seek_table[best_st].number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value < Position)
|
||||||
|
throw new Exception("cannot seek backwards without seek table");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (value > _sampleOffset)
|
while (value > _sampleOffset)
|
||||||
{
|
{
|
||||||
_samplesInBuffer = 0;
|
_samplesInBuffer = 0;
|
||||||
@@ -313,14 +328,14 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
unsafe void decode_subframe_constant(BitReader bitreader, FlacFrame* frame, int ch)
|
unsafe void decode_subframe_constant(BitReader bitreader, FlacFrame* frame, int ch)
|
||||||
{
|
{
|
||||||
int obits = (int)frame->subframes[ch].obits;
|
int obits = (int)frame->subframes[ch].obits;
|
||||||
frame->subframes[ch].residual[0] = bitreader.readbits_signed(obits);
|
frame->subframes[ch].best.residual[0] = bitreader.readbits_signed(obits);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void decode_subframe_verbatim(BitReader bitreader, FlacFrame* frame, int ch)
|
unsafe void decode_subframe_verbatim(BitReader bitreader, FlacFrame* frame, int ch)
|
||||||
{
|
{
|
||||||
int obits = (int)frame->subframes[ch].obits;
|
int obits = (int)frame->subframes[ch].obits;
|
||||||
for (int i = 0; i < frame->blocksize; i++)
|
for (int i = 0; i < frame->blocksize; i++)
|
||||||
frame->subframes[ch].residual[i] = bitreader.readbits_signed(obits);
|
frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void decode_residual(BitReader bitreader, FlacFrame* frame, int ch)
|
unsafe void decode_residual(BitReader bitreader, FlacFrame* frame, int ch)
|
||||||
@@ -330,25 +345,25 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
if (coding_method != 0 && coding_method != 1) // if 1, then parameter length == 5 bits instead of 4
|
if (coding_method != 0 && coding_method != 1) // if 1, then parameter length == 5 bits instead of 4
|
||||||
throw new Exception("unsupported residual coding");
|
throw new Exception("unsupported residual coding");
|
||||||
// partition order
|
// partition order
|
||||||
frame->subframes[ch].rc.porder = (int)bitreader.readbits(4);
|
frame->subframes[ch].best.rc.porder = (int)bitreader.readbits(4);
|
||||||
if (frame->subframes[ch].rc.porder > 8)
|
if (frame->subframes[ch].best.rc.porder > 8)
|
||||||
throw new Exception("invalid partition order");
|
throw new Exception("invalid partition order");
|
||||||
int psize = frame->blocksize >> frame->subframes[ch].rc.porder;
|
int psize = frame->blocksize >> frame->subframes[ch].best.rc.porder;
|
||||||
int res_cnt = psize - frame->subframes[ch].order;
|
int res_cnt = psize - frame->subframes[ch].best.order;
|
||||||
|
|
||||||
int rice_len = 4 + (int)coding_method;
|
int rice_len = 4 + (int)coding_method;
|
||||||
// residual
|
// residual
|
||||||
int j = frame->subframes[ch].order;
|
int j = frame->subframes[ch].best.order;
|
||||||
int* r = frame->subframes[ch].residual + j;
|
int* r = frame->subframes[ch].best.residual + j;
|
||||||
for (int p = 0; p < (1 << frame->subframes[ch].rc.porder); p++)
|
for (int p = 0; p < (1 << frame->subframes[ch].best.rc.porder); p++)
|
||||||
{
|
{
|
||||||
if (p == 1) res_cnt = psize;
|
if (p == 1) res_cnt = psize;
|
||||||
int n = Math.Min(res_cnt, frame->blocksize - j);
|
int n = Math.Min(res_cnt, frame->blocksize - j);
|
||||||
|
|
||||||
int k = frame->subframes[ch].rc.rparams[p] = (int)bitreader.readbits(rice_len);
|
int k = frame->subframes[ch].best.rc.rparams[p] = (int)bitreader.readbits(rice_len);
|
||||||
if (k == (1 << rice_len) - 1)
|
if (k == (1 << rice_len) - 1)
|
||||||
{
|
{
|
||||||
k = frame->subframes[ch].rc.esc_bps[p] = (int)bitreader.readbits(5);
|
k = frame->subframes[ch].best.rc.esc_bps[p] = (int)bitreader.readbits(5);
|
||||||
for (int i = n; i > 0; i--)
|
for (int i = n; i > 0; i--)
|
||||||
*(r++) = bitreader.readbits_signed((int)k);
|
*(r++) = bitreader.readbits_signed((int)k);
|
||||||
}
|
}
|
||||||
@@ -365,8 +380,8 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
// warm-up samples
|
// warm-up samples
|
||||||
int obits = (int)frame->subframes[ch].obits;
|
int obits = (int)frame->subframes[ch].obits;
|
||||||
for (int i = 0; i < frame->subframes[ch].order; i++)
|
for (int i = 0; i < frame->subframes[ch].best.order; i++)
|
||||||
frame->subframes[ch].residual[i] = bitreader.readbits_signed(obits);
|
frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
||||||
|
|
||||||
// residual
|
// residual
|
||||||
decode_residual(bitreader, frame, ch);
|
decode_residual(bitreader, frame, ch);
|
||||||
@@ -376,14 +391,14 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
// warm-up samples
|
// warm-up samples
|
||||||
int obits = (int)frame->subframes[ch].obits;
|
int obits = (int)frame->subframes[ch].obits;
|
||||||
for (int i = 0; i < frame->subframes[ch].order; i++)
|
for (int i = 0; i < frame->subframes[ch].best.order; i++)
|
||||||
frame->subframes[ch].residual[i] = bitreader.readbits_signed(obits);
|
frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
||||||
|
|
||||||
// LPC coefficients
|
// LPC coefficients
|
||||||
frame->subframes[ch].cbits = (int)bitreader.readbits(4) + 1; // lpc_precision
|
frame->subframes[ch].best.cbits = (int)bitreader.readbits(4) + 1; // lpc_precision
|
||||||
frame->subframes[ch].shift = bitreader.readbits_signed(5);
|
frame->subframes[ch].best.shift = bitreader.readbits_signed(5);
|
||||||
for (int i = 0; i < frame->subframes[ch].order; i++)
|
for (int i = 0; i < frame->subframes[ch].best.order; i++)
|
||||||
frame->subframes[ch].coefs[i] = bitreader.readbits_signed(frame->subframes[ch].cbits);
|
frame->subframes[ch].best.coefs[i] = bitreader.readbits_signed(frame->subframes[ch].best.cbits);
|
||||||
|
|
||||||
// residual
|
// residual
|
||||||
decode_residual(bitreader, frame, ch);
|
decode_residual(bitreader, frame, ch);
|
||||||
@@ -411,25 +426,25 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
case ChannelMode.RightSide: frame->subframes[ch].obits += 1 - (uint)ch; break;
|
case ChannelMode.RightSide: frame->subframes[ch].obits += 1 - (uint)ch; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->subframes[ch].type = (SubframeType)type_code;
|
frame->subframes[ch].best.type = (SubframeType)type_code;
|
||||||
frame->subframes[ch].order = 0;
|
frame->subframes[ch].best.order = 0;
|
||||||
|
|
||||||
if ((type_code & (uint)SubframeType.LPC) != 0)
|
if ((type_code & (uint)SubframeType.LPC) != 0)
|
||||||
{
|
{
|
||||||
frame->subframes[ch].order = (type_code - (int)SubframeType.LPC) + 1;
|
frame->subframes[ch].best.order = (type_code - (int)SubframeType.LPC) + 1;
|
||||||
frame->subframes[ch].type = SubframeType.LPC;
|
frame->subframes[ch].best.type = SubframeType.LPC;
|
||||||
}
|
}
|
||||||
else if ((type_code & (uint)SubframeType.Fixed) != 0)
|
else if ((type_code & (uint)SubframeType.Fixed) != 0)
|
||||||
{
|
{
|
||||||
frame->subframes[ch].order = (type_code - (int)SubframeType.Fixed);
|
frame->subframes[ch].best.order = (type_code - (int)SubframeType.Fixed);
|
||||||
frame->subframes[ch].type = SubframeType.Fixed;
|
frame->subframes[ch].best.type = SubframeType.Fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->subframes[ch].residual = r + ch * Flake.MAX_BLOCKSIZE;
|
frame->subframes[ch].best.residual = r + ch * Flake.MAX_BLOCKSIZE;
|
||||||
frame->subframes[ch].samples = s + ch * Flake.MAX_BLOCKSIZE;
|
frame->subframes[ch].samples = s + ch * Flake.MAX_BLOCKSIZE;
|
||||||
|
|
||||||
// subframe
|
// subframe
|
||||||
switch (frame->subframes[ch].type)
|
switch (frame->subframes[ch].best.type)
|
||||||
{
|
{
|
||||||
case SubframeType.Constant:
|
case SubframeType.Constant:
|
||||||
decode_subframe_constant(bitreader, frame, ch);
|
decode_subframe_constant(bitreader, frame, ch);
|
||||||
@@ -451,14 +466,14 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
unsafe void restore_samples_fixed(FlacFrame* frame, int ch)
|
unsafe void restore_samples_fixed(FlacFrame* frame, int ch)
|
||||||
{
|
{
|
||||||
FlacSubframe* sub = frame->subframes + ch;
|
FlacSubframeInfo* sub = frame->subframes + ch;
|
||||||
|
|
||||||
Flake.memcpy(sub->samples, sub->residual, sub->order);
|
Flake.memcpy(sub->samples, sub->best.residual, sub->best.order);
|
||||||
int* data = sub->samples + sub->order;
|
int* data = sub->samples + sub->best.order;
|
||||||
int* residual = sub->residual + sub->order;
|
int* residual = sub->best.residual + sub->best.order;
|
||||||
int data_len = frame->blocksize - sub->order;
|
int data_len = frame->blocksize - sub->best.order;
|
||||||
int s0, s1, s2;
|
int s0, s1, s2;
|
||||||
switch (sub->order)
|
switch (sub->best.order)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
Flake.memcpy(data, residual, data_len);
|
Flake.memcpy(data, residual, data_len);
|
||||||
@@ -497,27 +512,27 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
unsafe void restore_samples_lpc(FlacFrame* frame, int ch)
|
unsafe void restore_samples_lpc(FlacFrame* frame, int ch)
|
||||||
{
|
{
|
||||||
FlacSubframe* sub = frame->subframes + ch;
|
FlacSubframeInfo* sub = frame->subframes + ch;
|
||||||
ulong csum = 0;
|
ulong csum = 0;
|
||||||
for (int i = sub->order; i > 0; i--)
|
for (int i = sub->best.order; i > 0; i--)
|
||||||
csum += (ulong)Math.Abs(sub->coefs[i - 1]);
|
csum += (ulong)Math.Abs(sub->best.coefs[i - 1]);
|
||||||
if ((csum << (int)sub->obits) >= 1UL << 32)
|
if ((csum << (int)sub->obits) >= 1UL << 32)
|
||||||
lpc.decode_residual_long(sub->residual, sub->samples, frame->blocksize, sub->order, sub->coefs, sub->shift);
|
lpc.decode_residual_long(sub->best.residual, sub->samples, frame->blocksize, sub->best.order, sub->best.coefs, sub->best.shift);
|
||||||
else
|
else
|
||||||
lpc.decode_residual(sub->residual, sub->samples, frame->blocksize, sub->order, sub->coefs, sub->shift);
|
lpc.decode_residual(sub->best.residual, sub->samples, frame->blocksize, sub->best.order, sub->best.coefs, sub->best.shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void restore_samples(FlacFrame* frame)
|
unsafe void restore_samples(FlacFrame* frame)
|
||||||
{
|
{
|
||||||
for (int ch = 0; ch < channels; ch++)
|
for (int ch = 0; ch < channels; ch++)
|
||||||
{
|
{
|
||||||
switch (frame->subframes[ch].type)
|
switch (frame->subframes[ch].best.type)
|
||||||
{
|
{
|
||||||
case SubframeType.Constant:
|
case SubframeType.Constant:
|
||||||
Flake.memset(frame->subframes[ch].samples, frame->subframes[ch].residual[0], frame->blocksize);
|
Flake.memset(frame->subframes[ch].samples, frame->subframes[ch].best.residual[0], frame->blocksize);
|
||||||
break;
|
break;
|
||||||
case SubframeType.Verbatim:
|
case SubframeType.Verbatim:
|
||||||
Flake.memcpy(frame->subframes[ch].samples, frame->subframes[ch].residual, frame->blocksize);
|
Flake.memcpy(frame->subframes[ch].samples, frame->subframes[ch].best.residual, frame->blocksize);
|
||||||
break;
|
break;
|
||||||
case SubframeType.Fixed:
|
case SubframeType.Fixed:
|
||||||
restore_samples_fixed(frame, ch);
|
restore_samples_fixed(frame, ch);
|
||||||
@@ -574,12 +589,12 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
BitReader bitreader = new BitReader(buf, pos, len);
|
BitReader bitreader = new BitReader(buf, pos, len);
|
||||||
FlacFrame frame;
|
FlacFrame frame;
|
||||||
FlacSubframe* subframes = stackalloc FlacSubframe[channels];
|
FlacSubframeInfo* subframes = stackalloc FlacSubframeInfo[channels];
|
||||||
frame.subframes = subframes;
|
frame.subframes = subframes;
|
||||||
decode_frame_header(bitreader, &frame);
|
decode_frame_header(bitreader, &frame);
|
||||||
decode_subframes(bitreader, &frame);
|
decode_subframes(bitreader, &frame);
|
||||||
bitreader.flush();
|
bitreader.flush();
|
||||||
ushort crc = crc16.ComputeChecksum(bitreader.Buffer, pos, bitreader.Position - pos);
|
ushort crc = crc16.ComputeChecksum(bitreader.Buffer + pos, bitreader.Position - pos);
|
||||||
if (crc != bitreader.readbits(16))
|
if (crc != bitreader.readbits(16))
|
||||||
throw new Exception("frame crc mismatch");
|
throw new Exception("frame crc mismatch");
|
||||||
restore_samples(&frame);
|
restore_samples(&frame);
|
||||||
@@ -691,17 +706,13 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
else if (type == MetadataType.FLAC__METADATA_TYPE_SEEKTABLE)
|
else if (type == MetadataType.FLAC__METADATA_TYPE_SEEKTABLE)
|
||||||
{
|
{
|
||||||
const int FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
|
|
||||||
const int FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
|
|
||||||
const int FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
|
|
||||||
|
|
||||||
int num_entries = len / 18;
|
int num_entries = len / 18;
|
||||||
seek_table = new SeekPoint[num_entries];
|
seek_table = new SeekPoint[num_entries];
|
||||||
for (int e = 0; e < num_entries; e++)
|
for (int e = 0; e < num_entries; e++)
|
||||||
{
|
{
|
||||||
seek_table[e].number = bitreader.readbits64(FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN);
|
seek_table[e].number = bitreader.readbits64(Flake.FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN);
|
||||||
seek_table[e].offset = bitreader.readbits64(FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN);
|
seek_table[e].offset = bitreader.readbits64(Flake.FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN);
|
||||||
seek_table[e].framesize = bitreader.readbits24(FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN);
|
seek_table[e].framesize = bitreader.readbits24(Flake.FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_framesBufferLength < 4 + len)
|
if (_framesBufferLength < 4 + len)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
* Calculates autocorrelation data from audio samples
|
* Calculates autocorrelation data from audio samples
|
||||||
* A Welch window function is applied before calculation.
|
* A Welch window function is applied before calculation.
|
||||||
*/
|
*/
|
||||||
static unsafe void
|
static public unsafe void
|
||||||
compute_autocorr(/*const*/ int* data, uint len, uint lag, double* autoc, double* window)
|
compute_autocorr(/*const*/ int* data, uint len, uint lag, double* autoc, double* window)
|
||||||
{
|
{
|
||||||
double* data1 = stackalloc double[(int)len + 16];
|
double* data1 = stackalloc double[(int)len + 16];
|
||||||
@@ -83,7 +83,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
* Levinson-Durbin recursion.
|
* Levinson-Durbin recursion.
|
||||||
* Produces LPC coefficients from autocorrelation data.
|
* Produces LPC coefficients from autocorrelation data.
|
||||||
*/
|
*/
|
||||||
static unsafe void
|
public static unsafe void
|
||||||
compute_lpc_coefs(/*const*/ double* autoc, uint max_order, double* reff,
|
compute_lpc_coefs(/*const*/ double* autoc, uint max_order, double* reff,
|
||||||
double* lpc/*[][MAX_LPC_ORDER]*/)
|
double* lpc/*[][MAX_LPC_ORDER]*/)
|
||||||
{
|
{
|
||||||
@@ -139,19 +139,12 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static unsafe void
|
||||||
* Compute LPC coefs for Flake.OrderMethod._EST
|
compute_schur_reflection(/*const*/ double* autoc, uint max_order,
|
||||||
* Faster LPC coeff computation by first calculating the reflection coefficients
|
double* reff/*[][MAX_LPC_ORDER]*/)
|
||||||
* using Schur recursion. That allows for estimating the optimal order before
|
|
||||||
* running Levinson recursion.
|
|
||||||
*/
|
|
||||||
static unsafe uint
|
|
||||||
compute_lpc_coefs_est(/*const*/ double* autoc, uint max_order,
|
|
||||||
double* lpc/*[][MAX_LPC_ORDER]*/)
|
|
||||||
{
|
{
|
||||||
double* gen0 = stackalloc double[MAX_LPC_ORDER];
|
double* gen0 = stackalloc double[MAX_LPC_ORDER];
|
||||||
double* gen1 = stackalloc double[MAX_LPC_ORDER];
|
double* gen1 = stackalloc double[MAX_LPC_ORDER];
|
||||||
double* reff = stackalloc double[MAX_LPC_ORDER];
|
|
||||||
|
|
||||||
// Schur recursion
|
// Schur recursion
|
||||||
for (uint i = 0; i < max_order; i++)
|
for (uint i = 0; i < max_order; i++)
|
||||||
@@ -170,6 +163,22 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
reff[i] = -gen1[0] / error;
|
reff[i] = -gen1[0] / error;
|
||||||
error += gen1[0] * reff[i];
|
error += gen1[0] * reff[i];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute LPC coefs for Flake.OrderMethod._EST
|
||||||
|
* Faster LPC coeff computation by first calculating the reflection coefficients
|
||||||
|
* using Schur recursion. That allows for estimating the optimal order before
|
||||||
|
* running Levinson recursion.
|
||||||
|
*/
|
||||||
|
public static unsafe uint
|
||||||
|
compute_lpc_coefs_est(/*const*/ double* autoc, uint max_order,
|
||||||
|
double* lpc/*[][MAX_LPC_ORDER]*/)
|
||||||
|
{
|
||||||
|
double* reff = stackalloc double[MAX_LPC_ORDER];
|
||||||
|
|
||||||
|
// Schur recursion
|
||||||
|
compute_schur_reflection(autoc, max_order, reff);
|
||||||
|
|
||||||
// Estimate optimal order using reflection coefficients
|
// Estimate optimal order using reflection coefficients
|
||||||
uint order_est = 1;
|
uint order_est = 1;
|
||||||
@@ -396,6 +405,132 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static unsafe void
|
||||||
|
encode_residual_long(int* res, int* smp, int n, int order,
|
||||||
|
int* coefs, int shift)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < order; i++)
|
||||||
|
res[i] = smp[i];
|
||||||
|
|
||||||
|
int* s = smp;
|
||||||
|
int* r = res + order;
|
||||||
|
int c0 = coefs[0];
|
||||||
|
int c1 = coefs[1];
|
||||||
|
switch (order)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *(s--) - (int)(pred >> shift);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = coefs[2] * (long)*(s++);
|
||||||
|
pred += c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
s -= 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = coefs[3] * (long)*(s++);
|
||||||
|
pred += coefs[2] * (long)*(s++);
|
||||||
|
pred += c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
s -= 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = coefs[4] * (long)*(s++);
|
||||||
|
pred += coefs[3] * (long)*(s++);
|
||||||
|
pred += coefs[2] * (long)*(s++);
|
||||||
|
pred += c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
s -= 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = coefs[5] * (long)*(s++);
|
||||||
|
pred += coefs[4] * (long)*(s++);
|
||||||
|
pred += coefs[3] * (long)*(s++);
|
||||||
|
pred += coefs[2] * (long)*(s++);
|
||||||
|
pred += c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
s -= 5;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = coefs[6] * (long)*(s++);
|
||||||
|
pred += coefs[5] * (long)*(s++);
|
||||||
|
pred += coefs[4] * (long)*(s++);
|
||||||
|
pred += coefs[3] * (long)*(s++);
|
||||||
|
pred += coefs[2] * (long)*(s++);
|
||||||
|
pred += c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
s -= 6;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
for (int i = n - order; i > 0; i--)
|
||||||
|
{
|
||||||
|
long pred = coefs[7] * (long)*(s++);
|
||||||
|
pred += coefs[6] * (long)*(s++);
|
||||||
|
pred += coefs[5] * (long)*(s++);
|
||||||
|
pred += coefs[4] * (long)*(s++);
|
||||||
|
pred += coefs[3] * (long)*(s++);
|
||||||
|
pred += coefs[2] * (long)*(s++);
|
||||||
|
pred += c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
s -= 7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for (int i = order; i < n; i++)
|
||||||
|
{
|
||||||
|
s = smp + i - order;
|
||||||
|
long pred = 0;
|
||||||
|
int* co = coefs + order - 1;
|
||||||
|
int* c7 = coefs + 7;
|
||||||
|
while (co > c7)
|
||||||
|
pred += *(co--) * (long)*(s++);
|
||||||
|
pred += coefs[7] * (long)*(s++);
|
||||||
|
pred += coefs[6] * (long)*(s++);
|
||||||
|
pred += coefs[5] * (long)*(s++);
|
||||||
|
pred += coefs[4] * (long)*(s++);
|
||||||
|
pred += coefs[3] * (long)*(s++);
|
||||||
|
pred += coefs[2] * (long)*(s++);
|
||||||
|
pred += c1 * (long)*(s++);
|
||||||
|
pred += c0 * (long)*(s++);
|
||||||
|
*(r++) = *s - (int)(pred >> shift);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static unsafe void
|
public static unsafe void
|
||||||
decode_residual(int* res, int* smp, int n, int order,
|
decode_residual(int* res, int* smp, int n, int order,
|
||||||
int* coefs, int shift)
|
int* coefs, int shift)
|
||||||
|
|||||||
Reference in New Issue
Block a user