mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
further Flake optimizations
This commit is contained in:
@@ -32,7 +32,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
int _bitaccumulator;
|
int _bitaccumulator;
|
||||||
uint cache;
|
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,
|
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,
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
|||||||
@@ -110,6 +110,32 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assumes there's enough space, buffer != null and bits is in range 1..31
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bits"></param>
|
||||||
|
/// <param name="val"></param>
|
||||||
|
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)
|
public void write_utf8(int val)
|
||||||
{
|
{
|
||||||
write_utf8((uint)val);
|
write_utf8((uint)val);
|
||||||
@@ -150,23 +176,78 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
public void write_rice_signed(int k, int val)
|
public void write_rice_signed(int k, int val)
|
||||||
{
|
{
|
||||||
int v, q;
|
|
||||||
|
|
||||||
// convert signed to unsigned
|
// convert signed to unsigned
|
||||||
v = -2 * val - 1;
|
int v = -2 * val - 1;
|
||||||
v ^= (v >> 31);
|
v ^= (v >> 31);
|
||||||
|
|
||||||
// write quotient in unary
|
// write quotient in unary
|
||||||
q = (v >> k) + 1;
|
int q = (v >> k) + 1;
|
||||||
while (q > 31)
|
while (q + k > 31)
|
||||||
{
|
{
|
||||||
writebits(31, 0);
|
int b = Math.Min(q + k - 31, 31);
|
||||||
q -= 31;
|
writebits(b, 0);
|
||||||
|
q -= b;
|
||||||
}
|
}
|
||||||
writebits(q, 1);
|
|
||||||
|
|
||||||
// write write remainder in binary using 'k' bits
|
// write remainder in binary using 'k' bits
|
||||||
writebits(k, v & ((1 << k) - 1));
|
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()
|
public void flush()
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
public const int MAX_PARTITION_ORDER = 8;
|
public const int MAX_PARTITION_ORDER = 8;
|
||||||
public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER;
|
public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER;
|
||||||
|
|
||||||
|
public const uint UINT32_MAX = 0xffffffff;
|
||||||
|
|
||||||
public const int FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
|
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_STREAM_OFFSET_LEN = 64; /* bits */
|
||||||
public const int FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* 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)
|
public static int log2i(uint v)
|
||||||
{
|
{
|
||||||
int i;
|
//int i;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; }
|
if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; }
|
||||||
if (0 != (v & 0xff00)) { v >>= 8; n += 8; }
|
if (0 != (v & 0xff00)) { v >>= 8; n += 8; }
|
||||||
for (i = 2; i < 256; i <<= 1)
|
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;
|
// if (v >= i) n++;
|
||||||
}
|
// else break;
|
||||||
|
//}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,15 +125,36 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe struct RiceContext
|
unsafe class RiceContext
|
||||||
{
|
{
|
||||||
public int porder; /* partition order */
|
public RiceContext()
|
||||||
public fixed int rparams[Flake.MAX_PARTITIONS]; /* Rice parameters */
|
{
|
||||||
public fixed int esc_bps[Flake.MAX_PARTITIONS]; /* bps if using escape code */
|
rparams = new int[Flake.MAX_PARTITIONS];
|
||||||
|
esc_bps = new int[Flake.MAX_PARTITIONS];
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// partition order
|
||||||
|
/// </summary>
|
||||||
|
public int porder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rice parameters
|
||||||
|
/// </summary>
|
||||||
|
public int[] rparams;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// bps if using escape code
|
||||||
|
/// </summary>
|
||||||
|
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 SubframeType type;
|
||||||
public int order;
|
public int order;
|
||||||
public int* residual;
|
public int* residual;
|
||||||
@@ -139,31 +163,129 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
public int cbits;
|
public int cbits;
|
||||||
public int shift;
|
public int shift;
|
||||||
public fixed int coefs[lpc.MAX_LPC_ORDER];
|
public int[] coefs;
|
||||||
public int window;
|
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 FlacSubframe best;
|
||||||
public uint obits;
|
public uint obits;
|
||||||
public uint wbits;
|
public uint wbits;
|
||||||
public int* samples;
|
public int* samples;
|
||||||
public fixed uint done_lpcs[lpc.MAX_LPC_WINDOWS * lpc.MAX_LPC_PRECISIONS];
|
|
||||||
public uint done_fixed;
|
public uint done_fixed;
|
||||||
public fixed double reflection_coeffs[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_WINDOWS];
|
public LpcContext[] lpc_ctx;
|
||||||
public fixed double autocorr_values[(lpc.MAX_LPC_ORDER + 1) * lpc.MAX_LPC_WINDOWS];
|
|
||||||
public fixed int autocorr_orders[lpc.MAX_LPC_WINDOWS];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
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 blocksize;
|
||||||
public int bs_code0, bs_code1;
|
public int bs_code0, bs_code1;
|
||||||
public ChannelMode ch_mode;
|
public ChannelMode ch_mode;
|
||||||
public int ch_order0, ch_order1;
|
//public int ch_order0, ch_order1;
|
||||||
public byte crc8;
|
public byte crc8;
|
||||||
public FlacSubframeInfo* subframes;
|
public FlacSubframeInfo[] subframes;
|
||||||
public uint frame_count;
|
public uint frame_count;
|
||||||
public FlacSubframe current;
|
public FlacSubframe current;
|
||||||
public double* window_buffer;
|
public double* window_buffer;
|
||||||
@@ -185,11 +307,11 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
public enum PredictionType
|
public enum PredictionType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// verbatim
|
/// Verbatim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
None = 0,
|
None = 0,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fixed only
|
/// Fixed prediction only
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Fixed = 1,
|
Fixed = 1,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -199,11 +321,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exhaustive search
|
/// Exhaustive search
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Search = 3,
|
Search = 3
|
||||||
/// <summary>
|
|
||||||
/// Internal; Use prediction type from previous estimation
|
|
||||||
/// </summary>
|
|
||||||
Estimated = 4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum StereoMethod
|
public enum StereoMethod
|
||||||
@@ -249,45 +367,44 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
public enum MetadataType
|
public enum MetadataType
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block
|
/// <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_STREAMINFO = 0,
|
StreamInfo = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <A HREF="../format.html#metadata_block_padding">PADDING</A> block
|
/// <A HREF="../format.html#metadata_block_padding">PADDING</A> block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_PADDING = 1,
|
Padding = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <A HREF="../format.html#metadata_block_application">APPLICATION</A> block
|
/// <A HREF="../format.html#metadata_block_application">APPLICATION</A> block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_APPLICATION = 2,
|
Application = 2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block
|
/// <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_SEEKTABLE = 3,
|
Seektable = 3,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags)
|
/// <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
|
VorbisComment = 4,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block
|
/// <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_CUESHEET = 5,
|
CUESheet = 5,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <A HREF="../format.html#metadata_block_picture">PICTURE</A> block
|
/// <A HREF="../format.html#metadata_block_picture">PICTURE</A> block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_PICTURE = 6,
|
Picture = 6,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// marker to denote beginning of undefined type range; this number will increase as new metadata types are added
|
/// marker to denote beginning of undefined type range; this number will increase as new metadata types are added
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FLAC__METADATA_TYPE_UNDEFINED = 7
|
Undefined = 7
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
Crc8 crc8;
|
Crc8 crc8;
|
||||||
Crc16 crc16;
|
Crc16 crc16;
|
||||||
|
FlacFrame frame;
|
||||||
int channels;
|
int channels;
|
||||||
uint bits_per_sample;
|
uint bits_per_sample;
|
||||||
int sample_rate = 44100;
|
int sample_rate = 44100;
|
||||||
@@ -74,6 +75,8 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
_framesBuffer = new byte[0x20000];
|
_framesBuffer = new byte[0x20000];
|
||||||
decode_metadata();
|
decode_metadata();
|
||||||
|
|
||||||
|
frame = new FlacFrame(channels);
|
||||||
|
|
||||||
//max_frame_size = 16 + ((Flake.MAX_BLOCKSIZE * (int)(bits_per_sample * channels + 1) + 7) >> 3);
|
//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)
|
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;
|
bits_per_sample = _bits_per_sample;
|
||||||
samplesBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
samplesBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
||||||
residualBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
residualBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
||||||
|
frame = new FlacFrame(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close()
|
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;
|
int header_start = bitreader.Position;
|
||||||
|
|
||||||
if (bitreader.readbits(15) != 0x7FFC)
|
if (bitreader.readbits(15) != 0x7FFC)
|
||||||
throw new Exception("invalid frame");
|
throw new Exception("invalid frame");
|
||||||
uint vbs = bitreader.readbit();
|
uint vbs = bitreader.readbit();
|
||||||
frame->bs_code0 = (int) bitreader.readbits(4);
|
frame.bs_code0 = (int) bitreader.readbits(4);
|
||||||
uint sr_code0 = 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);
|
uint bps_code = bitreader.readbits(3);
|
||||||
if (Flake.flac_bitdepths[bps_code] != bits_per_sample)
|
if (Flake.flac_bitdepths[bps_code] != bits_per_sample)
|
||||||
throw new Exception("unsupported bps coding");
|
throw new Exception("unsupported bps coding");
|
||||||
uint t1 = bitreader.readbit(); // == 0?????
|
uint t1 = bitreader.readbit(); // == 0?????
|
||||||
if (t1 != 0)
|
if (t1 != 0)
|
||||||
throw new Exception("unsupported frame coding");
|
throw new Exception("unsupported frame coding");
|
||||||
frame->frame_count = bitreader.read_utf8();
|
frame.frame_count = bitreader.read_utf8();
|
||||||
|
|
||||||
// custom block size
|
// custom block size
|
||||||
if (frame->bs_code0 == 6)
|
if (frame.bs_code0 == 6)
|
||||||
{
|
{
|
||||||
frame->bs_code1 = (int)bitreader.readbits(8);
|
frame.bs_code1 = (int)bitreader.readbits(8);
|
||||||
frame->blocksize = frame->bs_code1 + 1;
|
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.bs_code1 = (int)bitreader.readbits(16);
|
||||||
frame->blocksize = frame->bs_code1 + 1;
|
frame.blocksize = frame.bs_code1 + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
frame->blocksize = Flake.flac_blocksizes[frame->bs_code0];
|
frame.blocksize = Flake.flac_blocksizes[frame.bs_code0];
|
||||||
|
|
||||||
// custom sample rate
|
// custom sample rate
|
||||||
if (sr_code0 < 4 || sr_code0 > 11)
|
if (sr_code0 < 4 || sr_code0 > 11)
|
||||||
@@ -329,62 +333,62 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
throw new Exception("invalid sample rate mode");
|
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)
|
if (frame_channels > 11)
|
||||||
throw new Exception("invalid channel mode");
|
throw new Exception("invalid channel mode");
|
||||||
if (frame_channels == 2 || frame_channels > 8) // Mid/Left/Right Side Stereo
|
if (frame_channels == 2 || frame_channels > 8) // Mid/Left/Right Side Stereo
|
||||||
frame_channels = 2;
|
frame_channels = 2;
|
||||||
else
|
else
|
||||||
frame->ch_mode = ChannelMode.NotStereo;
|
frame.ch_mode = ChannelMode.NotStereo;
|
||||||
if (frame_channels != channels)
|
if (frame_channels != channels)
|
||||||
throw new Exception("invalid channel mode");
|
throw new Exception("invalid channel mode");
|
||||||
|
|
||||||
// CRC-8 of frame header
|
// CRC-8 of frame header
|
||||||
byte crc = crc8.ComputeChecksum(bitreader.Buffer, header_start, bitreader.Position - header_start);
|
byte crc = crc8.ComputeChecksum(bitreader.Buffer, header_start, bitreader.Position - header_start);
|
||||||
frame->crc8 = (byte)bitreader.readbits(8);
|
frame.crc8 = (byte)bitreader.readbits(8);
|
||||||
if (frame->crc8 != crc)
|
if (frame.crc8 != crc)
|
||||||
throw new Exception("header crc mismatch");
|
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;
|
int obits = (int)frame.subframes[ch].obits;
|
||||||
frame->subframes[ch].best.residual[0] = bitreader.readbits_signed(obits);
|
frame.subframes[ch].best.residual[0] = bitreader.readbits_signed(obits);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void decode_subframe_verbatim(BitReader bitreader, FlacFrame* frame, int ch)
|
unsafe void decode_subframe_verbatim(BitReader bitreader, FlacFrame frame, int ch)
|
||||||
{
|
{
|
||||||
int obits = (int)frame->subframes[ch].obits;
|
int obits = (int)frame.subframes[ch].obits;
|
||||||
for (int i = 0; i < frame->blocksize; i++)
|
for (int i = 0; i < frame.blocksize; i++)
|
||||||
frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void decode_residual(BitReader bitreader, FlacFrame* frame, int ch)
|
unsafe void decode_residual(BitReader bitreader, FlacFrame frame, int ch)
|
||||||
{
|
{
|
||||||
// rice-encoded block
|
// rice-encoded block
|
||||||
uint coding_method = bitreader.readbits(2); // ????? == 0
|
uint coding_method = bitreader.readbits(2); // ????? == 0
|
||||||
if (coding_method != 0 && coding_method != 1) // if 1, then parameter length == 5 bits instead of 4
|
if (coding_method != 0 && coding_method != 1) // if 1, then parameter length == 5 bits instead of 4
|
||||||
throw new Exception("unsupported residual coding");
|
throw new Exception("unsupported residual coding");
|
||||||
// partition order
|
// partition order
|
||||||
frame->subframes[ch].best.rc.porder = (int)bitreader.readbits(4);
|
frame.subframes[ch].best.rc.porder = (int)bitreader.readbits(4);
|
||||||
if (frame->subframes[ch].best.rc.porder > 8)
|
if (frame.subframes[ch].best.rc.porder > 8)
|
||||||
throw new Exception("invalid partition order");
|
throw new Exception("invalid partition order");
|
||||||
int psize = frame->blocksize >> frame->subframes[ch].best.rc.porder;
|
int psize = frame.blocksize >> frame.subframes[ch].best.rc.porder;
|
||||||
int res_cnt = psize - frame->subframes[ch].best.order;
|
int res_cnt = psize - frame.subframes[ch].best.order;
|
||||||
|
|
||||||
int rice_len = 4 + (int)coding_method;
|
int rice_len = 4 + (int)coding_method;
|
||||||
// residual
|
// residual
|
||||||
int j = frame->subframes[ch].best.order;
|
int j = frame.subframes[ch].best.order;
|
||||||
int* r = frame->subframes[ch].best.residual + j;
|
int* r = frame.subframes[ch].best.residual + j;
|
||||||
for (int p = 0; p < (1 << frame->subframes[ch].best.rc.porder); p++)
|
for (int p = 0; p < (1 << frame.subframes[ch].best.rc.porder); p++)
|
||||||
{
|
{
|
||||||
if (p == 1) res_cnt = psize;
|
if (p == 1) res_cnt = psize;
|
||||||
int n = Math.Min(res_cnt, frame->blocksize - j);
|
int n = Math.Min(res_cnt, frame.blocksize - j);
|
||||||
|
|
||||||
int k = frame->subframes[ch].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)
|
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--)
|
for (int i = n; i > 0; i--)
|
||||||
*(r++) = bitreader.readbits_signed((int)k);
|
*(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
|
// warm-up samples
|
||||||
int obits = (int)frame->subframes[ch].obits;
|
int obits = (int)frame.subframes[ch].obits;
|
||||||
for (int i = 0; i < frame->subframes[ch].best.order; i++)
|
for (int i = 0; i < frame.subframes[ch].best.order; i++)
|
||||||
frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
||||||
|
|
||||||
// residual
|
// residual
|
||||||
decode_residual(bitreader, frame, ch);
|
decode_residual(bitreader, frame, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// warm-up samples
|
||||||
int obits = (int)frame->subframes[ch].obits;
|
int obits = (int)frame.subframes[ch].obits;
|
||||||
for (int i = 0; i < frame->subframes[ch].best.order; i++)
|
for (int i = 0; i < frame.subframes[ch].best.order; i++)
|
||||||
frame->subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
frame.subframes[ch].best.residual[i] = bitreader.readbits_signed(obits);
|
||||||
|
|
||||||
// LPC coefficients
|
// LPC coefficients
|
||||||
frame->subframes[ch].best.cbits = (int)bitreader.readbits(4) + 1; // lpc_precision
|
frame.subframes[ch].best.cbits = (int)bitreader.readbits(4) + 1; // lpc_precision
|
||||||
frame->subframes[ch].best.shift = bitreader.readbits_signed(5);
|
frame.subframes[ch].best.shift = bitreader.readbits_signed(5);
|
||||||
if (frame->subframes[ch].best.shift < 0)
|
if (frame.subframes[ch].best.shift < 0)
|
||||||
throw new Exception("negative shift");
|
throw new Exception("negative shift");
|
||||||
for (int i = 0; i < frame->subframes[ch].best.order; i++)
|
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);
|
frame.subframes[ch].best.coefs[i] = bitreader.readbits_signed(frame.subframes[ch].best.cbits);
|
||||||
|
|
||||||
// residual
|
// residual
|
||||||
decode_residual(bitreader, frame, ch);
|
decode_residual(bitreader, frame, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void decode_subframes(BitReader bitreader, FlacFrame* frame)
|
unsafe void decode_subframes(BitReader bitreader, FlacFrame frame)
|
||||||
{
|
{
|
||||||
fixed (int *r = residualBuffer, s = samplesBuffer)
|
fixed (int *r = residualBuffer, s = samplesBuffer)
|
||||||
for (int ch = 0; ch < channels; ch++)
|
for (int ch = 0; ch < channels; ch++)
|
||||||
@@ -437,37 +441,37 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
if (t1 != 0)
|
if (t1 != 0)
|
||||||
throw new Exception("unsupported subframe coding");
|
throw new Exception("unsupported subframe coding");
|
||||||
int type_code = (int)bitreader.readbits(6);
|
int type_code = (int)bitreader.readbits(6);
|
||||||
frame->subframes[ch].wbits = bitreader.readbit();
|
frame.subframes[ch].wbits = bitreader.readbit();
|
||||||
if (frame->subframes[ch].wbits != 0)
|
if (frame.subframes[ch].wbits != 0)
|
||||||
frame->subframes[ch].wbits += bitreader.read_unary();
|
frame.subframes[ch].wbits += bitreader.read_unary();
|
||||||
|
|
||||||
frame->subframes[ch].obits = bits_per_sample - frame->subframes[ch].wbits;
|
frame.subframes[ch].obits = bits_per_sample - frame.subframes[ch].wbits;
|
||||||
switch (frame->ch_mode)
|
switch (frame.ch_mode)
|
||||||
{
|
{
|
||||||
case ChannelMode.MidSide: frame->subframes[ch].obits += (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.LeftSide: frame.subframes[ch].obits += (uint)ch; break;
|
||||||
case ChannelMode.RightSide: frame->subframes[ch].obits += 1 - (uint)ch; break;
|
case ChannelMode.RightSide: frame.subframes[ch].obits += 1 - (uint)ch; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->subframes[ch].best.type = (SubframeType)type_code;
|
frame.subframes[ch].best.type = (SubframeType)type_code;
|
||||||
frame->subframes[ch].best.order = 0;
|
frame.subframes[ch].best.order = 0;
|
||||||
|
|
||||||
if ((type_code & (uint)SubframeType.LPC) != 0)
|
if ((type_code & (uint)SubframeType.LPC) != 0)
|
||||||
{
|
{
|
||||||
frame->subframes[ch].best.order = (type_code - (int)SubframeType.LPC) + 1;
|
frame.subframes[ch].best.order = (type_code - (int)SubframeType.LPC) + 1;
|
||||||
frame->subframes[ch].best.type = SubframeType.LPC;
|
frame.subframes[ch].best.type = SubframeType.LPC;
|
||||||
}
|
}
|
||||||
else if ((type_code & (uint)SubframeType.Fixed) != 0)
|
else if ((type_code & (uint)SubframeType.Fixed) != 0)
|
||||||
{
|
{
|
||||||
frame->subframes[ch].best.order = (type_code - (int)SubframeType.Fixed);
|
frame.subframes[ch].best.order = (type_code - (int)SubframeType.Fixed);
|
||||||
frame->subframes[ch].best.type = SubframeType.Fixed;
|
frame.subframes[ch].best.type = SubframeType.Fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->subframes[ch].best.residual = r + ch * Flake.MAX_BLOCKSIZE;
|
frame.subframes[ch].best.residual = r + ch * Flake.MAX_BLOCKSIZE;
|
||||||
frame->subframes[ch].samples = s + ch * Flake.MAX_BLOCKSIZE;
|
frame.subframes[ch].samples = s + ch * Flake.MAX_BLOCKSIZE;
|
||||||
|
|
||||||
// subframe
|
// subframe
|
||||||
switch (frame->subframes[ch].best.type)
|
switch (frame.subframes[ch].best.type)
|
||||||
{
|
{
|
||||||
case SubframeType.Constant:
|
case SubframeType.Constant:
|
||||||
decode_subframe_constant(bitreader, frame, ch);
|
decode_subframe_constant(bitreader, frame, ch);
|
||||||
@@ -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);
|
Flake.memcpy(sub.samples, sub.best.residual, sub.best.order);
|
||||||
int* data = sub->samples + sub->best.order;
|
int* data = sub.samples + sub.best.order;
|
||||||
int* residual = sub->best.residual + sub->best.order;
|
int* residual = sub.best.residual + sub.best.order;
|
||||||
int data_len = frame->blocksize - sub->best.order;
|
int data_len = frame.blocksize - sub.best.order;
|
||||||
int s0, s1, s2;
|
int s0, s1, s2;
|
||||||
switch (sub->best.order)
|
switch (sub.best.order)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
Flake.memcpy(data, residual, data_len);
|
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;
|
ulong csum = 0;
|
||||||
for (int i = sub->best.order; i > 0; i--)
|
fixed (int* coefs = sub.best.coefs)
|
||||||
csum += (ulong)Math.Abs(sub->best.coefs[i - 1]);
|
{
|
||||||
if ((csum << (int)sub->obits) >= 1UL << 32)
|
for (int i = sub.best.order; i > 0; i--)
|
||||||
lpc.decode_residual_long(sub->best.residual, sub->samples, frame->blocksize, sub->best.order, sub->best.coefs, sub->best.shift);
|
csum += (ulong)Math.Abs(coefs[i - 1]);
|
||||||
else
|
if ((csum << (int)sub.obits) >= 1UL << 32)
|
||||||
lpc.decode_residual(sub->best.residual, sub->samples, frame->blocksize, sub->best.order, sub->best.coefs, sub->best.shift);
|
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++)
|
for (int ch = 0; ch < channels; ch++)
|
||||||
{
|
{
|
||||||
switch (frame->subframes[ch].best.type)
|
switch (frame.subframes[ch].best.type)
|
||||||
{
|
{
|
||||||
case SubframeType.Constant:
|
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;
|
break;
|
||||||
case SubframeType.Verbatim:
|
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;
|
break;
|
||||||
case SubframeType.Fixed:
|
case SubframeType.Fixed:
|
||||||
restore_samples_fixed(frame, ch);
|
restore_samples_fixed(frame, ch);
|
||||||
@@ -564,24 +571,24 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
restore_samples_lpc(frame, ch);
|
restore_samples_lpc(frame, ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (frame->subframes[ch].wbits != 0)
|
if (frame.subframes[ch].wbits != 0)
|
||||||
{
|
{
|
||||||
int* s = frame->subframes[ch].samples;
|
int* s = frame.subframes[ch].samples;
|
||||||
int x = (int) frame->subframes[ch].wbits;
|
int x = (int) frame.subframes[ch].wbits;
|
||||||
for (int i = frame->blocksize; i > 0; i--)
|
for (int i = frame.blocksize; i > 0; i--)
|
||||||
*(s++) <<= x;
|
*(s++) <<= x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (frame->ch_mode != ChannelMode.NotStereo)
|
if (frame.ch_mode != ChannelMode.NotStereo)
|
||||||
{
|
{
|
||||||
int* l = frame->subframes[0].samples;
|
int* l = frame.subframes[0].samples;
|
||||||
int* r = frame->subframes[1].samples;
|
int* r = frame.subframes[1].samples;
|
||||||
switch (frame->ch_mode)
|
switch (frame.ch_mode)
|
||||||
{
|
{
|
||||||
case ChannelMode.LeftRight:
|
case ChannelMode.LeftRight:
|
||||||
break;
|
break;
|
||||||
case ChannelMode.MidSide:
|
case ChannelMode.MidSide:
|
||||||
for (int i = frame->blocksize; i > 0; i--)
|
for (int i = frame.blocksize; i > 0; i--)
|
||||||
{
|
{
|
||||||
int mid = *l;
|
int mid = *l;
|
||||||
int side = *r;
|
int side = *r;
|
||||||
@@ -592,14 +599,14 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ChannelMode.LeftSide:
|
case ChannelMode.LeftSide:
|
||||||
for (int i = frame->blocksize; i > 0; i--)
|
for (int i = frame.blocksize; i > 0; i--)
|
||||||
{
|
{
|
||||||
int _l = *(l++), _r = *r;
|
int _l = *(l++), _r = *r;
|
||||||
*(r++) = _l - _r;
|
*(r++) = _l - _r;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ChannelMode.RightSide:
|
case ChannelMode.RightSide:
|
||||||
for (int i = frame->blocksize; i > 0; i--)
|
for (int i = frame.blocksize; i > 0; i--)
|
||||||
*(l++) += *(r++);
|
*(l++) += *(r++);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -611,16 +618,13 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
fixed (byte* buf = buffer)
|
fixed (byte* buf = buffer)
|
||||||
{
|
{
|
||||||
BitReader bitreader = new BitReader(buf, pos, len);
|
BitReader bitreader = new BitReader(buf, pos, len);
|
||||||
FlacFrame frame;
|
decode_frame_header(bitreader, frame);
|
||||||
FlacSubframeInfo* subframes = stackalloc FlacSubframeInfo[channels];
|
decode_subframes(bitreader, frame);
|
||||||
frame.subframes = subframes;
|
|
||||||
decode_frame_header(bitreader, &frame);
|
|
||||||
decode_subframes(bitreader, &frame);
|
|
||||||
bitreader.flush();
|
bitreader.flush();
|
||||||
ushort crc = crc16.ComputeChecksum(bitreader.Buffer + pos, bitreader.Position - pos);
|
ushort crc = crc16.ComputeChecksum(bitreader.Buffer + pos, bitreader.Position - pos);
|
||||||
if (crc != bitreader.readbits(16))
|
if (crc != bitreader.readbits(16))
|
||||||
throw new Exception("frame crc mismatch");
|
throw new Exception("frame crc mismatch");
|
||||||
restore_samples(&frame);
|
restore_samples(frame);
|
||||||
_samplesInBuffer = (uint)frame.blocksize;
|
_samplesInBuffer = (uint)frame.blocksize;
|
||||||
return bitreader.Position - pos;
|
return bitreader.Position - pos;
|
||||||
}
|
}
|
||||||
@@ -705,7 +709,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
MetadataType type = (MetadataType)bitreader.readbits(7);
|
MetadataType type = (MetadataType)bitreader.readbits(7);
|
||||||
int len = (int)bitreader.readbits(24);
|
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_MIN_BLOCK_SIZE_LEN = 16; /* bits */
|
||||||
const int FLAC__STREAM_METADATA_STREAMINFO_MAX_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);
|
_sampleCount = bitreader.readbits64(FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN);
|
||||||
bitreader.skipbits(FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_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;
|
int num_entries = len / 18;
|
||||||
seek_table = new SeekPoint[num_entries];
|
seek_table = new SeekPoint[num_entries];
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ using System.IO;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
//using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using CUETools.Codecs;
|
using CUETools.Codecs;
|
||||||
|
|
||||||
namespace CUETools.Codecs.FLAKE
|
namespace CUETools.Codecs.FLAKE
|
||||||
@@ -81,7 +81,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
double[] windowBuffer;
|
double[] windowBuffer;
|
||||||
int samplesInBuffer = 0;
|
int samplesInBuffer = 0;
|
||||||
|
|
||||||
int _compressionLevel = 5;
|
int _compressionLevel = 7;
|
||||||
int _blocksize = 0;
|
int _blocksize = 0;
|
||||||
int _totalSize = 0;
|
int _totalSize = 0;
|
||||||
int _windowsize = 0, _windowcount = 0;
|
int _windowsize = 0, _windowcount = 0;
|
||||||
@@ -90,6 +90,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
Crc16 crc16;
|
Crc16 crc16;
|
||||||
MD5 md5;
|
MD5 md5;
|
||||||
|
|
||||||
|
FlacFrame frame;
|
||||||
FlakeReader verify;
|
FlakeReader verify;
|
||||||
|
|
||||||
SeekPoint[] seek_table;
|
SeekPoint[] seek_table;
|
||||||
@@ -122,6 +123,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
crc8 = new Crc8();
|
crc8 = new Crc8();
|
||||||
crc16 = new Crc16();
|
crc16 = new Crc16();
|
||||||
|
frame = new FlacFrame(channels * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TotalSize
|
public int TotalSize
|
||||||
@@ -159,10 +161,10 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
//static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime, out long lpExitTime, out long lpKernelTime, out long lpUserTime);
|
static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime, out long lpExitTime, out long lpKernelTime, out long lpUserTime);
|
||||||
//[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
//static extern IntPtr GetCurrentThread();
|
static extern IntPtr GetCurrentThread();
|
||||||
|
|
||||||
void DoClose()
|
void DoClose()
|
||||||
{
|
{
|
||||||
@@ -194,9 +196,9 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
inited = false;
|
inited = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//long fake, KernelStart, UserStart;
|
long fake, KernelStart, UserStart;
|
||||||
//GetThreadTimes(GetCurrentThread(), out fake, out fake, out KernelStart, out UserStart);
|
GetThreadTimes(GetCurrentThread(), out fake, out fake, out KernelStart, out UserStart);
|
||||||
//_userProcessorTime = new TimeSpan(UserStart);
|
_userProcessorTime = new TimeSpan(UserStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
@@ -468,43 +470,13 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
return (uint)shift;
|
return (uint)shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void init_frame(FlacFrame * frame, int bs)
|
/// <summary>
|
||||||
{
|
|
||||||
//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
|
/// Copy channel-interleaved input samples into separate subframes
|
||||||
unsafe void copy_samples(int[,] samples, int pos, int block)
|
/// </summary>
|
||||||
|
/// <param name="samples"></param>
|
||||||
|
/// <param name="pos"></param>
|
||||||
|
/// <param name="block"></param>
|
||||||
|
unsafe void copy_samples(int[,] samples, int pos, int block)
|
||||||
{
|
{
|
||||||
fixed (int* fsamples = samplesBuffer, src = &samples[pos, 0])
|
fixed (int* fsamples = samplesBuffer, src = &samples[pos, 0])
|
||||||
{
|
{
|
||||||
@@ -562,10 +534,10 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
return k_opt;
|
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* s = frame.subframes[ch].samples;
|
||||||
int n = frame->blocksize;
|
int n = frame.blocksize;
|
||||||
ulong sum = 0;
|
ulong sum = 0;
|
||||||
for (int i = 2; i < n; i++)
|
for (int i = 2; i < n; i++)
|
||||||
sum += (ulong)Math.Abs(s[i] - 2 * s[i - 1] + s[i - 2]);
|
sum += (ulong)Math.Abs(s[i] - 2 * s[i - 1] + s[i - 2]);
|
||||||
@@ -574,23 +546,6 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
return nbits;
|
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)
|
unsafe static void channel_decorrelation(int* leftS, int* rightS, int *leftM, int *rightM, int blocksize)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < blocksize; i++)
|
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(ref RiceContext rc, int porder, uint* sums, uint n, uint pred_order)
|
||||||
|
|
||||||
static unsafe uint calc_optimal_rice_params(RiceContext* rc, int porder, uint* sums, uint n, uint pred_order)
|
|
||||||
{
|
{
|
||||||
uint part = (1U << porder);
|
uint part = (1U << porder);
|
||||||
uint all_bits = 0;
|
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);
|
uint cnt = (n >> porder);
|
||||||
for (uint i = 1; i < part; i++)
|
for (uint i = 1; i < part; i++)
|
||||||
{
|
{
|
||||||
uint nbits;
|
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 += nbits;
|
||||||
}
|
}
|
||||||
all_bits += (4 * part);
|
all_bits += (4 * part);
|
||||||
rc->porder = porder;
|
rc.porder = porder;
|
||||||
return all_bits;
|
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* udata = stackalloc uint[(int)n];
|
||||||
uint* sums = stackalloc uint[(pmax + 1) * Flake.MAX_PARTITIONS];
|
uint* sums = stackalloc uint[(pmax + 1) * Flake.MAX_PARTITIONS];
|
||||||
//uint* bits = stackalloc uint[Flake.MAX_PARTITION_ORDER];
|
//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);
|
calc_sums(pmin, pmax, udata, n, pred_order, sums);
|
||||||
|
|
||||||
int opt_porder = pmin;
|
int opt_porder = pmin;
|
||||||
uint opt_bits = UINT32_MAX;
|
uint opt_bits = Flake.UINT32_MAX;
|
||||||
for (int i = pmin; i <= pmax; i++)
|
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)
|
if (bits <= opt_bits)
|
||||||
{
|
{
|
||||||
opt_porder = i;
|
opt_porder = i;
|
||||||
opt_bits = bits;
|
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;
|
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)
|
int* data, int n, int pred_order, uint bps)
|
||||||
{
|
{
|
||||||
pmin = get_max_p_order(pmin, n, pred_order);
|
pmin = get_max_p_order(pmin, n, pred_order);
|
||||||
pmax = get_max_p_order(pmax, n, pred_order);
|
pmax = get_max_p_order(pmax, n, pred_order);
|
||||||
uint bits = (uint)pred_order * bps + 6;
|
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;
|
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)
|
int* data, int n, int pred_order, uint bps, uint precision)
|
||||||
{
|
{
|
||||||
pmin = get_max_p_order(pmin, n, pred_order);
|
pmin = get_max_p_order(pmin, n, pred_order);
|
||||||
pmax = get_max_p_order(pmax, 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;
|
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;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void choose_best_subframe(FlacFrame* frame, int ch)
|
unsafe void encode_residual_lpc_sub(FlacFrame frame, double * lpcs, int iWindow, int order, 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)
|
|
||||||
{
|
{
|
||||||
// select LPC precision based on block size
|
// select LPC precision based on block size
|
||||||
uint lpc_precision;
|
uint lpc_precision;
|
||||||
if (frame->blocksize <= 192) lpc_precision = 7U;
|
if (frame.blocksize <= 192) lpc_precision = 7U;
|
||||||
else if (frame->blocksize <= 384) lpc_precision = 8U;
|
else if (frame.blocksize <= 384) lpc_precision = 8U;
|
||||||
else if (frame->blocksize <= 576) lpc_precision = 9U;
|
else if (frame.blocksize <= 576) lpc_precision = 9U;
|
||||||
else if (frame->blocksize <= 1152) lpc_precision = 10U;
|
else if (frame.blocksize <= 1152) lpc_precision = 10U;
|
||||||
else if (frame->blocksize <= 2304) lpc_precision = 11U;
|
else if (frame.blocksize <= 2304) lpc_precision = 11U;
|
||||||
else if (frame->blocksize <= 4608) lpc_precision = 12U;
|
else if (frame.blocksize <= 4608) lpc_precision = 12U;
|
||||||
else if (frame->blocksize <= 8192) lpc_precision = 13U;
|
else if (frame.blocksize <= 8192) lpc_precision = 13U;
|
||||||
else if (frame->blocksize <= 16384) lpc_precision = 14U;
|
else if (frame.blocksize <= 16384) lpc_precision = 14U;
|
||||||
else lpc_precision = 15;
|
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++)
|
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
|
// 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;
|
uint cbits = lpc_precision + (uint)i_precision;
|
||||||
|
|
||||||
frame->current.type = SubframeType.LPC;
|
frame.current.type = SubframeType.LPC;
|
||||||
frame->current.order = order;
|
frame.current.order = order;
|
||||||
frame->current.window = iWindow;
|
frame.current.window = iWindow;
|
||||||
|
|
||||||
lpc.quantize_lpc_coefs(lpcs + (frame->current.order - 1) * lpc.MAX_LPC_ORDER,
|
fixed (int* coefs = frame.current.coefs)
|
||||||
frame->current.order, cbits, frame->current.coefs, out frame->current.shift);
|
{
|
||||||
|
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)
|
if (frame.current.shift < 0 || frame.current.shift > 15)
|
||||||
throw new Exception("negative shift");
|
throw new Exception("negative shift");
|
||||||
|
|
||||||
ulong csum = 0;
|
ulong csum = 0;
|
||||||
for (int i = frame->current.order; i > 0; i--)
|
for (int i = frame.current.order; i > 0; i--)
|
||||||
csum += (ulong)Math.Abs(frame->current.coefs[i - 1]);
|
csum += (ulong)Math.Abs(coefs[i - 1]);
|
||||||
|
|
||||||
if ((csum << (int)frame->subframes[ch].obits) >= 1UL << 32)
|
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);
|
lpc.encode_residual_long(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift);
|
||||||
else
|
else
|
||||||
lpc.encode_residual(frame->current.residual, frame->subframes[ch].samples, frame->blocksize, frame->current.order, frame->current.coefs, frame->current.shift);
|
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;
|
return; // already calculated;
|
||||||
|
|
||||||
frame->current.order = order;
|
frame.current.order = order;
|
||||||
frame->current.type = SubframeType.Fixed;
|
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.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.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)) ||
|
int* smp = frame.subframes[ch].samples;
|
||||||
(order < 6 && order < max_order - 1 && reff[order + 1] * reff[order + 1] + reff[order] * reff[order] < 0.1);
|
int i, n = frame.blocksize;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
// save best.window, because we can overwrite it later with fixed frame
|
// 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
|
// CONSTANT
|
||||||
for (i = 1; i < n; i++)
|
for (i = 1; i < n; i++)
|
||||||
@@ -878,16 +807,16 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
if (i == n)
|
if (i == n)
|
||||||
{
|
{
|
||||||
frame->subframes[ch].best.type = SubframeType.Constant;
|
frame.subframes[ch].best.type = SubframeType.Constant;
|
||||||
frame->subframes[ch].best.residual[0] = smp[0];
|
frame.subframes[ch].best.residual[0] = smp[0];
|
||||||
frame->subframes[ch].best.size = frame->subframes[ch].obits;
|
frame.subframes[ch].best.size = frame.subframes[ch].obits;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// VERBATIM
|
// VERBATIM
|
||||||
frame->current.type = SubframeType.Verbatim;
|
frame.current.type = SubframeType.Verbatim;
|
||||||
frame->current.size = frame->subframes[ch].obits * (uint)frame->blocksize;
|
frame.current.size = frame.subframes[ch].obits * (uint)frame.blocksize;
|
||||||
choose_best_subframe(frame, ch);
|
frame.ChooseBestSubframe(ch);
|
||||||
|
|
||||||
if (n < 5 || predict == PredictionType.None)
|
if (n < 5 || predict == PredictionType.None)
|
||||||
return;
|
return;
|
||||||
@@ -896,7 +825,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
if (predict == PredictionType.Fixed ||
|
if (predict == PredictionType.Fixed ||
|
||||||
(predict == PredictionType.Search && pass != 1) ||
|
(predict == PredictionType.Search && pass != 1) ||
|
||||||
//predict == PredictionType.Search ||
|
//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)
|
n <= eparams.max_prediction_order)
|
||||||
{
|
{
|
||||||
int max_fixed_order = Math.Min(eparams.max_fixed_order, 4);
|
int max_fixed_order = Math.Min(eparams.max_fixed_order, 4);
|
||||||
@@ -911,10 +840,10 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
(predict == PredictionType.Levinson ||
|
(predict == PredictionType.Levinson ||
|
||||||
predict == PredictionType.Search)
|
predict == PredictionType.Search)
|
||||||
//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 min_order = eparams.min_prediction_order;
|
||||||
int max_order = eparams.max_prediction_order;
|
int max_order = eparams.max_prediction_order;
|
||||||
|
|
||||||
@@ -923,9 +852,10 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
if (pass == 2 && iWindow != best_window)
|
if (pass == 2 && iWindow != best_window)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
double* reff = get_reflection_coeffs(frame, ch, max_order, iWindow);
|
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
|
||||||
double* lpcs = stackalloc double[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER];
|
|
||||||
lpc.compute_lpc_coefs(null, (uint)max_order, reff, lpcs);
|
lpc_ctx.GetReflection(max_order, smp, n, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2);
|
||||||
|
lpc_ctx.ComputeLPC(lpcs);
|
||||||
|
|
||||||
switch (omethod)
|
switch (omethod)
|
||||||
{
|
{
|
||||||
@@ -939,7 +869,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for (i = max_order; i >= min_order && found < eparams.estimation_depth; i--)
|
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);
|
encode_residual_lpc_sub(frame, lpcs, iWindow, i, ch);
|
||||||
found++;
|
found++;
|
||||||
@@ -953,7 +883,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for (i = min_order; i <= max_order && found < eparams.estimation_depth; i++)
|
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);
|
encode_residual_lpc_sub(frame, lpcs, iWindow, i, ch);
|
||||||
found++;
|
found++;
|
||||||
@@ -981,12 +911,12 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
if (i < max_order)
|
if (i < max_order)
|
||||||
encode_residual_lpc_sub(frame, lpcs, iWindow, i, ch);
|
encode_residual_lpc_sub(frame, lpcs, iWindow, i, ch);
|
||||||
// if found a good order, try to search around it
|
// 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)
|
// log search (written by Michael Niedermayer for FFmpeg)
|
||||||
for (int step = lpc.MAX_LPC_ORDER; step > 0; step >>= 1)
|
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)
|
if (step <= (last + 1) / 2)
|
||||||
for (i = last - step; i <= last + step; i += step)
|
for (i = last - step; i <= last + step; i += step)
|
||||||
if (i >= min_order && i <= max_order)
|
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(15, 0x7FFC);
|
||||||
bitwriter.writebits(1, eparams.variable_block_size > 0 ? 1 : 0);
|
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);
|
bitwriter.writebits(4, sr_code0);
|
||||||
if (frame->ch_mode == ChannelMode.NotStereo)
|
if (frame.ch_mode == ChannelMode.NotStereo)
|
||||||
bitwriter.writebits(4, ch_code);
|
bitwriter.writebits(4, ch_code);
|
||||||
else
|
else
|
||||||
bitwriter.writebits(4, (int) frame->ch_mode);
|
bitwriter.writebits(4, (int) frame.ch_mode);
|
||||||
bitwriter.writebits(3, bps_code);
|
bitwriter.writebits(3, bps_code);
|
||||||
bitwriter.writebits(1, 0);
|
bitwriter.writebits(1, 0);
|
||||||
bitwriter.write_utf8(frame_count);
|
bitwriter.write_utf8(frame_count);
|
||||||
|
|
||||||
// custom block size
|
// custom block size
|
||||||
if (frame->bs_code1 >= 0)
|
if (frame.bs_code1 >= 0)
|
||||||
{
|
{
|
||||||
if (frame->bs_code1 < 256)
|
if (frame.bs_code1 < 256)
|
||||||
bitwriter.writebits(8, frame->bs_code1);
|
bitwriter.writebits(8, frame.bs_code1);
|
||||||
else
|
else
|
||||||
bitwriter.writebits(16, frame->bs_code1);
|
bitwriter.writebits(16, frame.bs_code1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// custom sample rate
|
// custom sample rate
|
||||||
@@ -1039,100 +969,97 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
bitwriter.writebits(8, crc);
|
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
|
// rice-encoded block
|
||||||
bitwriter.writebits(2, 0);
|
bitwriter.writebits(2, 0);
|
||||||
|
|
||||||
// partition order
|
// partition order
|
||||||
int porder = sub->best.rc.porder;
|
int porder = sub.best.rc.porder;
|
||||||
int psize = frame->blocksize >> porder;
|
int psize = frame.blocksize >> porder;
|
||||||
//assert(porder >= 0);
|
//assert(porder >= 0);
|
||||||
bitwriter.writebits(4, porder);
|
bitwriter.writebits(4, porder);
|
||||||
int res_cnt = psize - sub->best.order;
|
int res_cnt = psize - sub.best.order;
|
||||||
|
|
||||||
// residual
|
// residual
|
||||||
int j = sub->best.order;
|
int j = sub.best.order;
|
||||||
for (int p = 0; p < (1 << porder); p++)
|
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);
|
bitwriter.writebits(4, k);
|
||||||
if (p == 1) res_cnt = psize;
|
if (p == 1) res_cnt = psize;
|
||||||
if (k == 0)
|
int cnt = Math.Min(res_cnt, frame.blocksize - j);
|
||||||
for (int i = 0; i < res_cnt && j < frame->blocksize; i++, j++)
|
bitwriter.write_rice_block_signed(k, sub.best.residual + j, cnt);
|
||||||
bitwriter.write_unary_signed(sub->best.residual[j]);
|
j += cnt;
|
||||||
else
|
|
||||||
for (int i = 0; i < res_cnt && j < frame->blocksize; i++, j++)
|
|
||||||
bitwriter.write_rice_signed(k, sub->best.residual[j]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void
|
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
|
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++)
|
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.
|
// Don't use residual here, because we don't copy samples to residual for verbatim frames.
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void
|
unsafe void
|
||||||
output_subframe_fixed(FlacFrame* frame, BitWriter bitwriter, FlacSubframeInfo* sub)
|
output_subframe_fixed(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub)
|
||||||
{
|
{
|
||||||
// warm-up samples
|
// warm-up samples
|
||||||
for (int i = 0; i < sub->best.order; i++)
|
for (int i = 0; i < sub.best.order; i++)
|
||||||
bitwriter.writebits_signed(sub->obits, sub->best.residual[i]);
|
bitwriter.writebits_signed(sub.obits, sub.best.residual[i]);
|
||||||
|
|
||||||
// residual
|
// residual
|
||||||
output_residual(frame, bitwriter, sub);
|
output_residual(frame, bitwriter, sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void
|
unsafe void
|
||||||
output_subframe_lpc(FlacFrame* frame, BitWriter bitwriter, FlacSubframeInfo* sub)
|
output_subframe_lpc(FlacFrame frame, BitWriter bitwriter, FlacSubframeInfo sub)
|
||||||
{
|
{
|
||||||
// warm-up samples
|
// warm-up samples
|
||||||
for (int i = 0; i < sub->best.order; i++)
|
for (int i = 0; i < sub.best.order; i++)
|
||||||
bitwriter.writebits_signed(sub->obits, sub->best.residual[i]);
|
bitwriter.writebits_signed(sub.obits, sub.best.residual[i]);
|
||||||
|
|
||||||
// LPC coefficients
|
// LPC coefficients
|
||||||
int cbits = 1;
|
int cbits = 1;
|
||||||
for (int i = 0; i < sub->best.order; i++)
|
for (int i = 0; i < sub.best.order; i++)
|
||||||
while (cbits < 16 && sub->best.coefs[i] != (sub->best.coefs[i] << (32 - cbits)) >> (32 - cbits))
|
while (cbits < 16 && sub.best.coefs[i] != (sub.best.coefs[i] << (32 - cbits)) >> (32 - cbits))
|
||||||
cbits++;
|
cbits++;
|
||||||
bitwriter.writebits(4, cbits - 1);
|
bitwriter.writebits(4, cbits - 1);
|
||||||
bitwriter.writebits_signed(5, sub->best.shift);
|
bitwriter.writebits_signed(5, sub.best.shift);
|
||||||
for (int i = 0; i < sub->best.order; i++)
|
for (int i = 0; i < sub.best.order; i++)
|
||||||
bitwriter.writebits_signed(cbits, sub->best.coefs[i]);
|
bitwriter.writebits_signed(cbits, sub.best.coefs[i]);
|
||||||
|
|
||||||
// residual
|
// residual
|
||||||
output_residual(frame, bitwriter, sub);
|
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++)
|
for (int ch = 0; ch < channels; ch++)
|
||||||
{
|
{
|
||||||
FlacSubframeInfo* sub = frame->subframes + ch;
|
FlacSubframeInfo sub = frame.subframes[ch];
|
||||||
// subframe header
|
// subframe header
|
||||||
int type_code = (int) sub->best.type;
|
int type_code = (int) sub.best.type;
|
||||||
if (sub->best.type == SubframeType.Fixed)
|
if (sub.best.type == SubframeType.Fixed)
|
||||||
type_code |= sub->best.order;
|
type_code |= sub.best.order;
|
||||||
if (sub->best.type == SubframeType.LPC)
|
if (sub.best.type == SubframeType.LPC)
|
||||||
type_code |= sub->best.order - 1;
|
type_code |= sub.best.order - 1;
|
||||||
bitwriter.writebits(1, 0);
|
bitwriter.writebits(1, 0);
|
||||||
bitwriter.writebits(6, type_code);
|
bitwriter.writebits(6, type_code);
|
||||||
bitwriter.writebits(1, sub->wbits != 0 ? 1 : 0);
|
bitwriter.writebits(1, sub.wbits != 0 ? 1 : 0);
|
||||||
if (sub->wbits > 0)
|
if (sub.wbits > 0)
|
||||||
bitwriter.writebits((int)sub->wbits, 1);
|
bitwriter.writebits((int)sub.wbits, 1);
|
||||||
|
|
||||||
// subframe
|
// subframe
|
||||||
switch (sub->best.type)
|
switch (sub.best.type)
|
||||||
{
|
{
|
||||||
case SubframeType.Constant:
|
case SubframeType.Constant:
|
||||||
output_subframe_constant(frame, bitwriter, sub);
|
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);
|
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_prediction_order = eparams.max_prediction_order;
|
||||||
int max_fixed_order = eparams.max_fixed_order;
|
int max_fixed_order = eparams.max_fixed_order;
|
||||||
@@ -1230,12 +1157,12 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
eparams.estimation_depth = estimation_depth;
|
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);
|
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)
|
if (_windowcount > 1)
|
||||||
{
|
{
|
||||||
@@ -1245,7 +1172,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 0);
|
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;
|
int subframes = do_midside ? channels * 2 : channels;
|
||||||
|
|
||||||
@@ -1253,7 +1180,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
{
|
{
|
||||||
case StereoMethod.Estimate:
|
case StereoMethod.Estimate:
|
||||||
for (int ch = 0; ch < subframes; ch++)
|
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;
|
break;
|
||||||
case StereoMethod.Evaluate:
|
case StereoMethod.Evaluate:
|
||||||
for (int ch = 0; ch < subframes; ch++)
|
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)
|
if (do_midside)
|
||||||
{
|
{
|
||||||
uint bitsBest = UINT32_MAX;
|
uint bitsBest = Flake.UINT32_MAX;
|
||||||
ChannelMode modeBest = ChannelMode.LeftRight;
|
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;
|
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;
|
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;
|
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;
|
modeBest = ChannelMode.LeftRight;
|
||||||
}
|
}
|
||||||
frame->ch_mode = modeBest;
|
frame.ch_mode = modeBest;
|
||||||
return total + bitsBest;
|
return total + bitsBest;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ch = 0; ch < channels; ch++)
|
for (int ch = 0; ch < channels; ch++)
|
||||||
total += frame->subframes[ch].best.size;
|
total += frame.subframes[ch].best.size;
|
||||||
return total;
|
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)
|
switch (eparams.stereo_method)
|
||||||
{
|
{
|
||||||
case StereoMethod.Estimate:
|
case StereoMethod.Estimate:
|
||||||
for (int ch = 0; ch < channels; ch++)
|
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);
|
encode_residual_onepass(frame, ch);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1369,16 +1282,11 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
unsafe int encode_frame(out int size)
|
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 (int* s = samplesBuffer, r = residualBuffer)
|
||||||
fixed (double* window = windowBuffer)
|
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)
|
if (frame.blocksize != _windowsize && frame.blocksize > 4)
|
||||||
{
|
{
|
||||||
_windowsize = frame.blocksize;
|
_windowsize = frame.blocksize;
|
||||||
@@ -1397,11 +1305,11 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
frame.current.residual = r + channels * Flake.MAX_BLOCKSIZE;
|
frame.current.residual = r + channels * Flake.MAX_BLOCKSIZE;
|
||||||
frame.ch_mode = channels != 2 ? ChannelMode.NotStereo : ChannelMode.LeftRight;
|
frame.ch_mode = channels != 2 ? ChannelMode.NotStereo : ChannelMode.LeftRight;
|
||||||
for (int ch = 0; ch < channels; ch++)
|
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));
|
bits_per_sample, get_wasted_bits(s + ch * Flake.MAX_BLOCKSIZE, frame.blocksize));
|
||||||
|
|
||||||
for (int ch = 0; ch < channels; ch++)
|
for (int ch = 0; ch < channels; ch++)
|
||||||
encode_residual_onepass(&frame, ch);
|
encode_residual_onepass(frame, ch);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1409,41 +1317,43 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
frame.window_buffer = window;
|
frame.window_buffer = window;
|
||||||
frame.current.residual = r + 4 * Flake.MAX_BLOCKSIZE;
|
frame.current.residual = r + 4 * Flake.MAX_BLOCKSIZE;
|
||||||
for (int ch = 0; ch < 4; ch++)
|
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));
|
bits_per_sample + (ch == 3 ? 1U : 0U), get_wasted_bits(s + ch * Flake.MAX_BLOCKSIZE, frame.blocksize));
|
||||||
estimate_frame(&frame, true);
|
estimate_frame(frame, true);
|
||||||
uint fs = measure_frame_size(&frame, true);
|
uint fs = measure_frame_size(frame, true);
|
||||||
|
|
||||||
if (0 != eparams.variable_block_size)
|
if (0 != eparams.variable_block_size)
|
||||||
{
|
{
|
||||||
|
FlacFrame frame2 = new FlacFrame(channels * 2);
|
||||||
|
FlacFrame frame3 = new FlacFrame(channels * 2);
|
||||||
int tumbler = 1;
|
int tumbler = 1;
|
||||||
while ((frame.blocksize & 1) == 0 && frame.blocksize >= 1024)
|
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.window_buffer = frame.window_buffer + frame.blocksize;
|
||||||
frame2.current.residual = r + tumbler * 5 * Flake.MAX_BLOCKSIZE;
|
frame2.current.residual = r + tumbler * 5 * Flake.MAX_BLOCKSIZE;
|
||||||
frame2.subframes = sf + tumbler * channels * 2;
|
|
||||||
for (int ch = 0; ch < 4; ch++)
|
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);
|
frame.subframes[ch].obits + frame.subframes[ch].wbits, frame.subframes[ch].wbits);
|
||||||
estimate_frame(&frame2, true);
|
estimate_frame(frame2, true);
|
||||||
uint fs2 = measure_frame_size(&frame2, true);
|
uint fs2 = measure_frame_size(frame2, true);
|
||||||
uint fs3 = fs2;
|
uint fs3 = fs2;
|
||||||
if (eparams.variable_block_size == 2 || eparams.variable_block_size == 4)
|
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.window_buffer = frame2.window_buffer;
|
||||||
frame3.current.residual = frame2.current.residual + 5 * frame2.blocksize;
|
frame3.current.residual = frame2.current.residual + 5 * frame2.blocksize;
|
||||||
frame3.subframes = sf + channels * 4;
|
|
||||||
for (int ch = 0; ch < 4; ch++)
|
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);
|
frame.subframes[ch].obits + frame.subframes[ch].wbits, frame.subframes[ch].wbits);
|
||||||
estimate_frame(&frame3, true);
|
estimate_frame(frame3, true);
|
||||||
fs3 = measure_frame_size(&frame3, true);
|
fs3 = measure_frame_size(frame3, true);
|
||||||
}
|
}
|
||||||
if (fs2 + fs3 > fs)
|
if (fs2 + fs3 > fs)
|
||||||
break;
|
break;
|
||||||
|
FlacFrame tmp = frame;
|
||||||
frame = frame2;
|
frame = frame2;
|
||||||
|
frame2 = tmp;
|
||||||
fs = fs2;
|
fs = fs2;
|
||||||
if (eparams.variable_block_size <= 2)
|
if (eparams.variable_block_size <= 2)
|
||||||
break;
|
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);
|
BitWriter bitwriter = new BitWriter(frame_buffer, 0, max_frame_size);
|
||||||
|
|
||||||
output_frame_header(&frame, bitwriter);
|
output_frame_header(frame, bitwriter);
|
||||||
output_subframes(&frame, bitwriter);
|
output_subframes(frame, bitwriter);
|
||||||
output_frame_footer(bitwriter);
|
output_frame_footer(bitwriter);
|
||||||
|
|
||||||
if (frame_buffer != null)
|
if (frame_buffer != null)
|
||||||
@@ -1598,7 +1509,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
// metadata header
|
// metadata header
|
||||||
bitwriter.writebits(1, last);
|
bitwriter.writebits(1, last);
|
||||||
bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_STREAMINFO);
|
bitwriter.writebits(7, (int)MetadataType.StreamInfo);
|
||||||
bitwriter.writebits(24, 34);
|
bitwriter.writebits(24, 34);
|
||||||
|
|
||||||
if (eparams.variable_block_size > 0)
|
if (eparams.variable_block_size > 0)
|
||||||
@@ -1639,7 +1550,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
// metadata header
|
// metadata header
|
||||||
bitwriter.writebits(1, last);
|
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);
|
bitwriter.writebits(24, vendor_len + 8);
|
||||||
|
|
||||||
comment[pos + 4] = (byte)(vendor_len & 0xFF);
|
comment[pos + 4] = (byte)(vendor_len & 0xFF);
|
||||||
@@ -1662,7 +1573,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
// metadata header
|
// metadata header
|
||||||
bitwriter.writebits(1, last);
|
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);
|
bitwriter.writebits(24, 18 * seek_table.Length);
|
||||||
for (int i = 0; i < seek_table.Length; i++)
|
for (int i = 0; i < seek_table.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -1684,7 +1595,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
|
|
||||||
// metadata header
|
// metadata header
|
||||||
bitwriter.writebits(1, last);
|
bitwriter.writebits(1, last);
|
||||||
bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_PADDING);
|
bitwriter.writebits(7, (int)MetadataType.Padding);
|
||||||
bitwriter.writebits(24, padlen);
|
bitwriter.writebits(24, padlen);
|
||||||
|
|
||||||
return padlen + 4;
|
return padlen + 4;
|
||||||
@@ -1947,7 +1858,7 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
block_time_ms = 105;
|
block_time_ms = 105;
|
||||||
prediction_type = PredictionType.Search;
|
prediction_type = PredictionType.Search;
|
||||||
min_prediction_order = 1;
|
min_prediction_order = 1;
|
||||||
max_prediction_order = 8;
|
max_prediction_order = 12;
|
||||||
estimation_depth = 1;
|
estimation_depth = 1;
|
||||||
min_fixed_order = 2;
|
min_fixed_order = 2;
|
||||||
max_fixed_order = 2;
|
max_fixed_order = 2;
|
||||||
@@ -1960,49 +1871,46 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
do_verify = false;
|
do_verify = false;
|
||||||
do_seektable = true;
|
do_seektable = true;
|
||||||
|
|
||||||
// differences from level 5
|
// differences from level 7
|
||||||
switch (lvl)
|
switch (lvl)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
block_time_ms = 27;
|
block_time_ms = 53;
|
||||||
prediction_type = PredictionType.Fixed;
|
prediction_type = PredictionType.Fixed;
|
||||||
|
stereo_method = StereoMethod.Independent;
|
||||||
max_partition_order = 4;
|
max_partition_order = 4;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
prediction_type = PredictionType.Levinson;
|
prediction_type = PredictionType.Levinson;
|
||||||
stereo_method = StereoMethod.Independent;
|
stereo_method = StereoMethod.Independent;
|
||||||
window_function = WindowFunction.Welch;
|
window_function = WindowFunction.Welch;
|
||||||
|
max_prediction_order = 8;
|
||||||
max_partition_order = 4;
|
max_partition_order = 4;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
stereo_method = StereoMethod.Independent;
|
stereo_method = StereoMethod.Independent;
|
||||||
window_function = WindowFunction.Welch;
|
window_function = WindowFunction.Welch;
|
||||||
max_prediction_order = 12;
|
|
||||||
max_partition_order = 4;
|
max_partition_order = 4;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
stereo_method = StereoMethod.Estimate;
|
stereo_method = StereoMethod.Estimate;
|
||||||
window_function = WindowFunction.Welch;
|
window_function = WindowFunction.Welch;
|
||||||
|
max_prediction_order = 8;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
stereo_method = StereoMethod.Estimate;
|
stereo_method = StereoMethod.Estimate;
|
||||||
window_function = WindowFunction.Welch;
|
window_function = WindowFunction.Welch;
|
||||||
max_prediction_order = 12;
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
window_function = WindowFunction.Welch;
|
window_function = WindowFunction.Welch;
|
||||||
max_prediction_order = 12;
|
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
stereo_method = StereoMethod.Estimate;
|
stereo_method = StereoMethod.Estimate;
|
||||||
max_prediction_order = 12;
|
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
max_prediction_order = 12;
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
estimation_depth = 3;
|
estimation_depth = 3;
|
||||||
max_prediction_order = 12;
|
|
||||||
min_fixed_order = 0;
|
min_fixed_order = 0;
|
||||||
max_fixed_order = 4;
|
max_fixed_order = 4;
|
||||||
lpc_max_precision_search = 2;
|
lpc_max_precision_search = 2;
|
||||||
|
|||||||
@@ -804,4 +804,78 @@ namespace CUETools.Codecs.FLAKE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Context for LPC coefficients calculation and order estimation
|
||||||
|
/// </summary>
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reset to initial (blank) state
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
autocorr_order = 0;
|
||||||
|
for (int iPrecision = 0; iPrecision < lpc.MAX_LPC_PRECISIONS; iPrecision++)
|
||||||
|
done_lpcs[iPrecision] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate autocorrelation data and reflection coefficients.
|
||||||
|
/// Can be used to incrementaly compute coefficients for higher orders,
|
||||||
|
/// because it caches them.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="order">Maximum order</param>
|
||||||
|
/// <param name="samples">Samples pointer</param>
|
||||||
|
/// <param name="blocksize">Block size</param>
|
||||||
|
/// <param name="window">Window function</param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Produces LPC coefficients from autocorrelation data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lpcs">LPC coefficients buffer (for all orders)</param>
|
||||||
|
public void ComputeLPC(double* lpcs)
|
||||||
|
{
|
||||||
|
fixed (double* reff = reflection_coeffs)
|
||||||
|
lpc.compute_lpc_coefs(null, (uint)autocorr_order - 1, reff, lpcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="order"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace CUETools.FlakeExe
|
|||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine("Options:");
|
Console.WriteLine("Options:");
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine(" -0 .. -11 Compression level, default 5.");
|
Console.WriteLine(" -0 .. -11 Compression level, default 7.");
|
||||||
Console.WriteLine(" -o <file> Output filename, or \"-\" for stdout, or nul.");
|
Console.WriteLine(" -o <file> Output filename, or \"-\" for stdout, or nul.");
|
||||||
Console.WriteLine(" -p # Padding bytes.");
|
Console.WriteLine(" -p # Padding bytes.");
|
||||||
Console.WriteLine(" -q --quiet Quiet mode.");
|
Console.WriteLine(" -q --quiet Quiet mode.");
|
||||||
|
|||||||
@@ -911,7 +911,7 @@ namespace CUETools.Processor
|
|||||||
encoders = new CUEToolsUDCList();
|
encoders = new CUEToolsUDCList();
|
||||||
#if !MONO
|
#if !MONO
|
||||||
encoders.Add(new CUEToolsUDC("libFLAC", "flac", true, "0 1 2 3 4 5 6 7 8", "5", "FLACWriter"));
|
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("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("MAC_SDK", "ape", true, "fast normal high extra insane", "high", "APEWriter"));
|
||||||
encoders.Add(new CUEToolsUDC("ttalib", "tta", true, "", "", "TTAWriter"));
|
encoders.Add(new CUEToolsUDC("ttalib", "tta", true, "", "", "TTAWriter"));
|
||||||
|
|||||||
Reference in New Issue
Block a user