cleanup, optimizations

This commit is contained in:
chudov
2009-08-17 20:16:56 +00:00
parent ea0afc6273
commit bc2aceebda
4 changed files with 394 additions and 250 deletions

View File

@@ -4,34 +4,15 @@ using System.Text;
namespace CUETools.Codecs.FLAKE
{
class BitReader
unsafe class BitReader
{
byte[] buffer;
byte[] byte_to_unary_table;
byte* buffer;
int pos, len;
int _bitaccumulator;
uint cache;
public int Position
static readonly byte[] byte_to_unary_table = new byte[]
{
get { return pos; }
}
public byte[] Buffer
{
get
{
return buffer;
}
}
public BitReader(byte[] _buffer, int _pos, int _len)
{
buffer = _buffer;
pos = _pos;
len = _len;
_bitaccumulator = 0;
byte_to_unary_table = new byte[] {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -49,85 +30,107 @@ namespace CUETools.Codecs.FLAKE
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
public int Position
{
get { return pos; }
}
/* supports reading 1 to 24 bits, in big endian format */
public uint readbits_24(int bits)
public byte* Buffer
{
uint result = (((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16) | (((uint)buffer[pos + 2]) << 8) | ((uint)buffer[pos + 3]);
result <<= _bitaccumulator;
result >>= 32 - bits;
get
{
return buffer;
}
}
int new_accumulator = (_bitaccumulator + bits);
pos += (new_accumulator >> 3);
_bitaccumulator = (new_accumulator & 7);
public BitReader(byte* _buffer, int _pos, int _len)
{
buffer = _buffer;
pos = _pos;
len = _len;
_bitaccumulator = 0;
cache = peek4();
}
public uint peek4()
{
//uint result = ((((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16) | (((uint)buffer[pos + 2]) << 8) | ((uint)buffer[pos + 3])) << _bitaccumulator;
byte* b = buffer + pos;
uint result = *(b++);
result = (result << 8) + *(b++);
result = (result << 8) + *(b++);
result = (result << 8) + *(b++);
result <<= _bitaccumulator;
return result;
}
public uint readbits_8(int bits)
{
uint result = (((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16);
result <<= _bitaccumulator;
result >>= 32 - bits;
int new_accumulator = (_bitaccumulator + bits);
pos += (new_accumulator >> 3);
_bitaccumulator = (new_accumulator & 7);
return result;
}
public uint peekbits_24(int bits)
{
uint result = (((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16) | (((uint)buffer[pos + 2]) << 8) | ((uint)buffer[pos + 3]);
result <<= _bitaccumulator;
result >>= 32 - bits;
return result;
}
///* supports reading 1 to 16 bits, in big endian format */
//private unsafe uint peekbits_9(byte* buff, int pos)
//{
// uint result = (((uint)buff[pos]) << 8) | (((uint)buff[pos + 1]));
// result <<= _bitaccumulator;
// result &= 0x0000ffff;
// result >>= 7;
// return result;
//}
/* supports reading 1 to 16 bits, in big endian format */
/* skip any number of bits */
public void skipbits(int bits)
{
int new_accumulator = (_bitaccumulator + bits);
pos += (new_accumulator >> 3);
_bitaccumulator = (new_accumulator & 7);
cache = peek4();
}
/* skip up to 8 bits */
public void skipbits8(int bits)
{
cache <<= bits;
int new_accumulator = (_bitaccumulator + bits);
pos += (new_accumulator >> 3);
_bitaccumulator = (new_accumulator & 7);
cache |= ((uint)buffer[pos + 3] << _bitaccumulator);
}
/* supports reading 1 to 24 bits, in big endian format */
public uint readbits24(int bits)
{
//uint result = peek4() >> (32 - bits);
uint result = cache >> (32 - bits);
skipbits(bits);
return result;
}
public uint peekbits24(int bits)
{
return cache >> 32 - bits;
}
/* supports reading 1 to 32 bits, in big endian format */
public uint readbits(int bits)
{
uint result = cache >> 32 - bits;
if (bits <= 24)
return readbits_24(bits);
{
skipbits(bits);
return result;
}
skipbits(24);
result |= cache >> 56 - bits;
skipbits(bits - 24);
return result;
}
ulong result = (((ulong)buffer[pos]) << 32) | (((ulong)buffer[pos + 1]) << 24) | (((ulong)buffer[pos + 2]) << 16) | (((ulong)buffer[pos + 3]) << 8) | ((ulong)buffer[pos + 4]);
result <<= _bitaccumulator;
result &= 0x00ffffffffff;
result >>= 40 - bits;
int new_accumulator = (_bitaccumulator + bits);
pos += (new_accumulator >> 3);
_bitaccumulator = (new_accumulator & 7);
return (uint)result;
public ulong readbits64(int bits)
{
if (bits <= 24)
return readbits24(bits);
ulong result = readbits24(24);
bits -= 24;
if (bits <= 24)
return (result << bits) | readbits24(bits);
result = (result << 24) | readbits24(24);
bits -= 24;
return (result << bits) | readbits24(bits);
}
/* reads a single bit */
public uint readbit()
{
int new_accumulator;
uint result = buffer[pos];
result <<= _bitaccumulator;
result = result >> 7 & 1;
new_accumulator = (_bitaccumulator + 1);
pos += (new_accumulator / 8);
_bitaccumulator = (new_accumulator % 8);
uint result = cache >> 31;
skipbits8(1);
return result;
}
@@ -135,28 +138,23 @@ namespace CUETools.Codecs.FLAKE
{
uint val = 0;
int result = (buffer[pos] << _bitaccumulator) & 0xff;
if (result == 0)
uint result = cache >> 24;
while (result == 0)
{
val = 8 - (uint)_bitaccumulator;
_bitaccumulator = 0;
pos++;
return val + read_unary();
// check eof
val += 8;
skipbits8(8);
result = cache >> 24;
}
val = byte_to_unary_table[result];
int new_accumulator = (_bitaccumulator + (int)val + 1);
pos += (new_accumulator / 8);
_bitaccumulator = (new_accumulator % 8);
val += byte_to_unary_table[result];
skipbits8((int)(val & 7) + 1);
return val;
}
public void flush()
{
if (_bitaccumulator > 0)
readbits(8 - _bitaccumulator);
skipbits8(8 - _bitaccumulator);
}
public int readbits_signed(int bits)
@@ -223,15 +221,7 @@ namespace CUETools.Codecs.FLAKE
public int read_rice_signed(int k)
{
uint msbs = read_unary();
uint lsbs = readbits_24(k);
uint uval = (msbs << k) | lsbs;
return (int)(uval >> 1 ^ -(int)(uval & 1));
}
public int read_rice_signed8(int k)
{
uint msbs = read_unary();
uint lsbs = readbits_8(k);
uint lsbs = readbits24(k);
uint uval = (msbs << k) | lsbs;
return (int)(uval >> 1 ^ -(int)(uval & 1));
}
@@ -241,5 +231,49 @@ namespace CUETools.Codecs.FLAKE
uint uval = read_unary();
return (int)(uval >> 1 ^ -(int)(uval & 1));
}
public void read_rice_block(int n, int k, int* r)
{
fixed (byte* unary_table = byte_to_unary_table)
{
if (k == 0)
for (int i = n; i > 0; i--)
*(r++) = read_unary_signed();
else if (k <= 8)
for (int i = n; i > 0; i--)
{
//*(r++) = read_rice_signed((int)k);
uint bits = unary_table[cache >> 24];
uint msbs = bits;
while (bits == 8)
{
skipbits8(8);
bits = unary_table[cache >> 24];
msbs += bits;
}
skipbits8((int)(msbs & 7) + 1);
uint uval = (msbs << k) | (cache >> (32 - k));
skipbits8(k);
*(r++) = (int)(uval >> 1 ^ -(int)(uval & 1));
}
else
for (int i = n; i > 0; i--)
{
//*(r++) = read_rice_signed((int)k);
uint bits = unary_table[cache >> 24];
uint msbs = bits;
while (bits == 8)
{
skipbits8(8);
bits = unary_table[cache >> 24];
msbs += bits;
}
skipbits8((int)(msbs & 7) + 1);
uint uval = (msbs << k) | (cache >> (32 - k));
skipbits(k);
*(r++) = (int)(uval >> 1 ^ -(int)(uval & 1));
}
}
}
}
}

View File

@@ -10,6 +10,15 @@ namespace CUETools.Codecs.FLAKE
public const int MAX_RICE_PARAM = 14;
public const int MAX_PARTITION_ORDER = 8;
public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER;
public static readonly int[] flac_samplerates = new int[16] {
0, 0, 0, 0,
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
0, 0, 0, 0
};
public static readonly int[] flac_blocksizes = new int[15] { 0, 192, 576, 1152, 2304, 4608, 0, 0, 256, 512, 1024, 2048, 4096, 8192, 16384 };
public static readonly int[] flac_bitdepths = new int[8] { 0, 8, 12, 0, 16, 20, 24, 0 };
public static int log2i(int v)
{
return log2i((uint)v);
@@ -97,17 +106,30 @@ namespace CUETools.Codecs.FLAKE
for (int i = n; i > 0; i--)
*(res++) = *(smp++);
}
unsafe public static void memcpy(byte* res, byte* smp, int n)
{
for (int i = n; i > 0; i--)
*(res++) = *(smp++);
}
unsafe public static void memset(int* res, int smp, int n)
{
for (int i = n; i > 0; i--)
*(res++) = smp;
}
unsafe public static void interlace(int* res, int* src1, int* src2, int n)
{
for (int i = n; i > 0; i--)
{
*(res++) = *(src1++);
*(res++) = *(src2++);
}
}
}
unsafe struct RiceContext
{
public int porder; /* partition order */
public fixed uint rparams[Flake.MAX_PARTITIONS]; /* Rice parameters */
public fixed int rparams[Flake.MAX_PARTITIONS]; /* Rice parameters */
public fixed int esc_bps[Flake.MAX_PARTITIONS]; /* bps if using escape code */
};
@@ -214,6 +236,13 @@ namespace CUETools.Codecs.FLAKE
Flattop = 8
}
public struct SeekPoint
{
public ulong number;
public ulong offset;
public uint framesize;
}
public enum MetadataType
{
@@ -227,22 +256,34 @@ namespace CUETools.Codecs.FLAKE
/// </summary>
FLAC__METADATA_TYPE_PADDING = 1,
/// <summary>
/// <A HREF="../format.html#metadata_block_application">APPLICATION</A> block
/// </summary>
FLAC__METADATA_TYPE_APPLICATION = 2,
/**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
/// <summary>
/// <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block
/// </summary>
FLAC__METADATA_TYPE_SEEKTABLE = 3,
/**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
/// <summary>
/// <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags)
/// </summary>
FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
/// <summary>
/// <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block
/// </summary>
FLAC__METADATA_TYPE_CUESHEET = 5,
/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
/// <summary>
/// <A HREF="../format.html#metadata_block_picture">PICTURE</A> block
/// </summary>
FLAC__METADATA_TYPE_PICTURE = 6,
/**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
/// <summary>
/// marker to denote beginning of undefined type range; this number will increase as new metadata types are added
/// </summary>
FLAC__METADATA_TYPE_UNDEFINED = 7
/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
};
}

View File

@@ -7,14 +7,14 @@ namespace CUETools.Codecs.FLAKE
{
public class FlakeReader: IAudioSource
{
int[] flac_blocksizes;
int[] flac_bitdepths;
int[] samplesBuffer;
int[] residualBuffer;
byte[] _framesBuffer;
int _framesBufferLength = 0, _framesBufferOffset = 0;
long first_frame_offset;
SeekPoint[] seek_table;
Crc8 crc8;
Crc16 crc16;
@@ -45,22 +45,19 @@ namespace CUETools.Codecs.FLAKE
public FlakeReader(string path, Stream IO)
{
_path = path;
_IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
flac_bitdepths = new int[8] { 0, 8, 12, 0, 16, 20, 24, 0 };
flac_blocksizes = new int[15] { 0, 192, 576, 1152, 2304, 4608, 0, 0, 256, 512, 1024, 2048, 4096, 8192, 16384 };
_IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000);
crc8 = new Crc8();
crc16 = new Crc16();
_framesBuffer = new byte[0x10000];
_framesBuffer = new byte[0x20000];
decode_metadata();
//max_frame_size = 16 + ((Flake.MAX_BLOCKSIZE * (int)(bits_per_sample * channels + 1) + 7) >> 3);
if (max_frame_size * 2 > _framesBuffer.Length)
if (((int)max_frame_size * (int)bits_per_sample * channels * 2 >> 3) > _framesBuffer.Length)
{
byte[] temp = _framesBuffer;
_framesBuffer = new byte[max_frame_size * 2];
_framesBuffer = new byte[((int)max_frame_size * (int)bits_per_sample * channels * 2 >> 3)];
if (_framesBufferLength > 0)
Array.Copy(temp, _framesBufferOffset, _framesBuffer, 0, _framesBufferLength);
_framesBufferOffset = 0;
@@ -76,9 +73,6 @@ namespace CUETools.Codecs.FLAKE
public FlakeReader(int _channels, uint _bits_per_sample)
{
flac_bitdepths = new int[8] { 0, 8, 12, 0, 16, 20, 24, 0 };
flac_blocksizes = new int[15] { 0, 192, 576, 1152, 2304, 4608, 0, 0, 256, 512, 1024, 2048, 4096, 8192, 16384 };
crc8 = new Crc8();
crc16 = new Crc16();
@@ -110,7 +104,7 @@ namespace CUETools.Codecs.FLAKE
{
get
{
return _sampleCount - _sampleOffset + _samplesInBuffer;
return Length - Position;
}
}
@@ -122,7 +116,33 @@ namespace CUETools.Codecs.FLAKE
}
set
{
throw new Exception("seeking not yet supported");
if (value > _sampleCount)
throw new Exception("seeking past end of stream");
if (value < Position)
throw new Exception("backwards seeking not yet supported");
if (seek_table != null)
{
}
while (value > _sampleOffset)
{
_samplesInBuffer = 0;
_samplesBufferOffset = 0;
fill_frames_buffer();
if (_framesBufferLength == 0)
throw new Exception("seek failed");
int bytesDecoded = DecodeFrame(_framesBuffer, _framesBufferOffset, _framesBufferLength);
_framesBufferLength -= bytesDecoded;
_framesBufferOffset += bytesDecoded;
_sampleOffset += _samplesInBuffer;
};
uint diff = _samplesInBuffer - (uint)(_sampleOffset - value);
_samplesInBuffer -= diff;
_samplesBufferOffset += diff;
}
}
@@ -158,11 +178,23 @@ namespace CUETools.Codecs.FLAKE
}
}
void interlace(int [,] buff, int offset, int count)
unsafe void interlace(int [,] buff, int offset, int count)
{
if (channels == 2)
{
fixed (int* res = &buff[offset, 0], src = &samplesBuffer[_samplesBufferOffset])
Flake.interlace(res, src, src + Flake.MAX_BLOCKSIZE, count);
}
else
{
for (int ch = 0; ch < channels; ch++)
fixed (int* res = &buff[offset, ch], src = &samplesBuffer[_samplesBufferOffset + ch * Flake.MAX_BLOCKSIZE])
{
int* psrc = src;
for (int i = 0; i < count; i++)
buff[offset + i, ch] = samplesBuffer[_samplesBufferOffset + i + ch * Flake.MAX_BLOCKSIZE];
res[i + i] = *(psrc++);
}
}
}
public uint Read(int[,] buff, uint sampleCount)
@@ -201,13 +233,14 @@ namespace CUETools.Codecs.FLAKE
return (uint)offset + sampleCount;
}
void fill_frames_buffer()
unsafe void fill_frames_buffer()
{
if (_framesBufferLength == 0)
_framesBufferOffset = 0;
else if (_framesBufferLength < _framesBuffer.Length / 2 && _framesBufferOffset >= _framesBuffer.Length / 2)
{
Array.Copy(_framesBuffer, _framesBufferOffset, _framesBuffer, 0, _framesBufferLength);
fixed (byte* buff = _framesBuffer)
Flake.memcpy(buff, buff + _framesBufferOffset, _framesBufferLength);
_framesBufferOffset = 0;
}
while (_framesBufferLength < _framesBuffer.Length / 2)
@@ -230,7 +263,7 @@ namespace CUETools.Codecs.FLAKE
uint sr_code0 = bitreader.readbits(4);
frame->ch_mode = (ChannelMode)bitreader.readbits(4);
uint bps_code = bitreader.readbits(3);
if (flac_bitdepths[bps_code] != bits_per_sample)
if (Flake.flac_bitdepths[bps_code] != bits_per_sample)
throw new Exception("unsupported bps coding");
uint t1 = bitreader.readbit(); // == 0?????
if (t1 != 0)
@@ -249,7 +282,7 @@ namespace CUETools.Codecs.FLAKE
frame->blocksize = frame->bs_code1 + 1;
}
else
frame->blocksize = flac_blocksizes[frame->bs_code0];
frame->blocksize = Flake.flac_blocksizes[frame->bs_code0];
// custom sample rate
if (sr_code0 < 4 || sr_code0 > 11)
@@ -294,7 +327,7 @@ namespace CUETools.Codecs.FLAKE
{
// rice-encoded block
uint coding_method = bitreader.readbits(2); // ????? == 0
if (coding_method != 0) // 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");
// partition order
frame->subframes[ch].rc.porder = (int)bitreader.readbits(4);
@@ -303,23 +336,27 @@ namespace CUETools.Codecs.FLAKE
int psize = frame->blocksize >> frame->subframes[ch].rc.porder;
int res_cnt = psize - frame->subframes[ch].order;
int rice_len = 4 + (int)coding_method;
// residual
int j = frame->subframes[ch].order;
int* r = frame->subframes[ch].residual + j;
for (int p = 0; p < (1 << frame->subframes[ch].rc.porder); p++)
{
uint k = frame->subframes[ch].rc.rparams[p] = bitreader.readbits(4);
if (p == 1) res_cnt = psize;
int n = Math.Min(res_cnt, frame->blocksize - j);
if (k == 0)
int k = frame->subframes[ch].rc.rparams[p] = (int)bitreader.readbits(rice_len);
if (k == (1 << rice_len) - 1)
{
k = frame->subframes[ch].rc.esc_bps[p] = (int)bitreader.readbits(5);
for (int i = n; i > 0; i--)
*(r++) = bitreader.read_unary_signed();
else if (k <= 8)
for (int i = n; i > 0; i--)
*(r++) = bitreader.read_rice_signed8((int)k);
*(r++) = bitreader.readbits_signed((int)k);
}
else
for (int i = n; i > 0; i--)
*(r++) = bitreader.read_rice_signed((int)k);
{
bitreader.read_rice_block(n, (int)k, r);
r += n;
}
j += n;
}
}
@@ -420,18 +457,32 @@ namespace CUETools.Codecs.FLAKE
int* data = sub->samples + sub->order;
int* residual = sub->residual + sub->order;
int data_len = frame->blocksize - sub->order;
int s0, s1, s2;
switch (sub->order)
{
case 0:
Flake.memcpy(data, residual, data_len);
break;
case 1:
for (int i = 0; i < data_len; i++)
data[i] = residual[i] + data[i - 1];
s1 = data[-1];
for (int i = data_len; i > 0; i--)
{
s1 += *(residual++);
*(data++) = s1;
}
//data[i] = residual[i] + data[i - 1];
break;
case 2:
for (int i = 0; i < data_len; i++)
data[i] = residual[i] + (data[i - 1] << 1) - data[i - 2];
s2 = data[-2];
s1 = data[-1];
for (int i = data_len; i > 0; i--)
{
s0 = *(residual++) + (s1 << 1) - s2;
*(data++) = s0;
s2 = s1;
s1 = s0;
}
//data[i] = residual[i] + data[i - 1] * 2 - data[i - 2];
break;
case 3:
for (int i = 0; i < data_len; i++)
@@ -447,8 +498,10 @@ namespace CUETools.Codecs.FLAKE
unsafe void restore_samples_lpc(FlacFrame* frame, int ch)
{
FlacSubframe* sub = frame->subframes + ch;
if ((ulong)sub->order * ((1UL << (int)sub->obits) - 1) * ((1U << sub->cbits) - 1) >= (1UL << 32))
ulong csum = 0;
for (int i = sub->order; i > 0; i--)
csum += (ulong)Math.Abs(sub->coefs[i - 1]);
if ((csum << (int)sub->obits) >= 1UL << 32)
lpc.decode_residual_long(sub->residual, sub->samples, frame->blocksize, sub->order, sub->coefs, sub->shift);
else
lpc.decode_residual(sub->residual, sub->samples, frame->blocksize, sub->order, sub->coefs, sub->shift);
@@ -475,42 +528,51 @@ namespace CUETools.Codecs.FLAKE
}
if (frame->subframes[ch].wbits != 0)
{
int* s = frame->subframes[ch].samples;
int x = (int) frame->subframes[ch].wbits;
for (int i = 0; i < frame->blocksize; i++)
frame->subframes[ch].samples[i] <<= x;
for (int i = frame->blocksize; i > 0; i--)
*(s++) <<= x;
}
}
if (frame->ch_mode != ChannelMode.NotStereo)
{
int* l = frame->subframes[0].samples;
int* r = frame->subframes[1].samples;
switch (frame->ch_mode)
{
case ChannelMode.NotStereo:
break;
case ChannelMode.LeftRight:
break;
case ChannelMode.MidSide:
for (int i = 0; i < frame->blocksize; i++)
for (int i = frame->blocksize; i > 0; i--)
{
int mid = frame->subframes[0].samples[i];
int side = frame->subframes[1].samples[i];
int mid = *l;
int side = *r;
mid <<= 1;
mid |= (side & 1); /* i.e. if 'side' is odd... */
frame->subframes[0].samples[i] = (mid + side) >> 1;
frame->subframes[1].samples[i] = (mid - side) >> 1;
*(l++) = (mid + side) >> 1;
*(r++) = (mid - side) >> 1;
}
break;
case ChannelMode.LeftSide:
for (int i = 0; i < frame->blocksize; i++)
frame->subframes[1].samples[i] = frame->subframes[0].samples[i] - frame->subframes[1].samples[i];
for (int i = frame->blocksize; i > 0; i--)
{
int _l = *(l++), _r = *r;
*(r++) = _l - _r;
}
break;
case ChannelMode.RightSide:
for (int i = 0; i < frame->blocksize; i++)
frame->subframes[0].samples[i] += frame->subframes[1].samples[i];
for (int i = frame->blocksize; i > 0; i--)
*(l++) += *(r++);
break;
}
}
}
public unsafe int DecodeFrame(byte[] buffer, int pos, int len)
{
BitReader bitreader = new BitReader(buffer, pos, len);
fixed (byte* buf = buffer)
{
BitReader bitreader = new BitReader(buf, pos, len);
FlacFrame frame;
FlacSubframe* subframes = stackalloc FlacSubframe[channels];
frame.subframes = subframes;
@@ -521,10 +583,10 @@ namespace CUETools.Codecs.FLAKE
if (crc != bitreader.readbits(16))
throw new Exception("frame crc mismatch");
restore_samples(&frame);
restore_samples(&frame);
_samplesInBuffer = (uint)frame.blocksize;
return bitreader.Position - pos;
}
}
bool skip_bytes(int bytes)
@@ -535,7 +597,7 @@ namespace CUETools.Codecs.FLAKE
return true;
}
void decode_metadata()
unsafe void decode_metadata()
{
byte x;
int i, id;
@@ -597,9 +659,10 @@ namespace CUETools.Codecs.FLAKE
do
{
long pos = _IO.Position;
fill_frames_buffer();
BitReader bitreader = new BitReader(_framesBuffer, _framesBufferOffset, _framesBufferLength - _framesBufferOffset);
fixed (byte* buf = _framesBuffer)
{
BitReader bitreader = new BitReader(buf, _framesBufferOffset, _framesBufferLength - _framesBufferOffset);
bool is_last = bitreader.readbit() != 0;
MetadataType type = (MetadataType)bitreader.readbits(7);
int len = (int)bitreader.readbits(24);
@@ -623,12 +686,27 @@ namespace CUETools.Codecs.FLAKE
sample_rate = (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN);
channels = 1 + (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN);
bits_per_sample = 1 + bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN);
_sampleCount = (((ulong)bitreader.readbits(4)) << 4) + (ulong)bitreader.readbits(32);
_sampleCount = bitreader.readbits64(FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN);
bitreader.skipbits(FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN);
}
else if (type == MetadataType.FLAC__METADATA_TYPE_SEEKTABLE)
{
const int FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
const int FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
const int FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
int num_entries = len / 18;
seek_table = new SeekPoint[num_entries];
for (int e = 0; e < num_entries; e++)
{
seek_table[e].number = bitreader.readbits64(FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN);
seek_table[e].offset = bitreader.readbits64(FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN);
seek_table[e].framesize = bitreader.readbits24(FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN);
}
}
if (_framesBufferLength < 4 + len)
{
_IO.Position = pos + 4 + len;
_IO.Position += 4 + len - _framesBufferLength;
_framesBufferLength = 0;
}
else
@@ -638,7 +716,9 @@ namespace CUETools.Codecs.FLAKE
}
if (is_last)
break;
}
} while (true);
first_frame_offset = _IO.Position - _framesBufferLength;
}
}
}

View File

@@ -80,14 +80,6 @@ namespace CUETools.Codecs.FLAKE
if (channelCount != 2)
throw new Exception("ChannelCount must be 2.");
flac_samplerates = new int[16] {
0, 0, 0, 0,
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
0, 0, 0, 0
};
flac_bitdepths = new int[8] { 0, 8, 12, 0, 16, 20, 24, 0 };
flac_blocksizes = new int[15] { 0, 192, 576, 1152, 2304, 4608, 0, 0, 256, 512, 1024, 2048, 4096, 8192, 16384 };
channels = channelCount;
sample_rate = sampleRate;
bits_per_sample = (uint) bitsPerSample;
@@ -334,9 +326,9 @@ namespace CUETools.Codecs.FLAKE
{
for (i = 0; i < 15; i++)
{
if (eparams.block_size == flac_blocksizes[i])
if (eparams.block_size == Flake.flac_blocksizes[i])
{
frame->blocksize = flac_blocksizes[i];
frame->blocksize = Flake.flac_blocksizes[i];
frame->bs_code0 = i;
frame->bs_code1 = -1;
break;
@@ -394,7 +386,7 @@ namespace CUETools.Codecs.FLAKE
// return (uint)k_opt;
//}
static unsafe uint find_optimal_rice_param(uint sum, uint n, out uint nbits_best)
static unsafe int find_optimal_rice_param(uint sum, uint n, out uint nbits_best)
{
int k_opt = 0;
uint a = n;
@@ -412,7 +404,7 @@ namespace CUETools.Codecs.FLAKE
}
}
nbits_best = nbits;
return (uint)k_opt;
return k_opt;
}
unsafe uint calc_decorr_score(FlacFrame* frame, int ch, FlacSubframe* sub)
@@ -845,7 +837,7 @@ namespace CUETools.Codecs.FLAKE
int j = sub->order;
for (int p = 0; p < (1 << porder); p++)
{
int k = (int) sub->rc.rparams[p];
int k = sub->rc.rparams[p];
bitwriter.writebits(4, k);
if (p == 1) res_cnt = psize;
for (int i = 0; i < res_cnt && j < frame->blocksize; i++, j++)
@@ -1247,19 +1239,16 @@ namespace CUETools.Codecs.FLAKE
public string Path { get { return _path; } }
int[] flac_samplerates;
int[] flac_bitdepths;
int[] flac_blocksizes;
string vendor_string = "Flake#0.1";
int select_blocksize(int samplerate, int time_ms)
{
int blocksize = flac_blocksizes[1];
int blocksize = Flake.flac_blocksizes[1];
int target = (samplerate * time_ms) / 1000;
for (int i = 0; i < flac_blocksizes.Length; i++)
if (target >= flac_blocksizes[i] && flac_blocksizes[i] > blocksize)
for (int i = 0; i < Flake.flac_blocksizes.Length; i++)
if (target >= Flake.flac_blocksizes[i] && Flake.flac_blocksizes[i] > blocksize)
{
blocksize = flac_blocksizes[i];
blocksize = Flake.flac_blocksizes[i];
}
return blocksize;
}
@@ -1271,7 +1260,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header
bitwriter.writebits(1, last);
bitwriter.writebits(7, 0);
bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_STREAMINFO);
bitwriter.writebits(24, 34);
if (eparams.variable_block_size > 0)
@@ -1312,7 +1301,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header
bitwriter.writebits(1, last);
bitwriter.writebits(7, 4);
bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_VORBIS_COMMENT);
bitwriter.writebits(24, vendor_len + 8);
comment[pos + 4] = (byte)(vendor_len & 0xFF);
@@ -1337,7 +1326,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header
bitwriter.writebits(1, last);
bitwriter.writebits(7, 1);
bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_PADDING);
bitwriter.writebits(24, padlen);
return padlen + 4;
@@ -1384,7 +1373,7 @@ namespace CUETools.Codecs.FLAKE
// find samplerate in table
for (i = 4; i < 12; i++)
{
if (sample_rate == flac_samplerates[i])
if (sample_rate == Flake.flac_samplerates[i])
{
sr_code0 = i;
break;
@@ -1397,7 +1386,7 @@ namespace CUETools.Codecs.FLAKE
for (i = 1; i < 8; i++)
{
if (bits_per_sample == flac_bitdepths[i])
if (bits_per_sample == Flake.flac_bitdepths[i])
{
bps_code = i;
break;