From 2b7312e2618ad6ba83c3c17a93c377c51fa1fcc5 Mon Sep 17 00:00:00 2001 From: chudov Date: Fri, 28 Aug 2009 13:00:27 +0000 Subject: [PATCH] further Flake optimizations --- CUETools.Codecs.FLAKE/BitReader.cs | 2 +- CUETools.Codecs.FLAKE/BitWriter.cs | 101 +++++- CUETools.Codecs.FLAKE/Flake.cs | 189 +++++++++-- CUETools.Codecs.FLAKE/FlakeReader.cs | 208 ++++++------ CUETools.Codecs.FLAKE/FlakeWriter.cs | 480 +++++++++++---------------- CUETools.Codecs.FLAKE/lpc.cs | 74 +++++ CUETools.Flake/Program.cs | 2 +- CUETools.Processor/Processor.cs | 2 +- 8 files changed, 621 insertions(+), 437 deletions(-) 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"));