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 namespace CUETools.Codecs.FLAKE
{ {
class BitReader unsafe class BitReader
{ {
byte[] buffer; byte* buffer;
byte[] byte_to_unary_table;
int pos, len; int pos, len;
int _bitaccumulator; 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, 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,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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,
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 byte* Buffer
public uint readbits_24(int bits)
{ {
uint result = (((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16) | (((uint)buffer[pos + 2]) << 8) | ((uint)buffer[pos + 3]); get
result <<= _bitaccumulator; {
result >>= 32 - bits; return buffer;
}
}
int new_accumulator = (_bitaccumulator + bits); public BitReader(byte* _buffer, int _pos, int _len)
pos += (new_accumulator >> 3); {
_bitaccumulator = (new_accumulator & 7); 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; return result;
} }
public uint readbits_8(int bits) /* skip any number of 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 */
public void skipbits(int bits) public void skipbits(int bits)
{ {
int new_accumulator = (_bitaccumulator + bits); int new_accumulator = (_bitaccumulator + bits);
pos += (new_accumulator >> 3); pos += (new_accumulator >> 3);
_bitaccumulator = (new_accumulator & 7); _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 */ /* supports reading 1 to 32 bits, in big endian format */
public uint readbits(int bits) public uint readbits(int bits)
{ {
uint result = cache >> 32 - bits;
if (bits <= 24) 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]); public ulong readbits64(int bits)
result <<= _bitaccumulator; {
result &= 0x00ffffffffff; if (bits <= 24)
result >>= 40 - bits; return readbits24(bits);
int new_accumulator = (_bitaccumulator + bits); ulong result = readbits24(24);
pos += (new_accumulator >> 3); bits -= 24;
_bitaccumulator = (new_accumulator & 7); if (bits <= 24)
return (uint)result; return (result << bits) | readbits24(bits);
result = (result << 24) | readbits24(24);
bits -= 24;
return (result << bits) | readbits24(bits);
} }
/* reads a single bit */ /* reads a single bit */
public uint readbit() public uint readbit()
{ {
int new_accumulator; uint result = cache >> 31;
uint result = buffer[pos]; skipbits8(1);
result <<= _bitaccumulator;
result = result >> 7 & 1;
new_accumulator = (_bitaccumulator + 1);
pos += (new_accumulator / 8);
_bitaccumulator = (new_accumulator % 8);
return result; return result;
} }
@@ -135,28 +138,23 @@ namespace CUETools.Codecs.FLAKE
{ {
uint val = 0; uint val = 0;
int result = (buffer[pos] << _bitaccumulator) & 0xff; uint result = cache >> 24;
if (result == 0) while (result == 0)
{ {
val = 8 - (uint)_bitaccumulator; val += 8;
_bitaccumulator = 0; skipbits8(8);
pos++; result = cache >> 24;
return val + read_unary();
// check eof
} }
val = byte_to_unary_table[result]; val += byte_to_unary_table[result];
skipbits8((int)(val & 7) + 1);
int new_accumulator = (_bitaccumulator + (int)val + 1);
pos += (new_accumulator / 8);
_bitaccumulator = (new_accumulator % 8);
return val; return val;
} }
public void flush() public void flush()
{ {
if (_bitaccumulator > 0) if (_bitaccumulator > 0)
readbits(8 - _bitaccumulator); skipbits8(8 - _bitaccumulator);
} }
public int readbits_signed(int bits) public int readbits_signed(int bits)
@@ -223,15 +221,7 @@ namespace CUETools.Codecs.FLAKE
public int read_rice_signed(int k) public int read_rice_signed(int k)
{ {
uint msbs = read_unary(); uint msbs = read_unary();
uint lsbs = readbits_24(k); uint lsbs = readbits24(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 uval = (msbs << k) | lsbs; uint uval = (msbs << k) | lsbs;
return (int)(uval >> 1 ^ -(int)(uval & 1)); return (int)(uval >> 1 ^ -(int)(uval & 1));
} }
@@ -241,5 +231,49 @@ namespace CUETools.Codecs.FLAKE
uint uval = read_unary(); uint uval = read_unary();
return (int)(uval >> 1 ^ -(int)(uval & 1)); 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_RICE_PARAM = 14;
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 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) public static int log2i(int v)
{ {
return log2i((uint)v); return log2i((uint)v);
@@ -97,17 +106,30 @@ namespace CUETools.Codecs.FLAKE
for (int i = n; i > 0; i--) for (int i = n; i > 0; i--)
*(res++) = *(smp++); *(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) unsafe public static void memset(int* res, int smp, int n)
{ {
for (int i = n; i > 0; i--) for (int i = n; i > 0; i--)
*(res++) = smp; *(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 unsafe struct RiceContext
{ {
public int porder; /* partition order */ 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 */ public fixed int esc_bps[Flake.MAX_PARTITIONS]; /* bps if using escape code */
}; };
@@ -214,6 +236,13 @@ namespace CUETools.Codecs.FLAKE
Flattop = 8 Flattop = 8
} }
public struct SeekPoint
{
public ulong number;
public ulong offset;
public uint framesize;
}
public enum MetadataType public enum MetadataType
{ {
@@ -227,22 +256,34 @@ namespace CUETools.Codecs.FLAKE
/// </summary> /// </summary>
FLAC__METADATA_TYPE_PADDING = 1, FLAC__METADATA_TYPE_PADDING = 1,
/// <summary>
/// <A HREF="../format.html#metadata_block_application">APPLICATION</A> block
/// </summary>
FLAC__METADATA_TYPE_APPLICATION = 2, 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, 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, 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, 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, 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 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 public class FlakeReader: IAudioSource
{ {
int[] flac_blocksizes;
int[] flac_bitdepths;
int[] samplesBuffer; int[] samplesBuffer;
int[] residualBuffer; int[] residualBuffer;
byte[] _framesBuffer; byte[] _framesBuffer;
int _framesBufferLength = 0, _framesBufferOffset = 0; int _framesBufferLength = 0, _framesBufferOffset = 0;
long first_frame_offset;
SeekPoint[] seek_table;
Crc8 crc8; Crc8 crc8;
Crc16 crc16; Crc16 crc16;
@@ -45,22 +45,19 @@ namespace CUETools.Codecs.FLAKE
public FlakeReader(string path, Stream IO) public FlakeReader(string path, Stream IO)
{ {
_path = path; _path = path;
_IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); _IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000);
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(); crc8 = new Crc8();
crc16 = new Crc16(); crc16 = new Crc16();
_framesBuffer = new byte[0x10000]; _framesBuffer = new byte[0x20000];
decode_metadata(); decode_metadata();
//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 (max_frame_size * 2 > _framesBuffer.Length) if (((int)max_frame_size * (int)bits_per_sample * channels * 2 >> 3) > _framesBuffer.Length)
{ {
byte[] temp = _framesBuffer; 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) if (_framesBufferLength > 0)
Array.Copy(temp, _framesBufferOffset, _framesBuffer, 0, _framesBufferLength); Array.Copy(temp, _framesBufferOffset, _framesBuffer, 0, _framesBufferLength);
_framesBufferOffset = 0; _framesBufferOffset = 0;
@@ -76,9 +73,6 @@ namespace CUETools.Codecs.FLAKE
public FlakeReader(int _channels, uint _bits_per_sample) 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(); crc8 = new Crc8();
crc16 = new Crc16(); crc16 = new Crc16();
@@ -110,7 +104,7 @@ namespace CUETools.Codecs.FLAKE
{ {
get get
{ {
return _sampleCount - _sampleOffset + _samplesInBuffer; return Length - Position;
} }
} }
@@ -122,7 +116,33 @@ namespace CUETools.Codecs.FLAKE
} }
set 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++) 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++) 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) public uint Read(int[,] buff, uint sampleCount)
@@ -201,13 +233,14 @@ namespace CUETools.Codecs.FLAKE
return (uint)offset + sampleCount; return (uint)offset + sampleCount;
} }
void fill_frames_buffer() unsafe void fill_frames_buffer()
{ {
if (_framesBufferLength == 0) if (_framesBufferLength == 0)
_framesBufferOffset = 0; _framesBufferOffset = 0;
else if (_framesBufferLength < _framesBuffer.Length / 2 && _framesBufferOffset >= _framesBuffer.Length / 2) 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; _framesBufferOffset = 0;
} }
while (_framesBufferLength < _framesBuffer.Length / 2) while (_framesBufferLength < _framesBuffer.Length / 2)
@@ -230,7 +263,7 @@ namespace CUETools.Codecs.FLAKE
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 (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)
@@ -249,7 +282,7 @@ namespace CUETools.Codecs.FLAKE
frame->blocksize = frame->bs_code1 + 1; frame->blocksize = frame->bs_code1 + 1;
} }
else else
frame->blocksize = 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)
@@ -294,7 +327,7 @@ namespace CUETools.Codecs.FLAKE
{ {
// rice-encoded block // rice-encoded block
uint coding_method = bitreader.readbits(2); // ????? == 0 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"); throw new Exception("unsupported residual coding");
// partition order // partition order
frame->subframes[ch].rc.porder = (int)bitreader.readbits(4); 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 psize = frame->blocksize >> frame->subframes[ch].rc.porder;
int res_cnt = psize - frame->subframes[ch].order; int res_cnt = psize - frame->subframes[ch].order;
int rice_len = 4 + (int)coding_method;
// residual // residual
int j = frame->subframes[ch].order; int j = frame->subframes[ch].order;
int* r = frame->subframes[ch].residual + j; int* r = frame->subframes[ch].residual + j;
for (int p = 0; p < (1 << frame->subframes[ch].rc.porder); p++) 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; if (p == 1) res_cnt = psize;
int n = Math.Min(res_cnt, frame->blocksize - j); 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--) for (int i = n; i > 0; i--)
*(r++) = bitreader.read_unary_signed(); *(r++) = bitreader.readbits_signed((int)k);
else if (k <= 8) }
for (int i = n; i > 0; i--)
*(r++) = bitreader.read_rice_signed8((int)k);
else 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; j += n;
} }
} }
@@ -420,18 +457,32 @@ namespace CUETools.Codecs.FLAKE
int* data = sub->samples + sub->order; int* data = sub->samples + sub->order;
int* residual = sub->residual + sub->order; int* residual = sub->residual + sub->order;
int data_len = frame->blocksize - sub->order; int data_len = frame->blocksize - sub->order;
int s0, s1, s2;
switch (sub->order) switch (sub->order)
{ {
case 0: case 0:
Flake.memcpy(data, residual, data_len); Flake.memcpy(data, residual, data_len);
break; break;
case 1: case 1:
for (int i = 0; i < data_len; i++) s1 = data[-1];
data[i] = residual[i] + data[i - 1]; for (int i = data_len; i > 0; i--)
{
s1 += *(residual++);
*(data++) = s1;
}
//data[i] = residual[i] + data[i - 1];
break; break;
case 2: case 2:
for (int i = 0; i < data_len; i++) s2 = data[-2];
data[i] = residual[i] + (data[i - 1] << 1) - data[i - 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; break;
case 3: case 3:
for (int i = 0; i < data_len; i++) 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) unsafe void restore_samples_lpc(FlacFrame* frame, int ch)
{ {
FlacSubframe* sub = frame->subframes + ch; FlacSubframe* sub = frame->subframes + ch;
ulong csum = 0;
if ((ulong)sub->order * ((1UL << (int)sub->obits) - 1) * ((1U << sub->cbits) - 1) >= (1UL << 32)) 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); lpc.decode_residual_long(sub->residual, sub->samples, frame->blocksize, sub->order, sub->coefs, sub->shift);
else else
lpc.decode_residual(sub->residual, sub->samples, frame->blocksize, sub->order, sub->coefs, sub->shift); 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) if (frame->subframes[ch].wbits != 0)
{ {
int* s = frame->subframes[ch].samples;
int x = (int) frame->subframes[ch].wbits; int x = (int) frame->subframes[ch].wbits;
for (int i = 0; i < frame->blocksize; i++) for (int i = frame->blocksize; i > 0; i--)
frame->subframes[ch].samples[i] <<= x; *(s++) <<= x;
} }
} }
if (frame->ch_mode != ChannelMode.NotStereo)
{
int* l = frame->subframes[0].samples;
int* r = frame->subframes[1].samples;
switch (frame->ch_mode) switch (frame->ch_mode)
{ {
case ChannelMode.NotStereo:
break;
case ChannelMode.LeftRight: case ChannelMode.LeftRight:
break; break;
case ChannelMode.MidSide: 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 mid = *l;
int side = frame->subframes[1].samples[i]; int side = *r;
mid <<= 1; mid <<= 1;
mid |= (side & 1); /* i.e. if 'side' is odd... */ mid |= (side & 1); /* i.e. if 'side' is odd... */
frame->subframes[0].samples[i] = (mid + side) >> 1; *(l++) = (mid + side) >> 1;
frame->subframes[1].samples[i] = (mid - side) >> 1; *(r++) = (mid - side) >> 1;
} }
break; break;
case ChannelMode.LeftSide: case ChannelMode.LeftSide:
for (int i = 0; i < frame->blocksize; i++) for (int i = frame->blocksize; i > 0; i--)
frame->subframes[1].samples[i] = frame->subframes[0].samples[i] - frame->subframes[1].samples[i]; {
int _l = *(l++), _r = *r;
*(r++) = _l - _r;
}
break; break;
case ChannelMode.RightSide: case ChannelMode.RightSide:
for (int i = 0; i < frame->blocksize; i++) for (int i = frame->blocksize; i > 0; i--)
frame->subframes[0].samples[i] += frame->subframes[1].samples[i]; *(l++) += *(r++);
break; break;
} }
} }
}
public unsafe int DecodeFrame(byte[] buffer, int pos, int len) 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; FlacFrame frame;
FlacSubframe* subframes = stackalloc FlacSubframe[channels]; FlacSubframe* subframes = stackalloc FlacSubframe[channels];
frame.subframes = subframes; frame.subframes = subframes;
@@ -521,10 +583,10 @@ namespace CUETools.Codecs.FLAKE
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);
restore_samples(&frame);
_samplesInBuffer = (uint)frame.blocksize; _samplesInBuffer = (uint)frame.blocksize;
return bitreader.Position - pos; return bitreader.Position - pos;
} }
}
bool skip_bytes(int bytes) bool skip_bytes(int bytes)
@@ -535,7 +597,7 @@ namespace CUETools.Codecs.FLAKE
return true; return true;
} }
void decode_metadata() unsafe void decode_metadata()
{ {
byte x; byte x;
int i, id; int i, id;
@@ -597,9 +659,10 @@ namespace CUETools.Codecs.FLAKE
do do
{ {
long pos = _IO.Position;
fill_frames_buffer(); 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; bool is_last = bitreader.readbit() != 0;
MetadataType type = (MetadataType)bitreader.readbits(7); MetadataType type = (MetadataType)bitreader.readbits(7);
int len = (int)bitreader.readbits(24); 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); sample_rate = (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN);
channels = 1 + (int)bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_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); 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); 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) if (_framesBufferLength < 4 + len)
{ {
_IO.Position = pos + 4 + len; _IO.Position += 4 + len - _framesBufferLength;
_framesBufferLength = 0; _framesBufferLength = 0;
} }
else else
@@ -638,7 +716,9 @@ namespace CUETools.Codecs.FLAKE
} }
if (is_last) if (is_last)
break; break;
}
} while (true); } while (true);
first_frame_offset = _IO.Position - _framesBufferLength;
} }
} }
} }

View File

@@ -80,14 +80,6 @@ namespace CUETools.Codecs.FLAKE
if (channelCount != 2) if (channelCount != 2)
throw new Exception("ChannelCount must be 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; channels = channelCount;
sample_rate = sampleRate; sample_rate = sampleRate;
bits_per_sample = (uint) bitsPerSample; bits_per_sample = (uint) bitsPerSample;
@@ -334,9 +326,9 @@ namespace CUETools.Codecs.FLAKE
{ {
for (i = 0; i < 15; i++) 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_code0 = i;
frame->bs_code1 = -1; frame->bs_code1 = -1;
break; break;
@@ -394,7 +386,7 @@ namespace CUETools.Codecs.FLAKE
// return (uint)k_opt; // 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; int k_opt = 0;
uint a = n; uint a = n;
@@ -412,7 +404,7 @@ namespace CUETools.Codecs.FLAKE
} }
} }
nbits_best = nbits; nbits_best = nbits;
return (uint)k_opt; return k_opt;
} }
unsafe uint calc_decorr_score(FlacFrame* frame, int ch, FlacSubframe* sub) unsafe uint calc_decorr_score(FlacFrame* frame, int ch, FlacSubframe* sub)
@@ -845,7 +837,7 @@ namespace CUETools.Codecs.FLAKE
int j = sub->order; int j = sub->order;
for (int p = 0; p < (1 << porder); p++) 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); bitwriter.writebits(4, k);
if (p == 1) res_cnt = psize; if (p == 1) res_cnt = psize;
for (int i = 0; i < res_cnt && j < frame->blocksize; i++, j++) 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; } } public string Path { get { return _path; } }
int[] flac_samplerates;
int[] flac_bitdepths;
int[] flac_blocksizes;
string vendor_string = "Flake#0.1"; string vendor_string = "Flake#0.1";
int select_blocksize(int samplerate, int time_ms) 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; int target = (samplerate * time_ms) / 1000;
for (int i = 0; i < flac_blocksizes.Length; i++) for (int i = 0; i < Flake.flac_blocksizes.Length; i++)
if (target >= flac_blocksizes[i] && flac_blocksizes[i] > blocksize) if (target >= Flake.flac_blocksizes[i] && Flake.flac_blocksizes[i] > blocksize)
{ {
blocksize = flac_blocksizes[i]; blocksize = Flake.flac_blocksizes[i];
} }
return blocksize; return blocksize;
} }
@@ -1271,7 +1260,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header // metadata header
bitwriter.writebits(1, last); bitwriter.writebits(1, last);
bitwriter.writebits(7, 0); bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_STREAMINFO);
bitwriter.writebits(24, 34); bitwriter.writebits(24, 34);
if (eparams.variable_block_size > 0) if (eparams.variable_block_size > 0)
@@ -1312,7 +1301,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header // metadata header
bitwriter.writebits(1, last); bitwriter.writebits(1, last);
bitwriter.writebits(7, 4); bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_VORBIS_COMMENT);
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);
@@ -1337,7 +1326,7 @@ namespace CUETools.Codecs.FLAKE
// metadata header // metadata header
bitwriter.writebits(1, last); bitwriter.writebits(1, last);
bitwriter.writebits(7, 1); bitwriter.writebits(7, (int)MetadataType.FLAC__METADATA_TYPE_PADDING);
bitwriter.writebits(24, padlen); bitwriter.writebits(24, padlen);
return padlen + 4; return padlen + 4;
@@ -1384,7 +1373,7 @@ namespace CUETools.Codecs.FLAKE
// find samplerate in table // find samplerate in table
for (i = 4; i < 12; i++) for (i = 4; i < 12; i++)
{ {
if (sample_rate == flac_samplerates[i]) if (sample_rate == Flake.flac_samplerates[i])
{ {
sr_code0 = i; sr_code0 = i;
break; break;
@@ -1397,7 +1386,7 @@ namespace CUETools.Codecs.FLAKE
for (i = 1; i < 8; i++) for (i = 1; i < 8; i++)
{ {
if (bits_per_sample == flac_bitdepths[i]) if (bits_per_sample == Flake.flac_bitdepths[i])
{ {
bps_code = i; bps_code = i;
break; break;