diff --git a/CUETools.Codecs.FLAKE/BitReader.cs b/CUETools.Codecs.FLAKE/BitReader.cs
index 1aafe87..0a0afff 100644
--- a/CUETools.Codecs.FLAKE/BitReader.cs
+++ b/CUETools.Codecs.FLAKE/BitReader.cs
@@ -32,7 +32,7 @@ namespace CUETools.Codecs.FLAKE
int _bitaccumulator;
uint cache;
- static readonly byte[] byte_to_unary_table = new byte[]
+ public static readonly byte[] byte_to_unary_table = new byte[]
{
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
diff --git a/CUETools.Codecs.FLAKE/BitWriter.cs b/CUETools.Codecs.FLAKE/BitWriter.cs
index 7259f60..10e9c7e 100644
--- a/CUETools.Codecs.FLAKE/BitWriter.cs
+++ b/CUETools.Codecs.FLAKE/BitWriter.cs
@@ -110,6 +110,32 @@ namespace CUETools.Codecs.FLAKE
}
}
+ ///
+ /// Assumes there's enough space, buffer != null and bits is in range 1..31
+ ///
+ ///
+ ///
+ unsafe void writebits_fast(int bits, uint val, ref byte * buf)
+ {
+ if (bits < bit_left)
+ {
+ bit_buf = (bit_buf << bits) | val;
+ bit_left -= bits;
+ }
+ else
+ {
+ uint bb = (bit_buf << bit_left) | (val >> (bits - bit_left));
+ bit_left += (32 - bits);
+
+ *(buf++) = (byte)(bb >> 24);
+ *(buf++) = (byte)(bb >> 16);
+ *(buf++) = (byte)(bb >> 8);
+ *(buf++) = (byte)(bb);
+
+ bit_buf = val;
+ }
+ }
+
public void write_utf8(int val)
{
write_utf8((uint)val);
@@ -150,23 +176,78 @@ namespace CUETools.Codecs.FLAKE
public void write_rice_signed(int k, int val)
{
- int v, q;
-
// convert signed to unsigned
- v = -2 * val - 1;
+ int v = -2 * val - 1;
v ^= (v >> 31);
// write quotient in unary
- q = (v >> k) + 1;
- while (q > 31)
+ int q = (v >> k) + 1;
+ while (q + k > 31)
{
- writebits(31, 0);
- q -= 31;
+ int b = Math.Min(q + k - 31, 31);
+ writebits(b, 0);
+ q -= b;
}
- writebits(q, 1);
- // write write remainder in binary using 'k' bits
- writebits(k, v & ((1 << k) - 1));
+ // write remainder in binary using 'k' bits
+ writebits(k + q, (v & ((1 << k) - 1)) | (1 << k));
+ }
+
+ public unsafe void write_rice_block_signed(int k, int* residual, int count)
+ {
+ fixed (byte* fixbuf = &buffer[buf_ptr])
+ {
+ byte* buf = fixbuf;
+ for (int i = count; i > 0; i--)
+ {
+ int v = -2 * *(residual++) - 1;
+ v ^= (v >> 31);
+
+ // write quotient in unary
+ int q = (v >> k) + 1;
+ int bits = k + q;
+ while (bits > 31)
+ {
+ int b = Math.Min(bits - 31, 31);
+ if (b < bit_left)
+ {
+ bit_buf = (bit_buf << b);
+ bit_left -= b;
+ }
+ else
+ {
+ uint bb = bit_buf << bit_left;
+ bit_buf = 0;
+ bit_left += (32 - b);
+ *(buf++) = (byte)(bb >> 24);
+ *(buf++) = (byte)(bb >> 16);
+ *(buf++) = (byte)(bb >> 8);
+ *(buf++) = (byte)(bb);
+ }
+ bits -= b;
+ }
+
+ // write remainder in binary using 'k' bits
+ //writebits_fast(k + q, (uint)((v & ((1 << k) - 1)) | (1 << k)), ref buf);
+ uint val = (uint)((v & ((1 << k) - 1)) | (1 << k));
+ if (bits < bit_left)
+ {
+ bit_buf = (bit_buf << bits) | val;
+ bit_left -= bits;
+ }
+ else
+ {
+ uint bb = (bit_buf << bit_left) | (val >> (bits - bit_left));
+ bit_buf = val;
+ bit_left += (32 - bits);
+ *(buf++) = (byte)(bb >> 24);
+ *(buf++) = (byte)(bb >> 16);
+ *(buf++) = (byte)(bb >> 8);
+ *(buf++) = (byte)(bb);
+ }
+ }
+ buf_ptr += (int)(buf - fixbuf);
+ }
}
public void flush()
diff --git a/CUETools.Codecs.FLAKE/Flake.cs b/CUETools.Codecs.FLAKE/Flake.cs
index 3db732d..b04a2b9 100644
--- a/CUETools.Codecs.FLAKE/Flake.cs
+++ b/CUETools.Codecs.FLAKE/Flake.cs
@@ -32,6 +32,8 @@ namespace CUETools.Codecs.FLAKE
public const int MAX_PARTITION_ORDER = 8;
public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER;
+ public const uint UINT32_MAX = 0xffffffff;
+
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 */
@@ -50,15 +52,16 @@ namespace CUETools.Codecs.FLAKE
}
public static int log2i(uint v)
{
- int i;
+ //int i;
int n = 0;
if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; }
if (0 != (v & 0xff00)) { v >>= 8; n += 8; }
- for (i = 2; i < 256; i <<= 1)
- {
- if (v >= i) n++;
- else break;
- }
+ if (0 != v) return n + 7 - BitReader.byte_to_unary_table[v];
+ //for (i = 2; i < 256; i <<= 1)
+ //{
+ // if (v >= i) n++;
+ // else break;
+ //}
return n;
}
@@ -122,15 +125,36 @@ namespace CUETools.Codecs.FLAKE
}
}
- unsafe struct RiceContext
+ unsafe class RiceContext
{
- public int porder; /* partition order */
- public fixed int rparams[Flake.MAX_PARTITIONS]; /* Rice parameters */
- public fixed int esc_bps[Flake.MAX_PARTITIONS]; /* bps if using escape code */
+ public RiceContext()
+ {
+ rparams = new int[Flake.MAX_PARTITIONS];
+ esc_bps = new int[Flake.MAX_PARTITIONS];
+ }
+ ///
+ /// partition order
+ ///
+ public int porder;
+
+ ///
+ /// Rice parameters
+ ///
+ public int[] rparams;
+
+ ///
+ /// bps if using escape code
+ ///
+ public int[] esc_bps;
};
- unsafe struct FlacSubframe
+ unsafe class FlacSubframe
{
+ public FlacSubframe()
+ {
+ rc = new RiceContext();
+ coefs = new int[lpc.MAX_LPC_ORDER];
+ }
public SubframeType type;
public int order;
public int* residual;
@@ -139,31 +163,129 @@ namespace CUETools.Codecs.FLAKE
public int cbits;
public int shift;
- public fixed int coefs[lpc.MAX_LPC_ORDER];
+ public int[] coefs;
public int window;
};
- unsafe struct FlacSubframeInfo
+ unsafe class FlacSubframeInfo
{
+ public FlacSubframeInfo()
+ {
+ best = new FlacSubframe();
+ lpc_ctx = new LpcContext[lpc.MAX_LPC_WINDOWS];
+ for (int i = 0; i < lpc.MAX_LPC_WINDOWS; i++)
+ lpc_ctx[i] = new LpcContext();
+ }
+
+ public void Init(int* s, int* r, uint bps, uint w)
+ {
+ if (w > bps)
+ throw new Exception("internal error");
+ samples = s;
+ obits = bps - w;
+ wbits = w;
+ best.residual = r;
+ best.type = SubframeType.Verbatim;
+ best.size = Flake.UINT32_MAX;
+ for (int iWindow = 0; iWindow < lpc.MAX_LPC_WINDOWS; iWindow++)
+ lpc_ctx[iWindow].Reset();
+ done_fixed = 0;
+ }
+
public FlacSubframe best;
public uint obits;
public uint wbits;
public int* samples;
- public fixed uint done_lpcs[lpc.MAX_LPC_WINDOWS * lpc.MAX_LPC_PRECISIONS];
public uint done_fixed;
- public fixed double reflection_coeffs[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_WINDOWS];
- public fixed double autocorr_values[(lpc.MAX_LPC_ORDER + 1) * lpc.MAX_LPC_WINDOWS];
- public fixed int autocorr_orders[lpc.MAX_LPC_WINDOWS];
+ public LpcContext[] lpc_ctx;
};
- unsafe struct FlacFrame
+ unsafe class FlacFrame
{
+ public FlacFrame(int subframes_count)
+ {
+ subframes = new FlacSubframeInfo[subframes_count];
+ for (int ch = 0; ch < subframes_count; ch++)
+ subframes[ch] = new FlacSubframeInfo();
+ current = new FlacSubframe();
+ }
+
+ public void InitSize(int bs, bool vbs)
+ {
+ int i = 15;
+ if (!vbs)
+ {
+ for (i = 0; i < 15; i++)
+ {
+ if (bs == Flake.flac_blocksizes[i])
+ {
+ blocksize = Flake.flac_blocksizes[i];
+ bs_code0 = i;
+ bs_code1 = -1;
+ break;
+ }
+ }
+ }
+ if (i == 15)
+ {
+ blocksize = bs;
+ if (blocksize <= 256)
+ {
+ bs_code0 = 6;
+ bs_code1 = blocksize - 1;
+ }
+ else
+ {
+ bs_code0 = 7;
+ bs_code1 = blocksize - 1;
+ }
+ }
+ }
+
+ public void ChooseBestSubframe(int ch)
+ {
+ if (current.size >= subframes[ch].best.size)
+ return;
+ FlacSubframe tmp = subframes[ch].best;
+ subframes[ch].best = current;
+ current = tmp;
+ }
+
+ public void SwapSubframes(int ch1, int ch2)
+ {
+ FlacSubframeInfo tmp = subframes[ch1];
+ subframes[ch1] = subframes[ch2];
+ subframes[ch2] = tmp;
+ }
+
+ ///
+ /// Swap subframes according to channel mode.
+ /// It is assumed that we have 4 subframes,
+ /// 0 is right, 1 is left, 2 is middle, 3 is difference
+ ///
+ public void ChooseSubframes()
+ {
+ switch (ch_mode)
+ {
+ case ChannelMode.MidSide:
+ SwapSubframes(0, 2);
+ SwapSubframes(1, 3);
+ break;
+ case ChannelMode.RightSide:
+ SwapSubframes(0, 3);
+ break;
+ case ChannelMode.LeftSide:
+ SwapSubframes(1, 3);
+ break;
+ }
+ }
+
public int blocksize;
public int bs_code0, bs_code1;
public ChannelMode ch_mode;
- public int ch_order0, ch_order1;
+ //public int ch_order0, ch_order1;
public byte crc8;
- public FlacSubframeInfo* subframes;
+ public FlacSubframeInfo[] subframes;
public uint frame_count;
public FlacSubframe current;
public double* window_buffer;
@@ -185,11 +307,11 @@ namespace CUETools.Codecs.FLAKE
public enum PredictionType
{
///
- /// verbatim
+ /// Verbatim
///
None = 0,
///
- /// Fixed only
+ /// Fixed prediction only
///
Fixed = 1,
///
@@ -199,11 +321,7 @@ namespace CUETools.Codecs.FLAKE
///
/// Exhaustive search
///
- Search = 3,
- ///
- /// Internal; Use prediction type from previous estimation
- ///
- Estimated = 4
+ Search = 3
}
public enum StereoMethod
@@ -249,45 +367,44 @@ namespace CUETools.Codecs.FLAKE
public enum MetadataType
{
-
///
/// STREAMINFO block
///
- FLAC__METADATA_TYPE_STREAMINFO = 0,
+ StreamInfo = 0,
///
/// PADDING block
///
- FLAC__METADATA_TYPE_PADDING = 1,
+ Padding = 1,
///
/// APPLICATION block
///
- FLAC__METADATA_TYPE_APPLICATION = 2,
+ Application = 2,
///
/// SEEKTABLE block
///
- FLAC__METADATA_TYPE_SEEKTABLE = 3,
+ Seektable = 3,
///
/// VORBISCOMMENT block (a.k.a. FLAC tags)
///
- FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
+ VorbisComment = 4,
///
/// CUESHEET block
///
- FLAC__METADATA_TYPE_CUESHEET = 5,
+ CUESheet = 5,
///
/// PICTURE block
///
- FLAC__METADATA_TYPE_PICTURE = 6,
+ Picture = 6,
///
/// marker to denote beginning of undefined type range; this number will increase as new metadata types are added
///
- FLAC__METADATA_TYPE_UNDEFINED = 7
+ Undefined = 7
};
}
diff --git a/CUETools.Codecs.FLAKE/FlakeReader.cs b/CUETools.Codecs.FLAKE/FlakeReader.cs
index 237914c..2a21ae0 100644
--- a/CUETools.Codecs.FLAKE/FlakeReader.cs
+++ b/CUETools.Codecs.FLAKE/FlakeReader.cs
@@ -39,6 +39,7 @@ namespace CUETools.Codecs.FLAKE
Crc8 crc8;
Crc16 crc16;
+ FlacFrame frame;
int channels;
uint bits_per_sample;
int sample_rate = 44100;
@@ -74,6 +75,8 @@ namespace CUETools.Codecs.FLAKE
_framesBuffer = new byte[0x20000];
decode_metadata();
+ frame = new FlacFrame(channels);
+
//max_frame_size = 16 + ((Flake.MAX_BLOCKSIZE * (int)(bits_per_sample * channels + 1) + 7) >> 3);
if (((int)max_frame_size * (int)bits_per_sample * channels * 2 >> 3) > _framesBuffer.Length)
{
@@ -101,6 +104,7 @@ namespace CUETools.Codecs.FLAKE
bits_per_sample = _bits_per_sample;
samplesBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
residualBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
+ frame = new FlacFrame(channels);
}
public void Close()
@@ -288,37 +292,37 @@ namespace CUETools.Codecs.FLAKE
}
}
- unsafe void decode_frame_header(BitReader bitreader, FlacFrame* frame)
+ unsafe void decode_frame_header(BitReader bitreader, FlacFrame frame)
{
int header_start = bitreader.Position;
if (bitreader.readbits(15) != 0x7FFC)
throw new Exception("invalid frame");
uint vbs = bitreader.readbit();
- frame->bs_code0 = (int) bitreader.readbits(4);
+ frame.bs_code0 = (int) bitreader.readbits(4);
uint sr_code0 = bitreader.readbits(4);
- frame->ch_mode = (ChannelMode)bitreader.readbits(4);
+ frame.ch_mode = (ChannelMode)bitreader.readbits(4);
uint bps_code = bitreader.readbits(3);
if (Flake.flac_bitdepths[bps_code] != bits_per_sample)
throw new Exception("unsupported bps coding");
uint t1 = bitreader.readbit(); // == 0?????
if (t1 != 0)
throw new Exception("unsupported frame coding");
- frame->frame_count = bitreader.read_utf8();
+ frame.frame_count = bitreader.read_utf8();
// custom block size
- if (frame->bs_code0 == 6)
+ if (frame.bs_code0 == 6)
{
- frame->bs_code1 = (int)bitreader.readbits(8);
- frame->blocksize = frame->bs_code1 + 1;
+ frame.bs_code1 = (int)bitreader.readbits(8);
+ frame.blocksize = frame.bs_code1 + 1;
}
- else if (frame->bs_code0 == 7)
+ else if (frame.bs_code0 == 7)
{
- frame->bs_code1 = (int)bitreader.readbits(16);
- frame->blocksize = frame->bs_code1 + 1;
+ frame.bs_code1 = (int)bitreader.readbits(16);
+ frame.blocksize = frame.bs_code1 + 1;
}
else
- frame->blocksize = Flake.flac_blocksizes[frame->bs_code0];
+ frame.blocksize = Flake.flac_blocksizes[frame.bs_code0];
// custom sample rate
if (sr_code0 < 4 || sr_code0 > 11)
@@ -329,62 +333,62 @@ namespace CUETools.Codecs.FLAKE
throw new Exception("invalid sample rate mode");
}
- int frame_channels = (int)frame->ch_mode + 1;
+ int frame_channels = (int)frame.ch_mode + 1;
if (frame_channels > 11)
throw new Exception("invalid channel mode");
if (frame_channels == 2 || frame_channels > 8) // Mid/Left/Right Side Stereo
frame_channels = 2;
else
- frame->ch_mode = ChannelMode.NotStereo;
+ frame.ch_mode = ChannelMode.NotStereo;
if (frame_channels != channels)
throw new Exception("invalid channel mode");
// CRC-8 of frame header
byte crc = crc8.ComputeChecksum(bitreader.Buffer, header_start, bitreader.Position - header_start);
- frame->crc8 = (byte)bitreader.readbits(8);
- if (frame->crc8 != crc)
+ frame.crc8 = (byte)bitreader.readbits(8);
+ if (frame.crc8 != crc)
throw new Exception("header crc mismatch");
}
- 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;
- frame->subframes[ch].best.residual[0] = bitreader.readbits_signed(obits);
+ int obits = (int)frame.subframes[ch].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;
- for (int i = 0; i < frame->blocksize; i++)
- frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
+ int obits = (int)frame.subframes[ch].obits;
+ for (int i = 0; i < frame.blocksize; i++)
+ 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)
{
// rice-encoded block
uint coding_method = bitreader.readbits(2); // ????? == 0
if (coding_method != 0 && coding_method != 1) // if 1, then parameter length == 5 bits instead of 4
throw new Exception("unsupported residual coding");
// partition order
- frame->subframes[ch].best.rc.porder = (int)bitreader.readbits(4);
- if (frame->subframes[ch].best.rc.porder > 8)
+ frame.subframes[ch].best.rc.porder = (int)bitreader.readbits(4);
+ if (frame.subframes[ch].best.rc.porder > 8)
throw new Exception("invalid partition order");
- int psize = frame->blocksize >> frame->subframes[ch].best.rc.porder;
- int res_cnt = psize - frame->subframes[ch].best.order;
+ int psize = frame.blocksize >> frame.subframes[ch].best.rc.porder;
+ int res_cnt = psize - frame.subframes[ch].best.order;
int rice_len = 4 + (int)coding_method;
// residual
- int j = frame->subframes[ch].best.order;
- int* r = frame->subframes[ch].best.residual + j;
- for (int p = 0; p < (1 << frame->subframes[ch].best.rc.porder); p++)
+ int j = frame.subframes[ch].best.order;
+ int* r = frame.subframes[ch].best.residual + j;
+ for (int p = 0; p < (1 << frame.subframes[ch].best.rc.porder); p++)
{
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].best.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)
{
- k = frame->subframes[ch].best.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--)
*(r++) = bitreader.readbits_signed((int)k);
}
@@ -397,37 +401,37 @@ namespace CUETools.Codecs.FLAKE
}
}
- unsafe void decode_subframe_fixed(BitReader bitreader, FlacFrame* frame, int ch)
+ unsafe void decode_subframe_fixed(BitReader bitreader, FlacFrame frame, int ch)
{
// warm-up samples
- int obits = (int)frame->subframes[ch].obits;
- for (int i = 0; i < frame->subframes[ch].best.order; i++)
- frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
+ int obits = (int)frame.subframes[ch].obits;
+ for (int i = 0; i < frame.subframes[ch].best.order; i++)
+ frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
// residual
decode_residual(bitreader, frame, ch);
}
- unsafe void decode_subframe_lpc(BitReader bitreader, FlacFrame* frame, int ch)
+ unsafe void decode_subframe_lpc(BitReader bitreader, FlacFrame frame, int ch)
{
// warm-up samples
- int obits = (int)frame->subframes[ch].obits;
- for (int i = 0; i < frame->subframes[ch].best.order; i++)
- frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
+ int obits = (int)frame.subframes[ch].obits;
+ for (int i = 0; i < frame.subframes[ch].best.order; i++)
+ frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
// LPC coefficients
- frame->subframes[ch].best.cbits = (int)bitreader.readbits(4) + 1; // lpc_precision
- frame->subframes[ch].best.shift = bitreader.readbits_signed(5);
- if (frame->subframes[ch].best.shift < 0)
+ frame.subframes[ch].best.cbits = (int)bitreader.readbits(4) + 1; // lpc_precision
+ frame.subframes[ch].best.shift = bitreader.readbits_signed(5);
+ if (frame.subframes[ch].best.shift < 0)
throw new Exception("negative shift");
- for (int i = 0; i < frame->subframes[ch].best.order; i++)
- frame->subframes[ch].best.coefs[i] = bitreader.readbits_signed(frame->subframes[ch].best.cbits);
+ for (int i = 0; i < frame.subframes[ch].best.order; i++)
+ frame.subframes[ch].best.coefs[i] = bitreader.readbits_signed(frame.subframes[ch].best.cbits);
// residual
decode_residual(bitreader, frame, ch);
}
- unsafe void decode_subframes(BitReader bitreader, FlacFrame* frame)
+ unsafe void decode_subframes(BitReader bitreader, FlacFrame frame)
{
fixed (int *r = residualBuffer, s = samplesBuffer)
for (int ch = 0; ch < channels; ch++)
@@ -437,37 +441,37 @@ namespace CUETools.Codecs.FLAKE
if (t1 != 0)
throw new Exception("unsupported subframe coding");
int type_code = (int)bitreader.readbits(6);
- frame->subframes[ch].wbits = bitreader.readbit();
- if (frame->subframes[ch].wbits != 0)
- frame->subframes[ch].wbits += bitreader.read_unary();
+ frame.subframes[ch].wbits = bitreader.readbit();
+ if (frame.subframes[ch].wbits != 0)
+ frame.subframes[ch].wbits += bitreader.read_unary();
- frame->subframes[ch].obits = bits_per_sample - frame->subframes[ch].wbits;
- switch (frame->ch_mode)
+ frame.subframes[ch].obits = bits_per_sample - frame.subframes[ch].wbits;
+ switch (frame.ch_mode)
{
- case ChannelMode.MidSide: frame->subframes[ch].obits += (uint)ch; break;
- case ChannelMode.LeftSide: frame->subframes[ch].obits += (uint)ch; break;
- case ChannelMode.RightSide: frame->subframes[ch].obits += 1 - (uint)ch; break;
+ case ChannelMode.MidSide: frame.subframes[ch].obits += (uint)ch; break;
+ case ChannelMode.LeftSide: frame.subframes[ch].obits += (uint)ch; break;
+ case ChannelMode.RightSide: frame.subframes[ch].obits += 1 - (uint)ch; break;
}
- frame->subframes[ch].best.type = (SubframeType)type_code;
- frame->subframes[ch].best.order = 0;
+ frame.subframes[ch].best.type = (SubframeType)type_code;
+ frame.subframes[ch].best.order = 0;
if ((type_code & (uint)SubframeType.LPC) != 0)
{
- frame->subframes[ch].best.order = (type_code - (int)SubframeType.LPC) + 1;
- frame->subframes[ch].best.type = SubframeType.LPC;
+ frame.subframes[ch].best.order = (type_code - (int)SubframeType.LPC) + 1;
+ frame.subframes[ch].best.type = SubframeType.LPC;
}
else if ((type_code & (uint)SubframeType.Fixed) != 0)
{
- frame->subframes[ch].best.order = (type_code - (int)SubframeType.Fixed);
- frame->subframes[ch].best.type = SubframeType.Fixed;
+ frame.subframes[ch].best.order = (type_code - (int)SubframeType.Fixed);
+ frame.subframes[ch].best.type = SubframeType.Fixed;
}
- frame->subframes[ch].best.residual = r + ch * Flake.MAX_BLOCKSIZE;
- frame->subframes[ch].samples = s + ch * Flake.MAX_BLOCKSIZE;
+ frame.subframes[ch].best.residual = r + ch * Flake.MAX_BLOCKSIZE;
+ frame.subframes[ch].samples = s + ch * Flake.MAX_BLOCKSIZE;
// subframe
- switch (frame->subframes[ch].best.type)
+ switch (frame.subframes[ch].best.type)
{
case SubframeType.Constant:
decode_subframe_constant(bitreader, frame, ch);
@@ -487,16 +491,16 @@ namespace CUETools.Codecs.FLAKE
}
}
- unsafe void restore_samples_fixed(FlacFrame* frame, int ch)
+ unsafe void restore_samples_fixed(FlacFrame frame, int ch)
{
- FlacSubframeInfo* sub = frame->subframes + ch;
+ FlacSubframeInfo sub = frame.subframes[ch];
- Flake.memcpy(sub->samples, sub->best.residual, sub->best.order);
- int* data = sub->samples + sub->best.order;
- int* residual = sub->best.residual + sub->best.order;
- int data_len = frame->blocksize - sub->best.order;
+ Flake.memcpy(sub.samples, sub.best.residual, sub.best.order);
+ int* data = sub.samples + sub.best.order;
+ int* residual = sub.best.residual + sub.best.order;
+ int data_len = frame.blocksize - sub.best.order;
int s0, s1, s2;
- switch (sub->best.order)
+ switch (sub.best.order)
{
case 0:
Flake.memcpy(data, residual, data_len);
@@ -533,29 +537,32 @@ namespace CUETools.Codecs.FLAKE
}
}
- unsafe void restore_samples_lpc(FlacFrame* frame, int ch)
+ unsafe void restore_samples_lpc(FlacFrame frame, int ch)
{
- FlacSubframeInfo* sub = frame->subframes + ch;
+ FlacSubframeInfo sub = frame.subframes[ch];
ulong csum = 0;
- for (int i = sub->best.order; i > 0; i--)
- csum += (ulong)Math.Abs(sub->best.coefs[i - 1]);
- if ((csum << (int)sub->obits) >= 1UL << 32)
- lpc.decode_residual_long(sub->best.residual, sub->samples, frame->blocksize, sub->best.order, sub->best.coefs, sub->best.shift);
- else
- lpc.decode_residual(sub->best.residual, sub->samples, frame->blocksize, sub->best.order, sub->best.coefs, sub->best.shift);
+ fixed (int* coefs = sub.best.coefs)
+ {
+ for (int i = sub.best.order; i > 0; i--)
+ csum += (ulong)Math.Abs(coefs[i - 1]);
+ if ((csum << (int)sub.obits) >= 1UL << 32)
+ lpc.decode_residual_long(sub.best.residual, sub.samples, frame.blocksize, sub.best.order, coefs, sub.best.shift);
+ else
+ lpc.decode_residual(sub.best.residual, sub.samples, frame.blocksize, sub.best.order, coefs, sub.best.shift);
+ }
}
- unsafe void restore_samples(FlacFrame* frame)
+ unsafe void restore_samples(FlacFrame frame)
{
for (int ch = 0; ch < channels; ch++)
{
- switch (frame->subframes[ch].best.type)
+ switch (frame.subframes[ch].best.type)
{
case SubframeType.Constant:
- Flake.memset(frame->subframes[ch].samples, frame->subframes[ch].best.residual[0], frame->blocksize);
+ Flake.memset(frame.subframes[ch].samples, frame.subframes[ch].best.residual[0], frame.blocksize);
break;
case SubframeType.Verbatim:
- Flake.memcpy(frame->subframes[ch].samples, frame->subframes[ch].best.residual, frame->blocksize);
+ Flake.memcpy(frame.subframes[ch].samples, frame.subframes[ch].best.residual, frame.blocksize);
break;
case SubframeType.Fixed:
restore_samples_fixed(frame, ch);
@@ -564,24 +571,24 @@ namespace CUETools.Codecs.FLAKE
restore_samples_lpc(frame, ch);
break;
}
- if (frame->subframes[ch].wbits != 0)
+ if (frame.subframes[ch].wbits != 0)
{
- int* s = frame->subframes[ch].samples;
- int x = (int) frame->subframes[ch].wbits;
- for (int i = frame->blocksize; i > 0; i--)
+ int* s = frame.subframes[ch].samples;
+ int x = (int) frame.subframes[ch].wbits;
+ for (int i = frame.blocksize; i > 0; i--)
*(s++) <<= x;
}
}
- if (frame->ch_mode != ChannelMode.NotStereo)
+ if (frame.ch_mode != ChannelMode.NotStereo)
{
- int* l = frame->subframes[0].samples;
- int* r = frame->subframes[1].samples;
- switch (frame->ch_mode)
+ int* l = frame.subframes[0].samples;
+ int* r = frame.subframes[1].samples;
+ switch (frame.ch_mode)
{
case ChannelMode.LeftRight:
break;
case ChannelMode.MidSide:
- for (int i = frame->blocksize; i > 0; i--)
+ for (int i = frame.blocksize; i > 0; i--)
{
int mid = *l;
int side = *r;
@@ -592,14 +599,14 @@ namespace CUETools.Codecs.FLAKE
}
break;
case ChannelMode.LeftSide:
- for (int i = frame->blocksize; i > 0; i--)
+ for (int i = frame.blocksize; i > 0; i--)
{
int _l = *(l++), _r = *r;
*(r++) = _l - _r;
}
break;
case ChannelMode.RightSide:
- for (int i = frame->blocksize; i > 0; i--)
+ for (int i = frame.blocksize; i > 0; i--)
*(l++) += *(r++);
break;
}
@@ -611,16 +618,13 @@ namespace CUETools.Codecs.FLAKE
fixed (byte* buf = buffer)
{
BitReader bitreader = new BitReader(buf, pos, len);
- FlacFrame frame;
- FlacSubframeInfo* subframes = stackalloc FlacSubframeInfo[channels];
- frame.subframes = subframes;
- decode_frame_header(bitreader, &frame);
- decode_subframes(bitreader, &frame);
+ decode_frame_header(bitreader, frame);
+ decode_subframes(bitreader, frame);
bitreader.flush();
ushort crc = crc16.ComputeChecksum(bitreader.Buffer + pos, bitreader.Position - pos);
if (crc != bitreader.readbits(16))
throw new Exception("frame crc mismatch");
- restore_samples(&frame);
+ restore_samples(frame);
_samplesInBuffer = (uint)frame.blocksize;
return bitreader.Position - pos;
}
@@ -705,7 +709,7 @@ namespace CUETools.Codecs.FLAKE
MetadataType type = (MetadataType)bitreader.readbits(7);
int len = (int)bitreader.readbits(24);
- if (type == MetadataType.FLAC__METADATA_TYPE_STREAMINFO)
+ if (type == MetadataType.StreamInfo)
{
const int FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
const int FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
@@ -727,7 +731,7 @@ namespace CUETools.Codecs.FLAKE
_sampleCount = bitreader.readbits64(FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN);
bitreader.skipbits(FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN);
}
- else if (type == MetadataType.FLAC__METADATA_TYPE_SEEKTABLE)
+ else if (type == MetadataType.Seektable)
{
int num_entries = len / 18;
seek_table = new SeekPoint[num_entries];
diff --git a/CUETools.Codecs.FLAKE/FlakeWriter.cs b/CUETools.Codecs.FLAKE/FlakeWriter.cs
index 677bd39..e9f556c 100644
--- a/CUETools.Codecs.FLAKE/FlakeWriter.cs
+++ b/CUETools.Codecs.FLAKE/FlakeWriter.cs
@@ -25,7 +25,7 @@ using System.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Cryptography;
-//using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
using CUETools.Codecs;
namespace CUETools.Codecs.FLAKE
@@ -81,7 +81,7 @@ namespace CUETools.Codecs.FLAKE
double[] windowBuffer;
int samplesInBuffer = 0;
- int _compressionLevel = 5;
+ int _compressionLevel = 7;
int _blocksize = 0;
int _totalSize = 0;
int _windowsize = 0, _windowcount = 0;
@@ -90,6 +90,7 @@ namespace CUETools.Codecs.FLAKE
Crc16 crc16;
MD5 md5;
+ FlacFrame frame;
FlakeReader verify;
SeekPoint[] seek_table;
@@ -122,6 +123,7 @@ namespace CUETools.Codecs.FLAKE
crc8 = new Crc8();
crc16 = new Crc16();
+ frame = new FlacFrame(channels * 2);
}
public int TotalSize
@@ -159,10 +161,10 @@ namespace CUETools.Codecs.FLAKE
}
}
- //[DllImport("kernel32.dll")]
- //static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime, out long lpExitTime, out long lpKernelTime, out long lpUserTime);
- //[DllImport("kernel32.dll")]
- //static extern IntPtr GetCurrentThread();
+ [DllImport("kernel32.dll")]
+ static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime, out long lpExitTime, out long lpKernelTime, out long lpUserTime);
+ [DllImport("kernel32.dll")]
+ static extern IntPtr GetCurrentThread();
void DoClose()
{
@@ -194,9 +196,9 @@ namespace CUETools.Codecs.FLAKE
inited = false;
}
- //long fake, KernelStart, UserStart;
- //GetThreadTimes(GetCurrentThread(), out fake, out fake, out KernelStart, out UserStart);
- //_userProcessorTime = new TimeSpan(UserStart);
+ long fake, KernelStart, UserStart;
+ GetThreadTimes(GetCurrentThread(), out fake, out fake, out KernelStart, out UserStart);
+ _userProcessorTime = new TimeSpan(UserStart);
}
public void Close()
@@ -468,43 +470,13 @@ namespace CUETools.Codecs.FLAKE
return (uint)shift;
}
- unsafe void init_frame(FlacFrame * frame, int bs)
- {
- //if (channels == 2)
- //max_frame_size =
-
- int i = 15;
- if (eparams.variable_block_size == 0)
- {
- for (i = 0; i < 15; i++)
- {
- if (bs == Flake.flac_blocksizes[i])
- {
- frame->blocksize = Flake.flac_blocksizes[i];
- frame->bs_code0 = i;
- frame->bs_code1 = -1;
- break;
- }
- }
- }
- if (i == 15)
- {
- frame->blocksize = bs;
- if (frame->blocksize <= 256)
- {
- frame->bs_code0 = 6;
- frame->bs_code1 = frame->blocksize - 1;
- }
- else
- {
- frame->bs_code0 = 7;
- frame->bs_code1 = frame->blocksize - 1;
- }
- }
- }
-
+ ///
/// Copy channel-interleaved input samples into separate subframes
- unsafe void copy_samples(int[,] samples, int pos, int block)
+ ///
+ ///
+ ///
+ ///
+ unsafe void copy_samples(int[,] samples, int pos, int block)
{
fixed (int* fsamples = samplesBuffer, src = &samples[pos, 0])
{
@@ -562,10 +534,10 @@ namespace CUETools.Codecs.FLAKE
return k_opt;
}
- unsafe uint calc_decorr_score(FlacFrame* frame, int ch)
+ unsafe uint calc_decorr_score(FlacFrame frame, int ch)
{
- int* s = frame->subframes[ch].samples;
- int n = frame->blocksize;
+ int* s = frame.subframes[ch].samples;
+ int n = frame.blocksize;
ulong sum = 0;
for (int i = 2; i < n; i++)
sum += (ulong)Math.Abs(s[i] - 2 * s[i - 1] + s[i - 2]);
@@ -574,23 +546,6 @@ namespace CUETools.Codecs.FLAKE
return nbits;
}
- unsafe void initialize_subframe(FlacFrame* frame, int ch, int *s, int * r, uint bps, uint w)
- {
- if (w > bps)
- throw new Exception("internal error");
- frame->subframes[ch].samples = s;
- frame->subframes[ch].obits = bps - w;
- frame->subframes[ch].wbits = w;
- frame->subframes[ch].best.residual = r;
- frame->subframes[ch].best.type = SubframeType.Verbatim;
- frame->subframes[ch].best.size = UINT32_MAX;
- for (int iWindow = 0; iWindow < lpc.MAX_LPC_PRECISIONS * lpc.MAX_LPC_WINDOWS; iWindow++)
- frame->subframes[ch].done_lpcs[iWindow] = 0;
- frame->subframes[ch].done_fixed = 0;
- for (int iWindow = 0; iWindow < lpc.MAX_LPC_WINDOWS; iWindow++)
- frame->subframes[ch].autocorr_orders[iWindow] = 0;
- }
-
unsafe static void channel_decorrelation(int* leftS, int* rightS, int *leftM, int *rightM, int blocksize)
{
for (int i = 0; i < blocksize; i++)
@@ -658,22 +613,20 @@ namespace CUETools.Codecs.FLAKE
}
}
- public const uint UINT32_MAX = 0xffffffff;
-
- static unsafe uint calc_optimal_rice_params(RiceContext* rc, int porder, uint* sums, uint n, uint pred_order)
+ static unsafe uint calc_optimal_rice_params(ref RiceContext rc, int porder, uint* sums, uint n, uint pred_order)
{
uint part = (1U << porder);
uint all_bits = 0;
- rc->rparams[0] = find_optimal_rice_param(sums[0], (n >> porder) - pred_order, out all_bits);
+ rc.rparams[0] = find_optimal_rice_param(sums[0], (n >> porder) - pred_order, out all_bits);
uint cnt = (n >> porder);
for (uint i = 1; i < part; i++)
{
uint nbits;
- rc->rparams[i] = find_optimal_rice_param(sums[i], cnt, out nbits);
+ rc.rparams[i] = find_optimal_rice_param(sums[i], cnt, out nbits);
all_bits += nbits;
}
all_bits += (4 * part);
- rc->porder = porder;
+ rc.porder = porder;
return all_bits;
}
@@ -708,9 +661,9 @@ namespace CUETools.Codecs.FLAKE
}
}
- static unsafe uint calc_rice_params(RiceContext* rc, int pmin, int pmax, int* data, uint n, uint pred_order)
+ static unsafe uint calc_rice_params(ref RiceContext rc, int pmin, int pmax, int* data, uint n, uint pred_order)
{
- RiceContext tmp_rc;
+ RiceContext tmp_rc = new RiceContext(), tmp_rc2;
uint* udata = stackalloc uint[(int)n];
uint* sums = stackalloc uint[(pmax + 1) * Flake.MAX_PARTITIONS];
//uint* bits = stackalloc uint[Flake.MAX_PARTITION_ORDER];
@@ -725,15 +678,17 @@ namespace CUETools.Codecs.FLAKE
calc_sums(pmin, pmax, udata, n, pred_order, sums);
int opt_porder = pmin;
- uint opt_bits = UINT32_MAX;
+ uint opt_bits = Flake.UINT32_MAX;
for (int i = pmin; i <= pmax; i++)
{
- uint bits = calc_optimal_rice_params(&tmp_rc, i, sums + i * Flake.MAX_PARTITIONS, n, pred_order);
+ uint bits = calc_optimal_rice_params(ref tmp_rc, i, sums + i * Flake.MAX_PARTITIONS, n, pred_order);
if (bits <= opt_bits)
{
opt_porder = i;
opt_bits = bits;
- *rc = tmp_rc;
+ tmp_rc2 = rc;
+ rc = tmp_rc;
+ tmp_rc = tmp_rc2;
}
}
@@ -748,128 +703,102 @@ namespace CUETools.Codecs.FLAKE
return porder;
}
- static unsafe uint calc_rice_params_fixed(RiceContext* rc, int pmin, int pmax,
+ static unsafe uint calc_rice_params_fixed(ref RiceContext rc, int pmin, int pmax,
int* data, int n, int pred_order, uint bps)
{
pmin = get_max_p_order(pmin, n, pred_order);
pmax = get_max_p_order(pmax, n, pred_order);
uint bits = (uint)pred_order * bps + 6;
- bits += calc_rice_params(rc, pmin, pmax, data, (uint)n, (uint)pred_order);
+ bits += calc_rice_params(ref rc, pmin, pmax, data, (uint)n, (uint)pred_order);
return bits;
}
- static unsafe uint calc_rice_params_lpc(RiceContext* rc, int pmin, int pmax,
+ static unsafe uint calc_rice_params_lpc(ref RiceContext rc, int pmin, int pmax,
int* data, int n, int pred_order, uint bps, uint precision)
{
pmin = get_max_p_order(pmin, n, pred_order);
pmax = get_max_p_order(pmax, n, pred_order);
uint bits = (uint)pred_order * bps + 4 + 5 + (uint)pred_order * precision + 6;
- bits += calc_rice_params(rc, pmin, pmax, data, (uint)n, (uint)pred_order);
+ bits += calc_rice_params(ref rc, pmin, pmax, data, (uint)n, (uint)pred_order);
return bits;
}
- unsafe void choose_best_subframe(FlacFrame* frame, int ch)
- {
- if (frame->current.size < frame->subframes[ch].best.size)
- {
- FlacSubframe tmp = frame->subframes[ch].best;
- frame->subframes[ch].best = frame->current;
- frame->current = tmp;
- }
- }
-
- unsafe void encode_residual_lpc_sub(FlacFrame* frame, double * lpcs, int iWindow, int order, int ch)
+ unsafe void encode_residual_lpc_sub(FlacFrame frame, double * lpcs, int iWindow, int order, int ch)
{
// select LPC precision based on block size
uint lpc_precision;
- if (frame->blocksize <= 192) lpc_precision = 7U;
- else if (frame->blocksize <= 384) lpc_precision = 8U;
- else if (frame->blocksize <= 576) lpc_precision = 9U;
- else if (frame->blocksize <= 1152) lpc_precision = 10U;
- else if (frame->blocksize <= 2304) lpc_precision = 11U;
- else if (frame->blocksize <= 4608) lpc_precision = 12U;
- else if (frame->blocksize <= 8192) lpc_precision = 13U;
- else if (frame->blocksize <= 16384) lpc_precision = 14U;
+ if (frame.blocksize <= 192) lpc_precision = 7U;
+ else if (frame.blocksize <= 384) lpc_precision = 8U;
+ else if (frame.blocksize <= 576) lpc_precision = 9U;
+ else if (frame.blocksize <= 1152) lpc_precision = 10U;
+ else if (frame.blocksize <= 2304) lpc_precision = 11U;
+ else if (frame.blocksize <= 4608) lpc_precision = 12U;
+ else if (frame.blocksize <= 8192) lpc_precision = 13U;
+ else if (frame.blocksize <= 16384) lpc_precision = 14U;
else lpc_precision = 15;
for (int i_precision = eparams.lpc_min_precision_search; i_precision <= eparams.lpc_max_precision_search && lpc_precision + i_precision < 16; i_precision++)
// check if we already calculated with this order, window and precision
- if ((frame->subframes[ch].done_lpcs[iWindow + i_precision * lpc.MAX_LPC_WINDOWS] & (1U << (order - 1))) == 0)
+ if ((frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[i_precision] & (1U << (order - 1))) == 0)
{
- frame->subframes[ch].done_lpcs[iWindow + i_precision * lpc.MAX_LPC_WINDOWS] |= (1U << (order - 1));
+ frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[i_precision] |= (1U << (order - 1));
uint cbits = lpc_precision + (uint)i_precision;
- frame->current.type = SubframeType.LPC;
- frame->current.order = order;
- frame->current.window = iWindow;
+ frame.current.type = SubframeType.LPC;
+ frame.current.order = order;
+ frame.current.window = iWindow;
- lpc.quantize_lpc_coefs(lpcs + (frame->current.order - 1) * lpc.MAX_LPC_ORDER,
- frame->current.order, cbits, frame->current.coefs, out frame->current.shift);
+ fixed (int* coefs = frame.current.coefs)
+ {
+ lpc.quantize_lpc_coefs(lpcs + (frame.current.order - 1) * lpc.MAX_LPC_ORDER,
+ frame.current.order, cbits, coefs, out frame.current.shift);
- if (frame->current.shift < 0 || frame->current.shift > 15)
- throw new Exception("negative shift");
+ if (frame.current.shift < 0 || frame.current.shift > 15)
+ throw new Exception("negative shift");
- ulong csum = 0;
- for (int i = frame->current.order; i > 0; i--)
- csum += (ulong)Math.Abs(frame->current.coefs[i - 1]);
+ ulong csum = 0;
+ for (int i = frame.current.order; i > 0; i--)
+ csum += (ulong)Math.Abs(coefs[i - 1]);
- if ((csum << (int)frame->subframes[ch].obits) >= 1UL << 32)
- lpc.encode_residual_long(frame->current.residual, frame->subframes[ch].samples, frame->blocksize, frame->current.order, frame->current.coefs, frame->current.shift);
- else
- lpc.encode_residual(frame->current.residual, frame->subframes[ch].samples, frame->blocksize, frame->current.order, frame->current.coefs, frame->current.shift);
+ if ((csum << (int)frame.subframes[ch].obits) >= 1UL << 32)
+ lpc.encode_residual_long(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift);
+ else
+ lpc.encode_residual(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift);
- frame->current.size = calc_rice_params_lpc(&frame->current.rc, eparams.min_partition_order, eparams.max_partition_order,
- frame->current.residual, frame->blocksize, frame->current.order, frame->subframes[ch].obits, cbits);
+ }
- choose_best_subframe(frame, ch);
+ frame.current.size = calc_rice_params_lpc(ref frame.current.rc, eparams.min_partition_order, eparams.max_partition_order,
+ frame.current.residual, frame.blocksize, frame.current.order, frame.subframes[ch].obits, cbits);
+
+ frame.ChooseBestSubframe(ch);
}
}
- unsafe void encode_residual_fixed_sub(FlacFrame* frame, int order, int ch)
+ unsafe void encode_residual_fixed_sub(FlacFrame frame, int order, int ch)
{
- if ((frame->subframes[ch].done_fixed & (1U << order)) != 0)
+ if ((frame.subframes[ch].done_fixed & (1U << order)) != 0)
return; // already calculated;
- frame->current.order = order;
- frame->current.type = SubframeType.Fixed;
+ frame.current.order = order;
+ frame.current.type = SubframeType.Fixed;
- encode_residual_fixed(frame->current.residual, frame->subframes[ch].samples, frame->blocksize, frame->current.order);
+ encode_residual_fixed(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order);
- frame->current.size = calc_rice_params_fixed(&frame->current.rc, eparams.min_partition_order, eparams.max_partition_order,
- frame->current.residual, frame->blocksize, frame->current.order, frame->subframes[ch].obits);
+ frame.current.size = calc_rice_params_fixed(ref frame.current.rc, eparams.min_partition_order, eparams.max_partition_order,
+ frame.current.residual, frame.blocksize, frame.current.order, frame.subframes[ch].obits);
- frame->subframes[ch].done_fixed |= (1U << order);
+ frame.subframes[ch].done_fixed |= (1U << order);
- choose_best_subframe(frame, ch);
+ frame.ChooseBestSubframe(ch);
}
- unsafe static bool is_interesting_order(double* reff, int order, int max_order)
+ unsafe void encode_residual(FlacFrame frame, int ch, PredictionType predict, OrderMethod omethod, int pass)
{
- return (order > 4 && Math.Abs(reff[order - 1]) >= 0.10 && (order == max_order || Math.Abs(reff[order]) < 0.10)) ||
- (order < 6 && order < max_order - 1 && reff[order + 1] * reff[order + 1] + reff[order] * reff[order] < 0.1);
- }
-
- unsafe double* get_reflection_coeffs(FlacFrame* frame, int ch, int order, int iWindow)
- {
- double* reff = frame->subframes[ch].reflection_coeffs + iWindow * lpc.MAX_LPC_ORDER;
- if (frame->subframes[ch].autocorr_orders[iWindow] > order)
- return reff;
- double* autoc = frame->subframes[ch].autocorr_values + iWindow * (lpc.MAX_LPC_ORDER + 1);
- lpc.compute_autocorr(frame->subframes[ch].samples, (uint)frame->blocksize,
- (uint)frame->subframes[ch].autocorr_orders[iWindow],
- (uint)order, autoc, frame->window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2);
- lpc.compute_schur_reflection(autoc, (uint)order, reff);
- frame->subframes[ch].autocorr_orders[iWindow] = order + 1;
- return reff;
- }
-
- unsafe void encode_residual(FlacFrame* frame, int ch, PredictionType predict, OrderMethod omethod, int pass)
- {
- int* smp = frame->subframes[ch].samples;
- int i, n = frame->blocksize;
+ int* smp = frame.subframes[ch].samples;
+ int i, n = frame.blocksize;
// save best.window, because we can overwrite it later with fixed frame
- int best_window = frame->subframes[ch].best.type == SubframeType.LPC ? frame->subframes[ch].best.window : -1;
+ int best_window = frame.subframes[ch].best.type == SubframeType.LPC ? frame.subframes[ch].best.window : -1;
// CONSTANT
for (i = 1; i < n; i++)
@@ -878,16 +807,16 @@ namespace CUETools.Codecs.FLAKE
}
if (i == n)
{
- frame->subframes[ch].best.type = SubframeType.Constant;
- frame->subframes[ch].best.residual[0] = smp[0];
- frame->subframes[ch].best.size = frame->subframes[ch].obits;
+ frame.subframes[ch].best.type = SubframeType.Constant;
+ frame.subframes[ch].best.residual[0] = smp[0];
+ frame.subframes[ch].best.size = frame.subframes[ch].obits;
return;
}
// VERBATIM
- frame->current.type = SubframeType.Verbatim;
- frame->current.size = frame->subframes[ch].obits * (uint)frame->blocksize;
- choose_best_subframe(frame, ch);
+ frame.current.type = SubframeType.Verbatim;
+ frame.current.size = frame.subframes[ch].obits * (uint)frame.blocksize;
+ frame.ChooseBestSubframe(ch);
if (n < 5 || predict == PredictionType.None)
return;
@@ -896,7 +825,7 @@ namespace CUETools.Codecs.FLAKE
if (predict == PredictionType.Fixed ||
(predict == PredictionType.Search && pass != 1) ||
//predict == PredictionType.Search ||
- //(pass == 2 && frame->subframes[ch].best.type == SubframeType.Fixed) ||
+ //(pass == 2 && frame.subframes[ch].best.type == SubframeType.Fixed) ||
n <= eparams.max_prediction_order)
{
int max_fixed_order = Math.Min(eparams.max_fixed_order, 4);
@@ -911,10 +840,10 @@ namespace CUETools.Codecs.FLAKE
(predict == PredictionType.Levinson ||
predict == PredictionType.Search)
//predict == PredictionType.Search ||
- //(pass == 2 && frame->subframes[ch].best.type == SubframeType.LPC))
+ //(pass == 2 && frame.subframes[ch].best.type == SubframeType.LPC))
)
{
- //double* lpcs = stackalloc double[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER];
+ double* lpcs = stackalloc double[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER];
int min_order = eparams.min_prediction_order;
int max_order = eparams.max_prediction_order;
@@ -923,9 +852,10 @@ namespace CUETools.Codecs.FLAKE
if (pass == 2 && iWindow != best_window)
continue;
- double* reff = get_reflection_coeffs(frame, ch, max_order, iWindow);
- double* lpcs = stackalloc double[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER];
- lpc.compute_lpc_coefs(null, (uint)max_order, reff, lpcs);
+ LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
+
+ lpc_ctx.GetReflection(max_order, smp, n, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2);
+ lpc_ctx.ComputeLPC(lpcs);
switch (omethod)
{
@@ -939,7 +869,7 @@ namespace CUETools.Codecs.FLAKE
{
int found = 0;
for (i = max_order; i >= min_order && found < eparams.estimation_depth; i--)
- if (is_interesting_order(reff, i, max_order))
+ if (lpc_ctx.IsInterestingOrder(i))
{
encode_residual_lpc_sub(frame, lpcs, iWindow, i, ch);
found++;
@@ -953,7 +883,7 @@ namespace CUETools.Codecs.FLAKE
{
int found = 0;
for (i = min_order; i <= max_order && found < eparams.estimation_depth; i++)
- if (is_interesting_order(reff, i, max_order))
+ if (lpc_ctx.IsInterestingOrder(i))
{
encode_residual_lpc_sub(frame, lpcs, iWindow, i, ch);
found++;
@@ -981,12 +911,12 @@ namespace CUETools.Codecs.FLAKE
if (i < max_order)
encode_residual_lpc_sub(frame, lpcs, iWindow, i, ch);
// if found a good order, try to search around it
- if (frame->subframes[ch].best.type == SubframeType.LPC)
+ if (frame.subframes[ch].best.type == SubframeType.LPC)
{
// log search (written by Michael Niedermayer for FFmpeg)
for (int step = lpc.MAX_LPC_ORDER; step > 0; step >>= 1)
{
- int last = frame->subframes[ch].best.order;
+ int last = frame.subframes[ch].best.order;
if (step <= (last + 1) / 2)
for (i = last - step; i <= last + step; i += step)
if (i >= min_order && i <= max_order)
@@ -1001,27 +931,27 @@ namespace CUETools.Codecs.FLAKE
}
}
- unsafe void output_frame_header(FlacFrame* frame, BitWriter bitwriter)
+ unsafe void output_frame_header(FlacFrame frame, BitWriter bitwriter)
{
bitwriter.writebits(15, 0x7FFC);
bitwriter.writebits(1, eparams.variable_block_size > 0 ? 1 : 0);
- bitwriter.writebits(4, frame->bs_code0);
+ bitwriter.writebits(4, frame.bs_code0);
bitwriter.writebits(4, sr_code0);
- if (frame->ch_mode == ChannelMode.NotStereo)
+ if (frame.ch_mode == ChannelMode.NotStereo)
bitwriter.writebits(4, ch_code);
else
- bitwriter.writebits(4, (int) frame->ch_mode);
+ bitwriter.writebits(4, (int) frame.ch_mode);
bitwriter.writebits(3, bps_code);
bitwriter.writebits(1, 0);
bitwriter.write_utf8(frame_count);
// custom block size
- if (frame->bs_code1 >= 0)
+ if (frame.bs_code1 >= 0)
{
- if (frame->bs_code1 < 256)
- bitwriter.writebits(8, frame->bs_code1);
+ if (frame.bs_code1 < 256)
+ bitwriter.writebits(8, frame.bs_code1);
else
- bitwriter.writebits(16, frame->bs_code1);
+ bitwriter.writebits(16, frame.bs_code1);
}
// custom sample rate
@@ -1039,100 +969,97 @@ namespace CUETools.Codecs.FLAKE
bitwriter.writebits(8, crc);
}
- unsafe void output_residual(FlacFrame* frame, BitWriter bitwriter, FlacSubframeInfo* sub)
+ unsafe void output_residual(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub)
{
// rice-encoded block
bitwriter.writebits(2, 0);
// partition order
- int porder = sub->best.rc.porder;
- int psize = frame->blocksize >> porder;
+ int porder = sub.best.rc.porder;
+ int psize = frame.blocksize >> porder;
//assert(porder >= 0);
bitwriter.writebits(4, porder);
- int res_cnt = psize - sub->best.order;
+ int res_cnt = psize - sub.best.order;
// residual
- int j = sub->best.order;
+ int j = sub.best.order;
for (int p = 0; p < (1 << porder); p++)
{
- int k = sub->best.rc.rparams[p];
+ int k = sub.best.rc.rparams[p];
bitwriter.writebits(4, k);
if (p == 1) res_cnt = psize;
- if (k == 0)
- for (int i = 0; i < res_cnt && j < frame->blocksize; i++, j++)
- bitwriter.write_unary_signed(sub->best.residual[j]);
- else
- for (int i = 0; i < res_cnt && j < frame->blocksize; i++, j++)
- bitwriter.write_rice_signed(k, sub->best.residual[j]);
+ int cnt = Math.Min(res_cnt, frame.blocksize - j);
+ bitwriter.write_rice_block_signed(k, sub.best.residual + j, cnt);
+ j += cnt;
}
}
unsafe void
- output_subframe_constant(FlacFrame* frame, BitWriter bitwriter, FlacSubframeInfo* sub)
+ output_subframe_constant(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub)
{
- bitwriter.writebits_signed(sub->obits, sub->best.residual[0]);
+ bitwriter.writebits_signed(sub.obits, sub.best.residual[0]);
}
unsafe void
- output_subframe_verbatim(FlacFrame* frame, BitWriter bitwriter, FlacSubframeInfo* sub)
+ output_subframe_verbatim(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub)
{
- int n = frame->blocksize;
+ int n = frame.blocksize;
for (int i = 0; i < n; i++)
- bitwriter.writebits_signed(sub->obits, sub->samples[i]);
+ bitwriter.writebits_signed(sub.obits, sub.samples[i]);
// Don't use residual here, because we don't copy samples to residual for verbatim frames.
}
unsafe void
- output_subframe_fixed(FlacFrame* frame, BitWriter bitwriter, FlacSubframeInfo* sub)
+ output_subframe_fixed(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub)
{
// warm-up samples
- for (int i = 0; i < sub->best.order; i++)
- bitwriter.writebits_signed(sub->obits, sub->best.residual[i]);
+ for (int i = 0; i < sub.best.order; i++)
+ bitwriter.writebits_signed(sub.obits, sub.best.residual[i]);
// residual
output_residual(frame, bitwriter, sub);
}
unsafe void
- output_subframe_lpc(FlacFrame* frame, BitWriter bitwriter, FlacSubframeInfo* sub)
+ output_subframe_lpc(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub)
{
// warm-up samples
- for (int i = 0; i < sub->best.order; i++)
- bitwriter.writebits_signed(sub->obits, sub->best.residual[i]);
+ for (int i = 0; i < sub.best.order; i++)
+ bitwriter.writebits_signed(sub.obits, sub.best.residual[i]);
// LPC coefficients
int cbits = 1;
- for (int i = 0; i < sub->best.order; i++)
- while (cbits < 16 && sub->best.coefs[i] != (sub->best.coefs[i] << (32 - cbits)) >> (32 - cbits))
+ for (int i = 0; i < sub.best.order; i++)
+ while (cbits < 16 && sub.best.coefs[i] != (sub.best.coefs[i] << (32 - cbits)) >> (32 - cbits))
cbits++;
bitwriter.writebits(4, cbits - 1);
- bitwriter.writebits_signed(5, sub->best.shift);
- for (int i = 0; i < sub->best.order; i++)
- bitwriter.writebits_signed(cbits, sub->best.coefs[i]);
+ bitwriter.writebits_signed(5, sub.best.shift);
+ for (int i = 0; i < sub.best.order; i++)
+ bitwriter.writebits_signed(cbits, sub.best.coefs[i]);
// residual
output_residual(frame, bitwriter, sub);
}
- unsafe void output_subframes(FlacFrame* frame, BitWriter bitwriter)
+ unsafe void output_subframes(FlacFrame frame, BitWriter bitwriter)
{
for (int ch = 0; ch < channels; ch++)
{
- FlacSubframeInfo* sub = frame->subframes + ch;
+ FlacSubframeInfo sub = frame.subframes[ch];
// subframe header
- int type_code = (int) sub->best.type;
- if (sub->best.type == SubframeType.Fixed)
- type_code |= sub->best.order;
- if (sub->best.type == SubframeType.LPC)
- type_code |= sub->best.order - 1;
+ int type_code = (int) sub.best.type;
+ if (sub.best.type == SubframeType.Fixed)
+ type_code |= sub.best.order;
+ if (sub.best.type == SubframeType.LPC)
+ type_code |= sub.best.order - 1;
bitwriter.writebits(1, 0);
bitwriter.writebits(6, type_code);
- bitwriter.writebits(1, sub->wbits != 0 ? 1 : 0);
- if (sub->wbits > 0)
- bitwriter.writebits((int)sub->wbits, 1);
+ bitwriter.writebits(1, sub.wbits != 0 ? 1 : 0);
+ if (sub.wbits > 0)
+ bitwriter.writebits((int)sub.wbits, 1);
// subframe
- switch (sub->best.type)
+ switch (sub.best.type)
{
case SubframeType.Constant:
output_subframe_constant(frame, bitwriter, sub);
@@ -1206,7 +1133,7 @@ namespace CUETools.Codecs.FLAKE
window[n] = 0.5 - 0.5 * Math.Cos(2.0 * Math.PI * n / N);
}
- unsafe void encode_residual_pass1(FlacFrame* frame, int ch)
+ unsafe void encode_residual_pass1(FlacFrame frame, int ch)
{
int max_prediction_order = eparams.max_prediction_order;
int max_fixed_order = eparams.max_fixed_order;
@@ -1230,12 +1157,12 @@ namespace CUETools.Codecs.FLAKE
eparams.estimation_depth = estimation_depth;
}
- unsafe void encode_residual_pass2(FlacFrame* frame, int ch)
+ unsafe void encode_residual_pass2(FlacFrame frame, int ch)
{
encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 2);
}
- unsafe void encode_residual_onepass(FlacFrame* frame, int ch)
+ unsafe void encode_residual_onepass(FlacFrame frame, int ch)
{
if (_windowcount > 1)
{
@@ -1245,7 +1172,7 @@ namespace CUETools.Codecs.FLAKE
encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 0);
}
- unsafe void estimate_frame(FlacFrame* frame, bool do_midside)
+ unsafe void estimate_frame(FlacFrame frame, bool do_midside)
{
int subframes = do_midside ? channels * 2 : channels;
@@ -1253,7 +1180,7 @@ namespace CUETools.Codecs.FLAKE
{
case StereoMethod.Estimate:
for (int ch = 0; ch < subframes; ch++)
- frame->subframes[ch].best.size = (uint)frame->blocksize * 32 + calc_decorr_score(frame, ch);
+ frame.subframes[ch].best.size = (uint)frame.blocksize * 32 + calc_decorr_score(frame, ch);
break;
case StereoMethod.Evaluate:
for (int ch = 0; ch < subframes; ch++)
@@ -1271,67 +1198,53 @@ namespace CUETools.Codecs.FLAKE
}
}
- unsafe uint measure_frame_size(FlacFrame* frame, bool do_midside)
+ unsafe uint measure_frame_size(FlacFrame frame, bool do_midside)
{
- uint total = 48 + 16; // crude estimation of header/footer size;
+ // crude estimation of header/footer size
+ uint total = (uint)(32 + ((Flake.log2i(frame_count) + 4) / 5) * 8 + (eparams.variable_block_size != 0 ? 16 : 0) + 16);
if (do_midside)
{
- uint bitsBest = UINT32_MAX;
+ uint bitsBest = Flake.UINT32_MAX;
ChannelMode modeBest = ChannelMode.LeftRight;
- if (bitsBest > frame->subframes[2].best.size + frame->subframes[3].best.size)
+ if (bitsBest > frame.subframes[2].best.size + frame.subframes[3].best.size)
{
- bitsBest = frame->subframes[2].best.size + frame->subframes[3].best.size;
+ bitsBest = frame.subframes[2].best.size + frame.subframes[3].best.size;
modeBest = ChannelMode.MidSide;
}
- if (bitsBest > frame->subframes[3].best.size + frame->subframes[1].best.size)
+ if (bitsBest > frame.subframes[3].best.size + frame.subframes[1].best.size)
{
- bitsBest = frame->subframes[3].best.size + frame->subframes[1].best.size;
+ bitsBest = frame.subframes[3].best.size + frame.subframes[1].best.size;
modeBest = ChannelMode.RightSide;
}
- if (bitsBest > frame->subframes[3].best.size + frame->subframes[0].best.size)
+ if (bitsBest > frame.subframes[3].best.size + frame.subframes[0].best.size)
{
- bitsBest = frame->subframes[3].best.size + frame->subframes[0].best.size;
+ bitsBest = frame.subframes[3].best.size + frame.subframes[0].best.size;
modeBest = ChannelMode.LeftSide;
}
- if (bitsBest > frame->subframes[0].best.size + frame->subframes[1].best.size)
+ if (bitsBest > frame.subframes[0].best.size + frame.subframes[1].best.size)
{
- bitsBest = frame->subframes[0].best.size + frame->subframes[1].best.size;
+ bitsBest = frame.subframes[0].best.size + frame.subframes[1].best.size;
modeBest = ChannelMode.LeftRight;
}
- frame->ch_mode = modeBest;
+ frame.ch_mode = modeBest;
return total + bitsBest;
}
for (int ch = 0; ch < channels; ch++)
- total += frame->subframes[ch].best.size;
+ total += frame.subframes[ch].best.size;
return total;
}
- unsafe void encode_estimated_frame(FlacFrame* frame, bool do_midside)
+ unsafe void encode_estimated_frame(FlacFrame frame)
{
- if (do_midside)
- switch (frame->ch_mode)
- {
- case ChannelMode.MidSide:
- frame->subframes[0] = frame->subframes[2];
- frame->subframes[1] = frame->subframes[3];
- break;
- case ChannelMode.RightSide:
- frame->subframes[0] = frame->subframes[3];
- break;
- case ChannelMode.LeftSide:
- frame->subframes[1] = frame->subframes[3];
- break;
- }
-
switch (eparams.stereo_method)
{
case StereoMethod.Estimate:
for (int ch = 0; ch < channels; ch++)
{
- frame->subframes[ch].best.size = UINT32_MAX;
+ frame.subframes[ch].best.size = Flake.UINT32_MAX;
encode_residual_onepass(frame, ch);
}
break;
@@ -1369,16 +1282,11 @@ namespace CUETools.Codecs.FLAKE
unsafe int encode_frame(out int size)
{
- FlacFrame frame;
- FlacFrame frame2, frame3;
- FlacSubframeInfo* sf = stackalloc FlacSubframeInfo[channels * 6];
-
fixed (int* s = samplesBuffer, r = residualBuffer)
fixed (double* window = windowBuffer)
{
- frame.subframes = sf;
+ frame.InitSize(eparams.block_size, eparams.variable_block_size != 0);
- init_frame(&frame, eparams.block_size);
if (frame.blocksize != _windowsize && frame.blocksize > 4)
{
_windowsize = frame.blocksize;
@@ -1397,11 +1305,11 @@ namespace CUETools.Codecs.FLAKE
frame.current.residual = r + channels * Flake.MAX_BLOCKSIZE;
frame.ch_mode = channels != 2 ? ChannelMode.NotStereo : ChannelMode.LeftRight;
for (int ch = 0; ch < channels; ch++)
- initialize_subframe(&frame, ch, s + ch * Flake.MAX_BLOCKSIZE, r + ch * Flake.MAX_BLOCKSIZE,
+ frame.subframes[ch].Init(s + ch * Flake.MAX_BLOCKSIZE, r + ch * Flake.MAX_BLOCKSIZE,
bits_per_sample, get_wasted_bits(s + ch * Flake.MAX_BLOCKSIZE, frame.blocksize));
for (int ch = 0; ch < channels; ch++)
- encode_residual_onepass(&frame, ch);
+ encode_residual_onepass(frame, ch);
}
else
{
@@ -1409,41 +1317,43 @@ namespace CUETools.Codecs.FLAKE
frame.window_buffer = window;
frame.current.residual = r + 4 * Flake.MAX_BLOCKSIZE;
for (int ch = 0; ch < 4; ch++)
- initialize_subframe(&frame, ch, s + ch * Flake.MAX_BLOCKSIZE, r + ch * Flake.MAX_BLOCKSIZE,
+ frame.subframes[ch].Init(s + ch * Flake.MAX_BLOCKSIZE, r + ch * Flake.MAX_BLOCKSIZE,
bits_per_sample + (ch == 3 ? 1U : 0U), get_wasted_bits(s + ch * Flake.MAX_BLOCKSIZE, frame.blocksize));
- estimate_frame(&frame, true);
- uint fs = measure_frame_size(&frame, true);
+ estimate_frame(frame, true);
+ uint fs = measure_frame_size(frame, true);
if (0 != eparams.variable_block_size)
{
+ FlacFrame frame2 = new FlacFrame(channels * 2);
+ FlacFrame frame3 = new FlacFrame(channels * 2);
int tumbler = 1;
while ((frame.blocksize & 1) == 0 && frame.blocksize >= 1024)
{
- init_frame(&frame2, frame.blocksize / 2);
+ frame2.InitSize(frame.blocksize / 2, true);
frame2.window_buffer = frame.window_buffer + frame.blocksize;
frame2.current.residual = r + tumbler * 5 * Flake.MAX_BLOCKSIZE;
- frame2.subframes = sf + tumbler * channels * 2;
for (int ch = 0; ch < 4; ch++)
- initialize_subframe(&frame2, ch, frame.subframes[ch].samples, frame2.current.residual + (ch + 1) * frame2.blocksize,
+ frame2.subframes[ch].Init(frame.subframes[ch].samples, frame2.current.residual + (ch + 1) * frame2.blocksize,
frame.subframes[ch].obits + frame.subframes[ch].wbits, frame.subframes[ch].wbits);
- estimate_frame(&frame2, true);
- uint fs2 = measure_frame_size(&frame2, true);
+ estimate_frame(frame2, true);
+ uint fs2 = measure_frame_size(frame2, true);
uint fs3 = fs2;
if (eparams.variable_block_size == 2 || eparams.variable_block_size == 4)
{
- init_frame(&frame3, frame2.blocksize);
+ frame3.InitSize(frame2.blocksize, true);
frame3.window_buffer = frame2.window_buffer;
frame3.current.residual = frame2.current.residual + 5 * frame2.blocksize;
- frame3.subframes = sf + channels * 4;
for (int ch = 0; ch < 4; ch++)
- initialize_subframe(&frame3, ch, frame2.subframes[ch].samples + frame2.blocksize, frame3.current.residual + (ch + 1) * frame3.blocksize,
+ frame3.subframes[ch].Init(frame2.subframes[ch].samples + frame2.blocksize, frame3.current.residual + (ch + 1) * frame3.blocksize,
frame.subframes[ch].obits + frame.subframes[ch].wbits, frame.subframes[ch].wbits);
- estimate_frame(&frame3, true);
- fs3 = measure_frame_size(&frame3, true);
+ estimate_frame(frame3, true);
+ fs3 = measure_frame_size(frame3, true);
}
if (fs2 + fs3 > fs)
break;
+ FlacFrame tmp = frame;
frame = frame2;
+ frame2 = tmp;
fs = fs2;
if (eparams.variable_block_size <= 2)
break;
@@ -1451,13 +1361,14 @@ namespace CUETools.Codecs.FLAKE
}
}
- encode_estimated_frame(&frame, true);
+ frame.ChooseSubframes();
+ encode_estimated_frame(frame);
}
BitWriter bitwriter = new BitWriter(frame_buffer, 0, max_frame_size);
- output_frame_header(&frame, bitwriter);
- output_subframes(&frame, bitwriter);
+ output_frame_header(frame, bitwriter);
+ output_subframes(frame, bitwriter);
output_frame_footer(bitwriter);
if (frame_buffer != null)
@@ -1598,7 +1509,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header
bitwriter.writebits(1, last);
- bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_STREAMINFO);
+ bitwriter.writebits(7, (int)MetadataType.StreamInfo);
bitwriter.writebits(24, 34);
if (eparams.variable_block_size > 0)
@@ -1639,7 +1550,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header
bitwriter.writebits(1, last);
- bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ bitwriter.writebits(7, (int)MetadataType.VorbisComment);
bitwriter.writebits(24, vendor_len + 8);
comment[pos + 4] = (byte)(vendor_len & 0xFF);
@@ -1662,7 +1573,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header
bitwriter.writebits(1, last);
- bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_SEEKTABLE);
+ bitwriter.writebits(7, (int)MetadataType.Seektable);
bitwriter.writebits(24, 18 * seek_table.Length);
for (int i = 0; i < seek_table.Length; i++)
{
@@ -1684,7 +1595,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header
bitwriter.writebits(1, last);
- bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_PADDING);
+ bitwriter.writebits(7, (int)MetadataType.Padding);
bitwriter.writebits(24, padlen);
return padlen + 4;
@@ -1947,7 +1858,7 @@ namespace CUETools.Codecs.FLAKE
block_time_ms = 105;
prediction_type = PredictionType.Search;
min_prediction_order = 1;
- max_prediction_order = 8;
+ max_prediction_order = 12;
estimation_depth = 1;
min_fixed_order = 2;
max_fixed_order = 2;
@@ -1960,49 +1871,46 @@ namespace CUETools.Codecs.FLAKE
do_verify = false;
do_seektable = true;
- // differences from level 5
+ // differences from level 7
switch (lvl)
{
case 0:
- block_time_ms = 27;
+ block_time_ms = 53;
prediction_type = PredictionType.Fixed;
+ stereo_method = StereoMethod.Independent;
max_partition_order = 4;
break;
case 1:
prediction_type = PredictionType.Levinson;
stereo_method = StereoMethod.Independent;
window_function = WindowFunction.Welch;
+ max_prediction_order = 8;
max_partition_order = 4;
break;
case 2:
stereo_method = StereoMethod.Independent;
window_function = WindowFunction.Welch;
- max_prediction_order = 12;
max_partition_order = 4;
break;
case 3:
stereo_method = StereoMethod.Estimate;
window_function = WindowFunction.Welch;
+ max_prediction_order = 8;
break;
case 4:
stereo_method = StereoMethod.Estimate;
window_function = WindowFunction.Welch;
- max_prediction_order = 12;
break;
case 5:
window_function = WindowFunction.Welch;
- max_prediction_order = 12;
break;
case 6:
stereo_method = StereoMethod.Estimate;
- max_prediction_order = 12;
break;
case 7:
- max_prediction_order = 12;
break;
case 8:
estimation_depth = 3;
- max_prediction_order = 12;
min_fixed_order = 0;
max_fixed_order = 4;
lpc_max_precision_search = 2;
diff --git a/CUETools.Codecs.FLAKE/lpc.cs b/CUETools.Codecs.FLAKE/lpc.cs
index f574b1b..6c74dd5 100644
--- a/CUETools.Codecs.FLAKE/lpc.cs
+++ b/CUETools.Codecs.FLAKE/lpc.cs
@@ -804,4 +804,78 @@ namespace CUETools.Codecs.FLAKE
}
}
}
+
+ ///
+ /// Context for LPC coefficients calculation and order estimation
+ ///
+ unsafe class LpcContext
+ {
+ public LpcContext()
+ {
+ reflection_coeffs = new double[lpc.MAX_LPC_ORDER];
+ autocorr_values = new double[lpc.MAX_LPC_ORDER + 1];
+ done_lpcs = new uint[lpc.MAX_LPC_PRECISIONS];
+ }
+
+ ///
+ /// Reset to initial (blank) state
+ ///
+ public void Reset()
+ {
+ autocorr_order = 0;
+ for (int iPrecision = 0; iPrecision < lpc.MAX_LPC_PRECISIONS; iPrecision++)
+ done_lpcs[iPrecision] = 0;
+ }
+
+ ///
+ /// Calculate autocorrelation data and reflection coefficients.
+ /// Can be used to incrementaly compute coefficients for higher orders,
+ /// because it caches them.
+ ///
+ /// Maximum order
+ /// Samples pointer
+ /// Block size
+ /// Window function
+ public void GetReflection(int order, int* samples, int blocksize, double* window)
+ {
+ if (autocorr_order > order)
+ return;
+ fixed (double* reff = reflection_coeffs, autoc = autocorr_values)
+ {
+ lpc.compute_autocorr(samples, (uint)blocksize, (uint)autocorr_order, (uint)order, autoc, window);
+ lpc.compute_schur_reflection(autoc, (uint)order, reff);
+ autocorr_order = order + 1;
+ }
+ }
+
+ ///
+ /// Produces LPC coefficients from autocorrelation data.
+ ///
+ /// LPC coefficients buffer (for all orders)
+ public void ComputeLPC(double* lpcs)
+ {
+ fixed (double* reff = reflection_coeffs)
+ lpc.compute_lpc_coefs(null, (uint)autocorr_order - 1, reff, lpcs);
+ }
+
+ ///
+ /// Checks if an order is 'interesting'.
+ /// Lower orders are likely to be useful if next two reflection coefficients are small,
+ /// Higher orders are likely to be useful if reflection coefficient for that order is greater than 0.1 and the next one is not.
+ ///
+ ///
+ ///
+ public bool IsInterestingOrder(int order)
+ {
+ return (order > 4 && Math.Abs(reflection_coeffs[order - 1]) >= 0.10 && (order == autocorr_order - 1 || Math.Abs(reflection_coeffs[order]) < 0.10)) ||
+ (order < 6 && order < autocorr_order - 2 && reflection_coeffs[order + 1] * reflection_coeffs[order + 1] + reflection_coeffs[order] * reflection_coeffs[order] < 0.1);
+ }
+
+ double[] autocorr_values;
+ double[] reflection_coeffs;
+ int autocorr_order;
+
+ public uint[] done_lpcs;
+ }
+
}
diff --git a/CUETools.Flake/Program.cs b/CUETools.Flake/Program.cs
index 30b8081..f2f0a56 100644
--- a/CUETools.Flake/Program.cs
+++ b/CUETools.Flake/Program.cs
@@ -15,7 +15,7 @@ namespace CUETools.FlakeExe
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine();
- Console.WriteLine(" -0 .. -11 Compression level, default 5.");
+ Console.WriteLine(" -0 .. -11 Compression level, default 7.");
Console.WriteLine(" -o Output filename, or \"-\" for stdout, or nul.");
Console.WriteLine(" -p # Padding bytes.");
Console.WriteLine(" -q --quiet Quiet mode.");
diff --git a/CUETools.Processor/Processor.cs b/CUETools.Processor/Processor.cs
index 6ed3314..598e1fe 100644
--- a/CUETools.Processor/Processor.cs
+++ b/CUETools.Processor/Processor.cs
@@ -911,7 +911,7 @@ namespace CUETools.Processor
encoders = new CUEToolsUDCList();
#if !MONO
encoders.Add(new CUEToolsUDC("libFLAC", "flac", true, "0 1 2 3 4 5 6 7 8", "5", "FLACWriter"));
- encoders.Add(new CUEToolsUDC("libFlake", "flac", true, "0 1 2 3 4 5 6 7 8 9 10 11 12", "5", "FlakeWriter"));
+ encoders.Add(new CUEToolsUDC("libFlake", "flac", true, "0 1 2 3 4 5 6 7 8 9 10 11", "7", "FlakeWriter"));
encoders.Add(new CUEToolsUDC("libwavpack", "wv", true, "fast normal high high+", "normal", "WavPackWriter"));
encoders.Add(new CUEToolsUDC("MAC_SDK", "ape", true, "fast normal high extra insane", "high", "APEWriter"));
encoders.Add(new CUEToolsUDC("ttalib", "tta", true, "", "", "TTAWriter"));