diff --git a/CUETools.Codecs.FLAKE/BitReader.cs b/CUETools.Codecs.FLAKE/BitReader.cs
index 1305464..bb083ea 100644
--- a/CUETools.Codecs.FLAKE/BitReader.cs
+++ b/CUETools.Codecs.FLAKE/BitReader.cs
@@ -4,19 +4,39 @@ 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;
+
+ static readonly byte[] byte_to_unary_table = new byte[]
+ {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 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,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 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,
+ 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; }
}
- public byte[] Buffer
+ public byte* Buffer
{
get
{
@@ -24,110 +44,93 @@ namespace CUETools.Codecs.FLAKE
}
}
- public BitReader(byte[] _buffer, int _pos, int _len)
+ 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,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 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,
- 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
- };
+ cache = peek4();
}
- /* supports reading 1 to 24 bits, in big endian format */
- public uint readbits_24(int bits)
+ public uint peek4()
{
- uint result = (((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16) | (((uint)buffer[pos + 2]) << 8) | ((uint)buffer[pos + 3]);
+ //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;
- result >>= 32 - bits;
-
- int new_accumulator = (_bitaccumulator + bits);
- pos += (new_accumulator >> 3);
- _bitaccumulator = (new_accumulator & 7);
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,33 +138,28 @@ 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)
{
- int val = (int) readbits(bits);
+ int val = (int)readbits(bits);
val <<= (32 - bits);
val >>= (32 - bits);
return val;
@@ -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));
+ }
+ }
+ }
}
}
diff --git a/CUETools.Codecs.FLAKE/Flake.cs b/CUETools.Codecs.FLAKE/Flake.cs
index 794c4a4..4de4f95 100644
--- a/CUETools.Codecs.FLAKE/Flake.cs
+++ b/CUETools.Codecs.FLAKE/Flake.cs
@@ -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
///
FLAC__METADATA_TYPE_PADDING = 1,
+ ///
+ /// APPLICATION block
+ ///
FLAC__METADATA_TYPE_APPLICATION = 2,
- /**< APPLICATION block */
+ ///
+ /// SEEKTABLE block
+ ///
FLAC__METADATA_TYPE_SEEKTABLE = 3,
- /**< SEEKTABLE block */
+ ///
+ /// VORBISCOMMENT block (a.k.a. FLAC tags)
+ ///
FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
- /**< VORBISCOMMENT block (a.k.a. FLAC tags) */
+ ///
+ /// CUESHEET block
+ ///
FLAC__METADATA_TYPE_CUESHEET = 5,
- /**< CUESHEET block */
+ ///
+ /// PICTURE block
+ ///
FLAC__METADATA_TYPE_PICTURE = 6,
- /**< PICTURE block */
+ ///
+ /// marker to denote beginning of undefined type range; this number will increase as new metadata types are added
+ ///
FLAC__METADATA_TYPE_UNDEFINED = 7
- /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
};
}
diff --git a/CUETools.Codecs.FLAKE/FlakeReader.cs b/CUETools.Codecs.FLAKE/FlakeReader.cs
index 21ceb64..6269a28 100644
--- a/CUETools.Codecs.FLAKE/FlakeReader.cs
+++ b/CUETools.Codecs.FLAKE/FlakeReader.cs
@@ -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)
{
- for (int ch = 0; ch < channels ; ch++)
- for (int i = 0; i < count; i++)
- buff[offset + i, ch] = samplesBuffer[_samplesBufferOffset + i + ch * Flake.MAX_BLOCKSIZE];
+ 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++)
+ 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,55 +528,64 @@ 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;
}
}
- switch (frame->ch_mode)
+ if (frame->ch_mode != ChannelMode.NotStereo)
{
- case ChannelMode.NotStereo:
- break;
- case ChannelMode.LeftRight:
- break;
- case ChannelMode.MidSide:
- for (int i = 0; i < frame->blocksize; i++)
- {
- int mid = frame->subframes[0].samples[i];
- int side = frame->subframes[1].samples[i];
- 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;
- }
- 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];
- break;
- case ChannelMode.RightSide:
- for (int i = 0; i < frame->blocksize; i++)
- frame->subframes[0].samples[i] += frame->subframes[1].samples[i];
- break;
+ int* l = frame->subframes[0].samples;
+ int* r = frame->subframes[1].samples;
+ switch (frame->ch_mode)
+ {
+ case ChannelMode.LeftRight:
+ break;
+ case ChannelMode.MidSide:
+ for (int i = frame->blocksize; i > 0; i--)
+ {
+ int mid = *l;
+ int side = *r;
+ mid <<= 1;
+ mid |= (side & 1); /* i.e. if 'side' is odd... */
+ *(l++) = (mid + side) >> 1;
+ *(r++) = (mid - side) >> 1;
+ }
+ break;
+ case ChannelMode.LeftSide:
+ for (int i = frame->blocksize; i > 0; i--)
+ {
+ int _l = *(l++), _r = *r;
+ *(r++) = _l - _r;
+ }
+ break;
+ case ChannelMode.RightSide:
+ for (int i = frame->blocksize; i > 0; i--)
+ *(l++) += *(r++);
+ break;
+ }
}
}
public unsafe int DecodeFrame(byte[] buffer, int pos, int len)
{
- BitReader bitreader = new BitReader(buffer, pos, len);
- FlacFrame frame;
- FlacSubframe* subframes = stackalloc FlacSubframe[channels];
- frame.subframes = subframes;
- decode_frame_header(bitreader, &frame);
- decode_subframes(bitreader, &frame);
- bitreader.flush();
- ushort crc = crc16.ComputeChecksum(bitreader.Buffer, pos, bitreader.Position - pos);
- if (crc != bitreader.readbits(16))
- throw new Exception("frame crc mismatch");
- restore_samples(&frame);
- restore_samples(&frame);
- _samplesInBuffer = (uint)frame.blocksize;
- return bitreader.Position - pos;
+ fixed (byte* buf = buffer)
+ {
+ BitReader bitreader = new BitReader(buf, pos, len);
+ FlacFrame frame;
+ FlacSubframe* subframes = stackalloc FlacSubframe[channels];
+ frame.subframes = subframes;
+ decode_frame_header(bitreader, &frame);
+ decode_subframes(bitreader, &frame);
+ bitreader.flush();
+ ushort crc = crc16.ComputeChecksum(bitreader.Buffer, pos, bitreader.Position - pos);
+ if (crc != bitreader.readbits(16))
+ throw new Exception("frame crc mismatch");
+ restore_samples(&frame);
+ _samplesInBuffer = (uint)frame.blocksize;
+ return bitreader.Position - pos;
+ }
}
@@ -535,7 +597,7 @@ namespace CUETools.Codecs.FLAKE
return true;
}
- void decode_metadata()
+ unsafe void decode_metadata()
{
byte x;
int i, id;
@@ -597,48 +659,66 @@ namespace CUETools.Codecs.FLAKE
do
{
- long pos = _IO.Position;
fill_frames_buffer();
- BitReader bitreader = new BitReader(_framesBuffer, _framesBufferOffset, _framesBufferLength - _framesBufferOffset);
- bool is_last = bitreader.readbit() != 0;
- MetadataType type = (MetadataType)bitreader.readbits(7);
- int len = (int)bitreader.readbits(24);
+ 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);
- if (type == MetadataType.FLAC__METADATA_TYPE_STREAMINFO)
- {
- const int FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
- const int FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+ if (type == MetadataType.FLAC__METADATA_TYPE_STREAMINFO)
+ {
+ const int FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+ const int FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
- min_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN);
- max_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN);
- min_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN);
- max_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN);
- 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);
- bitreader.skipbits(FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN);
+ min_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN);
+ max_block_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN);
+ min_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN);
+ max_frame_size = bitreader.readbits(FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN);
+ 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 = 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 += 4 + len - _framesBufferLength;
+ _framesBufferLength = 0;
+ }
+ else
+ {
+ _framesBufferLength -= 4 + len;
+ _framesBufferOffset += 4 + len;
+ }
+ if (is_last)
+ break;
}
- if (_framesBufferLength < 4 + len)
- {
- _IO.Position = pos + 4 + len;
- _framesBufferLength = 0;
- }
- else
- {
- _framesBufferLength -= 4 + len;
- _framesBufferOffset += 4 + len;
- }
- if (is_last)
- break;
} while (true);
+ first_frame_offset = _IO.Position - _framesBufferLength;
}
}
}
diff --git a/CUETools.Codecs.FLAKE/FlakeWriter.cs b/CUETools.Codecs.FLAKE/FlakeWriter.cs
index 0974c1e..70f7818 100644
--- a/CUETools.Codecs.FLAKE/FlakeWriter.cs
+++ b/CUETools.Codecs.FLAKE/FlakeWriter.cs
@@ -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;