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;