mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[Refactor] Use collection expressions.
This commit is contained in:
@@ -1,335 +1,309 @@
|
||||
using System;
|
||||
|
||||
namespace CUETools.Codecs
|
||||
namespace CUETools.Codecs;
|
||||
|
||||
public unsafe class BitReader
|
||||
{
|
||||
unsafe public class BitReader
|
||||
byte* bptr_m;
|
||||
int buffer_len_m;
|
||||
|
||||
ulong cache_m;
|
||||
ushort crc16_m;
|
||||
int have_bits_m;
|
||||
|
||||
public BitReader()
|
||||
{
|
||||
#region Static Methods
|
||||
Buffer = null;
|
||||
bptr_m = null;
|
||||
buffer_len_m = 0;
|
||||
have_bits_m = 0;
|
||||
cache_m = 0;
|
||||
crc16_m = 0;
|
||||
}
|
||||
|
||||
public static int log2i(int v)
|
||||
public BitReader(byte* _buffer, int _pos, int _len)
|
||||
{
|
||||
Reset(_buffer, _pos, _len);
|
||||
}
|
||||
|
||||
public int Position => (int)(bptr_m - Buffer - (have_bits_m >> 3));
|
||||
|
||||
public byte* Buffer { get; private set; }
|
||||
|
||||
public void Reset(byte* _buffer, int _pos, int _len)
|
||||
{
|
||||
Buffer = _buffer;
|
||||
bptr_m = _buffer + _pos;
|
||||
buffer_len_m = _len;
|
||||
have_bits_m = 0;
|
||||
cache_m = 0;
|
||||
crc16_m = 0;
|
||||
fill();
|
||||
}
|
||||
|
||||
public void fill()
|
||||
{
|
||||
while(have_bits_m < 56)
|
||||
{
|
||||
return log2i((uint)v);
|
||||
have_bits_m += 8;
|
||||
byte b = *bptr_m++;
|
||||
cache_m |= (ulong)b << 64 - have_bits_m;
|
||||
crc16_m = (ushort)(crc16_m << 8 ^ Crc16.table[crc16_m >> 8 ^ b]);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly byte[] MultiplyDeBruijnBitPosition = new byte[32]
|
||||
{
|
||||
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
||||
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
||||
};
|
||||
|
||||
public static int log2i(ulong v)
|
||||
{
|
||||
v |= v >> 1; // first round down to one less than a power of 2
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
if (v >> 32 == 0)
|
||||
return MultiplyDeBruijnBitPosition[(uint)((uint)v * 0x07C4ACDDU) >> 27];
|
||||
return 32 + MultiplyDeBruijnBitPosition[(uint)((uint)(v >> 32) * 0x07C4ACDDU) >> 27];
|
||||
}
|
||||
|
||||
public static int log2i(uint v)
|
||||
{
|
||||
v |= v >> 1; // first round down to one less than a power of 2
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return MultiplyDeBruijnBitPosition[(uint)(v * 0x07C4ACDDU) >> 27];
|
||||
}
|
||||
|
||||
public static readonly byte[] byte_to_unary_table = new byte[]
|
||||
{
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
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
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
private byte* buffer_m;
|
||||
private byte* bptr_m;
|
||||
private int buffer_len_m;
|
||||
private int have_bits_m;
|
||||
private ulong cache_m;
|
||||
private ushort crc16_m;
|
||||
|
||||
public int Position
|
||||
{
|
||||
get { return (int)(bptr_m - buffer_m - (have_bits_m >> 3)); }
|
||||
}
|
||||
|
||||
public byte* Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return buffer_m;
|
||||
}
|
||||
}
|
||||
|
||||
public BitReader()
|
||||
{
|
||||
buffer_m = null;
|
||||
bptr_m = null;
|
||||
buffer_len_m = 0;
|
||||
have_bits_m = 0;
|
||||
cache_m = 0;
|
||||
crc16_m = 0;
|
||||
}
|
||||
|
||||
public BitReader(byte* _buffer, int _pos, int _len)
|
||||
{
|
||||
Reset(_buffer, _pos, _len);
|
||||
}
|
||||
|
||||
public void Reset(byte* _buffer, int _pos, int _len)
|
||||
{
|
||||
buffer_m = _buffer;
|
||||
bptr_m = _buffer + _pos;
|
||||
buffer_len_m = _len;
|
||||
have_bits_m = 0;
|
||||
cache_m = 0;
|
||||
crc16_m = 0;
|
||||
fill();
|
||||
}
|
||||
|
||||
public void fill()
|
||||
{
|
||||
while (have_bits_m < 56)
|
||||
{
|
||||
have_bits_m += 8;
|
||||
byte b = *(bptr_m++);
|
||||
cache_m |= (ulong)b << (64 - have_bits_m);
|
||||
crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ b]);
|
||||
}
|
||||
}
|
||||
|
||||
/* skip any number of bits */
|
||||
public void skipbits(int bits)
|
||||
{
|
||||
while (bits > have_bits_m)
|
||||
{
|
||||
bits -= have_bits_m;
|
||||
cache_m = 0;
|
||||
have_bits_m = 0;
|
||||
fill();
|
||||
}
|
||||
cache_m <<= bits;
|
||||
have_bits_m -= bits;
|
||||
}
|
||||
|
||||
public long read_long()
|
||||
{
|
||||
return ((long)readbits(32) << 32) | readbits(32);
|
||||
}
|
||||
|
||||
public ulong read_ulong()
|
||||
{
|
||||
return ((ulong)readbits(32) << 32) | readbits(32);
|
||||
}
|
||||
|
||||
public int read_int()
|
||||
{
|
||||
return (int)readbits(sizeof(int));
|
||||
}
|
||||
|
||||
public uint read_uint()
|
||||
{
|
||||
return (uint)readbits(sizeof(uint));
|
||||
}
|
||||
|
||||
public short read_short()
|
||||
{
|
||||
return (short)readbits(16);
|
||||
}
|
||||
|
||||
public ushort read_ushort()
|
||||
{
|
||||
return (ushort)readbits(16);
|
||||
}
|
||||
|
||||
/* supports reading 1 to 32 bits, in big endian format */
|
||||
public uint readbits(int bits)
|
||||
/* skip any number of bits */
|
||||
public void skipbits(int bits)
|
||||
{
|
||||
while(bits > have_bits_m)
|
||||
{
|
||||
bits -= have_bits_m;
|
||||
cache_m = 0;
|
||||
have_bits_m = 0;
|
||||
fill();
|
||||
uint result = (uint)(cache_m >> 64 - bits);
|
||||
skipbits(bits);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* supports reading 1 to 64 bits, in big endian format */
|
||||
public ulong readbits64(int bits)
|
||||
{
|
||||
if (bits <= 56)
|
||||
return readbits(bits);
|
||||
return ((ulong)readbits(32) << bits - 32) | readbits(bits - 32);
|
||||
}
|
||||
cache_m <<= bits;
|
||||
have_bits_m -= bits;
|
||||
}
|
||||
|
||||
/* reads a single bit */
|
||||
public uint readbit()
|
||||
{
|
||||
return readbits(1);
|
||||
}
|
||||
public long read_long() => (long)readbits(32) << 32 | readbits(32);
|
||||
|
||||
public uint read_unary()
|
||||
{
|
||||
fill();
|
||||
uint val = 0;
|
||||
ulong result = cache_m >> 56;
|
||||
while (result == 0)
|
||||
{
|
||||
val += 8;
|
||||
cache_m <<= 8;
|
||||
byte b = *(bptr_m++);
|
||||
cache_m |= (ulong)b << (64 - have_bits_m);
|
||||
crc16_m = (ushort)((crc16_m << 8) ^ Crc16.table[(crc16_m >> 8) ^ b]);
|
||||
result = cache_m >> 56;
|
||||
}
|
||||
val += byte_to_unary_table[result];
|
||||
skipbits((int)(val & 7) + 1);
|
||||
return val;
|
||||
}
|
||||
public ulong read_ulong() => (ulong)readbits(32) << 32 | readbits(32);
|
||||
|
||||
public void flush()
|
||||
{
|
||||
if ((have_bits_m & 7) > 0)
|
||||
{
|
||||
cache_m <<= have_bits_m & 7;
|
||||
have_bits_m -= have_bits_m & 7;
|
||||
}
|
||||
}
|
||||
public int read_int() => (int)readbits(sizeof(int));
|
||||
|
||||
public ushort get_crc16()
|
||||
public uint read_uint() => readbits(sizeof(uint));
|
||||
|
||||
public short read_short() => (short)readbits(16);
|
||||
|
||||
public ushort read_ushort() => (ushort)readbits(16);
|
||||
|
||||
/* supports reading 1 to 32 bits, in big endian format */
|
||||
public uint readbits(int bits)
|
||||
{
|
||||
fill();
|
||||
var result = (uint)(cache_m >> 64 - bits);
|
||||
skipbits(bits);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* supports reading 1 to 64 bits, in big endian format */
|
||||
public ulong readbits64(int bits)
|
||||
{
|
||||
if(bits <= 56) return readbits(bits);
|
||||
|
||||
return (ulong)readbits(32) << bits - 32 | readbits(bits - 32);
|
||||
}
|
||||
|
||||
/* reads a single bit */
|
||||
public uint readbit() => readbits(1);
|
||||
|
||||
public uint read_unary()
|
||||
{
|
||||
fill();
|
||||
uint val = 0;
|
||||
ulong result = cache_m >> 56;
|
||||
|
||||
while(result == 0)
|
||||
{
|
||||
if (have_bits_m == 0)
|
||||
return crc16_m;
|
||||
ushort crc = 0;
|
||||
int n = have_bits_m >> 3;
|
||||
for (int i = 0; i < n; i++)
|
||||
crc = (ushort)((crc << 8) ^ Crc16.table[(crc >> 8) ^ (byte)(cache_m >> (56 - (i << 3)))]);
|
||||
return Crc16.Subtract(crc16_m, crc, n);
|
||||
val += 8;
|
||||
cache_m <<= 8;
|
||||
byte b = *bptr_m++;
|
||||
cache_m |= (ulong)b << 64 - have_bits_m;
|
||||
crc16_m = (ushort)(crc16_m << 8 ^ Crc16.table[crc16_m >> 8 ^ b]);
|
||||
result = cache_m >> 56;
|
||||
}
|
||||
|
||||
public int readbits_signed(int bits)
|
||||
{
|
||||
int val = (int)readbits(bits);
|
||||
val <<= (32 - bits);
|
||||
val >>= (32 - bits);
|
||||
return val;
|
||||
}
|
||||
val += byte_to_unary_table[result];
|
||||
skipbits((int)(val & 7) + 1);
|
||||
|
||||
public uint read_utf8()
|
||||
{
|
||||
uint x = readbits(8);
|
||||
uint v;
|
||||
int i;
|
||||
if (0 == (x & 0x80))
|
||||
{
|
||||
v = x;
|
||||
i = 0;
|
||||
}
|
||||
else if (0xC0 == (x & 0xE0)) /* 110xxxxx */
|
||||
{
|
||||
v = x & 0x1F;
|
||||
i = 1;
|
||||
}
|
||||
else if (0xE0 == (x & 0xF0)) /* 1110xxxx */
|
||||
{
|
||||
v = x & 0x0F;
|
||||
i = 2;
|
||||
}
|
||||
else if (0xF0 == (x & 0xF8)) /* 11110xxx */
|
||||
{
|
||||
v = x & 0x07;
|
||||
i = 3;
|
||||
}
|
||||
else if (0xF8 == (x & 0xFC)) /* 111110xx */
|
||||
{
|
||||
v = x & 0x03;
|
||||
i = 4;
|
||||
}
|
||||
else if (0xFC == (x & 0xFE)) /* 1111110x */
|
||||
{
|
||||
v = x & 0x01;
|
||||
i = 5;
|
||||
}
|
||||
else if (0xFE == x) /* 11111110 */
|
||||
{
|
||||
v = 0;
|
||||
i = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("invalid utf8 encoding");
|
||||
}
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
x = readbits(8);
|
||||
if (0x80 != (x & 0xC0)) /* 10xxxxxx */
|
||||
throw new Exception("invalid utf8 encoding");
|
||||
v <<= 6;
|
||||
v |= (x & 0x3F);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public void read_rice_block(int n, int k, int* r)
|
||||
{
|
||||
fill();
|
||||
fixed (byte* unary_table = byte_to_unary_table)
|
||||
fixed (ushort* t = Crc16.table)
|
||||
public void flush()
|
||||
{
|
||||
if((have_bits_m & 7) > 0)
|
||||
{
|
||||
cache_m <<= have_bits_m & 7;
|
||||
have_bits_m -= have_bits_m & 7;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort get_crc16()
|
||||
{
|
||||
if(have_bits_m == 0) return crc16_m;
|
||||
ushort crc = 0;
|
||||
int n = have_bits_m >> 3;
|
||||
for(var i = 0; i < n; i++) crc = (ushort)(crc << 8 ^ Crc16.table[crc >> 8 ^ (byte)(cache_m >> 56 - (i << 3))]);
|
||||
|
||||
return Crc16.Subtract(crc16_m, crc, n);
|
||||
}
|
||||
|
||||
public int readbits_signed(int bits)
|
||||
{
|
||||
var val = (int)readbits(bits);
|
||||
val <<= 32 - bits;
|
||||
val >>= 32 - bits;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public uint read_utf8()
|
||||
{
|
||||
uint x = readbits(8);
|
||||
uint v;
|
||||
int i;
|
||||
|
||||
if(0 == (x & 0x80))
|
||||
{
|
||||
v = x;
|
||||
i = 0;
|
||||
}
|
||||
else if(0xC0 == (x & 0xE0)) /* 110xxxxx */
|
||||
{
|
||||
v = x & 0x1F;
|
||||
i = 1;
|
||||
}
|
||||
else if(0xE0 == (x & 0xF0)) /* 1110xxxx */
|
||||
{
|
||||
v = x & 0x0F;
|
||||
i = 2;
|
||||
}
|
||||
else if(0xF0 == (x & 0xF8)) /* 11110xxx */
|
||||
{
|
||||
v = x & 0x07;
|
||||
i = 3;
|
||||
}
|
||||
else if(0xF8 == (x & 0xFC)) /* 111110xx */
|
||||
{
|
||||
v = x & 0x03;
|
||||
i = 4;
|
||||
}
|
||||
else if(0xFC == (x & 0xFE)) /* 1111110x */
|
||||
{
|
||||
v = x & 0x01;
|
||||
i = 5;
|
||||
}
|
||||
else if(0xFE == x) /* 11111110 */
|
||||
{
|
||||
v = 0;
|
||||
i = 6;
|
||||
}
|
||||
else
|
||||
throw new Exception("invalid utf8 encoding");
|
||||
|
||||
for(; i > 0; i--)
|
||||
{
|
||||
x = readbits(8);
|
||||
|
||||
if(0x80 != (x & 0xC0)) /* 10xxxxxx */ throw new Exception("invalid utf8 encoding");
|
||||
v <<= 6;
|
||||
v |= x & 0x3F;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public void read_rice_block(int n, int k, int* r)
|
||||
{
|
||||
fill();
|
||||
|
||||
fixed(byte* unary_table = byte_to_unary_table)
|
||||
{
|
||||
fixed(ushort* t = Crc16.table)
|
||||
{
|
||||
uint mask = (1U << k) - 1;
|
||||
byte* bptr = bptr_m;
|
||||
int have_bits = have_bits_m;
|
||||
ulong cache = cache_m;
|
||||
ushort crc = crc16_m;
|
||||
for (int i = n; i > 0; i--)
|
||||
uint mask = (1U << k) - 1;
|
||||
byte* bptr = bptr_m;
|
||||
int have_bits = have_bits_m;
|
||||
ulong cache = cache_m;
|
||||
ushort crc = crc16_m;
|
||||
|
||||
for(int i = n; i > 0; i--)
|
||||
{
|
||||
uint bits;
|
||||
uint bits;
|
||||
byte* orig_bptr = bptr;
|
||||
while ((bits = unary_table[cache >> 56]) == 8)
|
||||
|
||||
while((bits = unary_table[cache >> 56]) == 8)
|
||||
{
|
||||
cache <<= 8;
|
||||
byte b = *(bptr++);
|
||||
cache |= (ulong)b << (64 - have_bits);
|
||||
crc = (ushort)((crc << 8) ^ t[(crc >> 8) ^ b]);
|
||||
}
|
||||
uint msbs = bits + ((uint)(bptr - orig_bptr) << 3);
|
||||
// assumes k <= 41 (have_bits < 41 + 7 + 1 + 8 == 57, so we don't loose bits here)
|
||||
while (have_bits < 56)
|
||||
{
|
||||
have_bits += 8;
|
||||
byte b = *(bptr++);
|
||||
cache |= (ulong)b << (64 - have_bits);
|
||||
crc = (ushort)((crc << 8) ^ t[(crc >> 8) ^ b]);
|
||||
byte b = *bptr++;
|
||||
cache |= (ulong)b << 64 - have_bits;
|
||||
crc = (ushort)(crc << 8 ^ t[crc >> 8 ^ b]);
|
||||
}
|
||||
|
||||
int btsk = k + (int)bits + 1;
|
||||
uint uval = (msbs << k) | (uint)((cache >> (64 - btsk)) & mask);
|
||||
cache <<= btsk;
|
||||
have_bits -= btsk;
|
||||
*(r++) = (int)(uval >> 1 ^ -(int)(uval & 1));
|
||||
uint msbs = bits + ((uint)(bptr - orig_bptr) << 3);
|
||||
|
||||
// assumes k <= 41 (have_bits < 41 + 7 + 1 + 8 == 57, so we don't loose bits here)
|
||||
while(have_bits < 56)
|
||||
{
|
||||
have_bits += 8;
|
||||
byte b = *bptr++;
|
||||
cache |= (ulong)b << 64 - have_bits;
|
||||
crc = (ushort)(crc << 8 ^ t[crc >> 8 ^ b]);
|
||||
}
|
||||
|
||||
int btsk = k + (int)bits + 1;
|
||||
uint uval = msbs << k | (uint)(cache >> 64 - btsk & mask);
|
||||
cache <<= btsk;
|
||||
have_bits -= btsk;
|
||||
*r++ = (int)(uval >> 1 ^ -(int)(uval & 1));
|
||||
}
|
||||
|
||||
have_bits_m = have_bits;
|
||||
cache_m = cache;
|
||||
bptr_m = bptr;
|
||||
crc16_m = crc;
|
||||
cache_m = cache;
|
||||
bptr_m = bptr;
|
||||
crc16_m = crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Static Methods
|
||||
|
||||
public static int log2i(int v) => log2i((uint)v);
|
||||
|
||||
public static readonly byte[] MultiplyDeBruijnBitPosition =
|
||||
[
|
||||
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26,
|
||||
5, 4, 31
|
||||
];
|
||||
|
||||
public static int log2i(ulong v)
|
||||
{
|
||||
v |= v >> 1; // first round down to one less than a power of 2
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
|
||||
if(v >> 32 == 0) return MultiplyDeBruijnBitPosition[(uint)v * 0x07C4ACDDU >> 27];
|
||||
|
||||
return 32 + MultiplyDeBruijnBitPosition[(uint)(v >> 32) * 0x07C4ACDDU >> 27];
|
||||
}
|
||||
|
||||
public static int log2i(uint v)
|
||||
{
|
||||
v |= v >> 1; // first round down to one less than a power of 2
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
|
||||
return MultiplyDeBruijnBitPosition[v * 0x07C4ACDDU >> 27];
|
||||
}
|
||||
|
||||
public static readonly byte[] byte_to_unary_table =
|
||||
[
|
||||
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
|
||||
];
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,51 +1,54 @@
|
||||
namespace CUETools.Codecs
|
||||
namespace CUETools.Codecs;
|
||||
|
||||
public enum InitialCrcValue
|
||||
{
|
||||
public enum InitialCrcValue { Zeros, NonZero1 = 0xffff, NonZero2 = 0x1D0F }
|
||||
|
||||
public class Crc16Ccitt
|
||||
{
|
||||
const ushort poly = 4129;
|
||||
ushort[] table = new ushort[256];
|
||||
ushort initialValue = 0;
|
||||
|
||||
public ushort ComputeChecksum(byte[] bytes, int pos, int count)
|
||||
{
|
||||
ushort crc = this.initialValue;
|
||||
for (int i = pos; i < pos + count; i++)
|
||||
{
|
||||
crc = (ushort)((crc << 8) ^ table[((crc >> 8) ^ (0xff & bytes[i]))]);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
public byte[] ComputeChecksumBytes(byte[] bytes, int pos, int count)
|
||||
{
|
||||
ushort crc = ComputeChecksum(bytes, pos, count);
|
||||
return new byte[] { (byte)(crc >> 8), (byte)(crc & 0x00ff) };
|
||||
}
|
||||
|
||||
public Crc16Ccitt(InitialCrcValue initialValue)
|
||||
{
|
||||
this.initialValue = (ushort)initialValue;
|
||||
ushort temp, a;
|
||||
for (int i = 0; i < table.Length; i++)
|
||||
{
|
||||
temp = 0;
|
||||
a = (ushort)(i << 8);
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if (((temp ^ a) & 0x8000) != 0)
|
||||
{
|
||||
temp = (ushort)((temp << 1) ^ poly);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp <<= 1;
|
||||
}
|
||||
a <<= 1;
|
||||
}
|
||||
table[i] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
Zeros,
|
||||
NonZero1 = 0xffff,
|
||||
NonZero2 = 0x1D0F
|
||||
}
|
||||
|
||||
public class Crc16Ccitt
|
||||
{
|
||||
const ushort poly = 4129;
|
||||
readonly ushort initialValue;
|
||||
readonly ushort[] table = new ushort[256];
|
||||
|
||||
public Crc16Ccitt(InitialCrcValue initialValue)
|
||||
{
|
||||
this.initialValue = (ushort)initialValue;
|
||||
ushort temp, a;
|
||||
|
||||
for(var i = 0; i < table.Length; i++)
|
||||
{
|
||||
temp = 0;
|
||||
a = (ushort)(i << 8);
|
||||
|
||||
for(var j = 0; j < 8; j++)
|
||||
{
|
||||
if(((temp ^ a) & 0x8000) != 0)
|
||||
temp = (ushort)(temp << 1 ^ poly);
|
||||
else
|
||||
temp <<= 1;
|
||||
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
table[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort ComputeChecksum(byte[] bytes, int pos, int count)
|
||||
{
|
||||
ushort crc = initialValue;
|
||||
for(int i = pos; i < pos + count; i++) crc = (ushort)(crc << 8 ^ table[crc >> 8 ^ 0xff & bytes[i]]);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
public byte[] ComputeChecksumBytes(byte[] bytes, int pos, int count)
|
||||
{
|
||||
ushort crc = ComputeChecksum(bytes, pos, count);
|
||||
|
||||
return [(byte)(crc >> 8), (byte)(crc & 0x00ff)];
|
||||
}
|
||||
}
|
||||
@@ -1,94 +1,296 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using CUETools.Codecs.CommandLine;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CUETools.Codecs
|
||||
namespace CUETools.Codecs;
|
||||
|
||||
public class CUEToolsCodecsConfig
|
||||
{
|
||||
public class CUEToolsCodecsConfig
|
||||
public List<IAudioDecoderSettings> decoders;
|
||||
[JsonIgnore]
|
||||
public DecoderListViewModel decodersViewModel;
|
||||
public List<IAudioEncoderSettings> encoders;
|
||||
[JsonIgnore]
|
||||
public EncoderListViewModel encodersViewModel;
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, CUEToolsFormat> formats;
|
||||
|
||||
public CUEToolsCodecsConfig()
|
||||
{
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, CUEToolsFormat> formats;
|
||||
public List<IAudioEncoderSettings> encoders;
|
||||
public List<IAudioDecoderSettings> decoders;
|
||||
[JsonIgnore]
|
||||
public EncoderListViewModel encodersViewModel;
|
||||
[JsonIgnore]
|
||||
public DecoderListViewModel decodersViewModel;
|
||||
|
||||
public CUEToolsCodecsConfig()
|
||||
{
|
||||
encoders = new List<IAudioEncoderSettings>();
|
||||
decoders = new List<IAudioDecoderSettings>();
|
||||
encodersViewModel = new EncoderListViewModel(encoders);
|
||||
decodersViewModel = new DecoderListViewModel(decoders);
|
||||
formats = new Dictionary<string, CUEToolsFormat>();
|
||||
}
|
||||
|
||||
public CUEToolsCodecsConfig(CUEToolsCodecsConfig src)
|
||||
{
|
||||
encoders = new List<IAudioEncoderSettings>();
|
||||
decoders = new List<IAudioDecoderSettings>();
|
||||
src.encoders.ForEach(item => encoders.Add(item.Clone()));
|
||||
src.decoders.ForEach(item => decoders.Add(item.Clone()));
|
||||
encodersViewModel = new EncoderListViewModel(encoders);
|
||||
decodersViewModel = new DecoderListViewModel(decoders);
|
||||
formats = new Dictionary<string, CUEToolsFormat>();
|
||||
foreach (var fmt in src.formats)
|
||||
formats.Add(fmt.Key, fmt.Value.Clone(this));
|
||||
}
|
||||
|
||||
public void Init(List<IAudioEncoderSettings> src_encoders, List<IAudioDecoderSettings> src_decoders)
|
||||
{
|
||||
encoders = new List<IAudioEncoderSettings>();
|
||||
decoders = new List<IAudioDecoderSettings>();
|
||||
src_encoders.ForEach(item => encoders.Add(item.Clone()));
|
||||
src_decoders.ForEach(item => decoders.Add(item.Clone()));
|
||||
|
||||
if (Type.GetType("Mono.Runtime", false) == null)
|
||||
{
|
||||
encoders.Add(new CommandLine.EncoderSettings("flake.exe", "flac", true, "0 1 2 3 4 5 6 7 8 9 10 11 12", "8", "flake.exe", "-%M - -o %O -p %P"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("takc.exe", "tak", true, "0 1 2 2e 2m 3 3e 3m 4 4e 4m", "2", "takc.exe", "-e -p%M -overwrite - %O"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("ffmpeg.exe", "m4a", true, "", "", "ffmpeg.exe", "-i - -f ipod -acodec alac -y %O"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("lame.exe (VBR)", "mp3", false, "V9 V8 V7 V6 V5 V4 V3 V2 V1 V0", "V2", "lame.exe", "--vbr-new -%M - %O"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("lame.exe (CBR)", "mp3", false, "96 128 192 256 320", "256", "lame.exe", "-m s -q 0 -b %M --noreplaygain - %O"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("oggenc.exe", "ogg", false, "-1 -0.5 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8", "3", "oggenc.exe", "-q %M - -o %O"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("opusenc.exe", "opus", false, "6 16 32 48 64 96 128 192 256", "128", "opusenc.exe", "--bitrate %M - %O"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("neroAacEnc.exe", "m4a", false, "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9", "0.4", "neroAacEnc.exe", "-q %M -if - -of %O"));
|
||||
encoders.Add(new CommandLine.EncoderSettings("qaac.exe (tvbr)", "m4a", false, "10 20 30 40 50 60 70 80 90 100 110 127", "80", "qaac.exe", "-s -V %M -q 2 - -o %O"));
|
||||
|
||||
decoders.Add(new CommandLine.DecoderSettings("takc.exe", "tak", "takc.exe", "-d %I -"));
|
||||
decoders.Add(new CommandLine.DecoderSettings("ffmpeg.exe", "m4a", "ffmpeg.exe", "-v 0 -i %I -f wav -"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// !!!
|
||||
}
|
||||
|
||||
encodersViewModel = new EncoderListViewModel(encoders);
|
||||
decodersViewModel = new DecoderListViewModel(decoders);
|
||||
|
||||
formats = new Dictionary<string, CUEToolsFormat>();
|
||||
formats.Add("flac", new CUEToolsFormat("flac", CUEToolsTagger.TagLibSharp, true, false, true, true, encodersViewModel.GetDefault("flac", true), null, decodersViewModel.GetDefault("flac")));
|
||||
formats.Add("wv", new CUEToolsFormat("wv", CUEToolsTagger.TagLibSharp, true, false, true, true, encodersViewModel.GetDefault("wv", true), null, decodersViewModel.GetDefault("wv")));
|
||||
formats.Add("ape", new CUEToolsFormat("ape", CUEToolsTagger.TagLibSharp, true, false, true, true, encodersViewModel.GetDefault("ape", true), null, decodersViewModel.GetDefault("ape")));
|
||||
formats.Add("tta", new CUEToolsFormat("tta", CUEToolsTagger.APEv2, true, false, false, true, encodersViewModel.GetDefault("tta", true), null, decodersViewModel.GetDefault("tta")));
|
||||
formats.Add("m2ts", new CUEToolsFormat("m2ts", CUEToolsTagger.APEv2, true, false, false, true, null, null, decodersViewModel.GetDefault("m2ts")));
|
||||
formats.Add("mpls", new CUEToolsFormat("mpls", CUEToolsTagger.APEv2, true, false, false, true, null, null, decodersViewModel.GetDefault("mpls")));
|
||||
formats.Add("wav", new CUEToolsFormat("wav", CUEToolsTagger.TagLibSharp, true, false, false, true, encodersViewModel.GetDefault("wav", true), null, decodersViewModel.GetDefault("wav")));
|
||||
formats.Add("m4a", new CUEToolsFormat("m4a", CUEToolsTagger.TagLibSharp, true, true, false, true, encodersViewModel.GetDefault("m4a", true), encodersViewModel.GetDefault("m4a", false), decodersViewModel.GetDefault("m4a")));
|
||||
formats.Add("tak", new CUEToolsFormat("tak", CUEToolsTagger.APEv2, true, false, true, true, encodersViewModel.GetDefault("tak", true), null, decodersViewModel.GetDefault("tak")));
|
||||
formats.Add("wma", new CUEToolsFormat("wma", CUEToolsTagger.TagLibSharp, true, true, false, true, encodersViewModel.GetDefault("wma", true), encodersViewModel.GetDefault("wma", false), decodersViewModel.GetDefault("wma")));
|
||||
formats.Add("mp3", new CUEToolsFormat("mp3", CUEToolsTagger.TagLibSharp, false, true, false, true, null, encodersViewModel.GetDefault("mp3", false), null));
|
||||
formats.Add("ogg", new CUEToolsFormat("ogg", CUEToolsTagger.TagLibSharp, false, true, false, true, null, encodersViewModel.GetDefault("ogg", false), null));
|
||||
formats.Add("opus", new CUEToolsFormat("opus", CUEToolsTagger.TagLibSharp, false, true, false, true, null, encodersViewModel.GetDefault("opus", false), null));
|
||||
formats.Add("mlp", new CUEToolsFormat("mlp", CUEToolsTagger.APEv2, true, false, false, false, null, null, decodersViewModel.GetDefault("mlp")));
|
||||
formats.Add("aob", new CUEToolsFormat("aob", CUEToolsTagger.APEv2, true, false, false, false, null, null, decodersViewModel.GetDefault("aob")));
|
||||
}
|
||||
encoders = [];
|
||||
decoders = [];
|
||||
encodersViewModel = new EncoderListViewModel(encoders);
|
||||
decodersViewModel = new DecoderListViewModel(decoders);
|
||||
formats = new Dictionary<string, CUEToolsFormat>();
|
||||
}
|
||||
}
|
||||
|
||||
public CUEToolsCodecsConfig(CUEToolsCodecsConfig src)
|
||||
{
|
||||
encoders = [];
|
||||
decoders = [];
|
||||
src.encoders.ForEach(item => encoders.Add(item.Clone()));
|
||||
src.decoders.ForEach(item => decoders.Add(item.Clone()));
|
||||
encodersViewModel = new EncoderListViewModel(encoders);
|
||||
decodersViewModel = new DecoderListViewModel(decoders);
|
||||
formats = new Dictionary<string, CUEToolsFormat>();
|
||||
foreach(KeyValuePair<string, CUEToolsFormat> fmt in src.formats) formats.Add(fmt.Key, fmt.Value.Clone(this));
|
||||
}
|
||||
|
||||
public void Init(List<IAudioEncoderSettings> src_encoders, List<IAudioDecoderSettings> src_decoders)
|
||||
{
|
||||
encoders = [];
|
||||
decoders = [];
|
||||
src_encoders.ForEach(item => encoders.Add(item.Clone()));
|
||||
src_decoders.ForEach(item => decoders.Add(item.Clone()));
|
||||
|
||||
if(Type.GetType("Mono.Runtime", false) == null)
|
||||
{
|
||||
encoders.Add(new EncoderSettings("flake.exe",
|
||||
"flac",
|
||||
true,
|
||||
"0 1 2 3 4 5 6 7 8 9 10 11 12",
|
||||
"8",
|
||||
"flake.exe",
|
||||
"-%M - -o %O -p %P"));
|
||||
|
||||
encoders.Add(new EncoderSettings("takc.exe",
|
||||
"tak",
|
||||
true,
|
||||
"0 1 2 2e 2m 3 3e 3m 4 4e 4m",
|
||||
"2",
|
||||
"takc.exe",
|
||||
"-e -p%M -overwrite - %O"));
|
||||
|
||||
encoders.Add(new EncoderSettings("ffmpeg.exe",
|
||||
"m4a",
|
||||
true,
|
||||
"",
|
||||
"",
|
||||
"ffmpeg.exe",
|
||||
"-i - -f ipod -acodec alac -y %O"));
|
||||
|
||||
encoders.Add(new EncoderSettings("lame.exe (VBR)",
|
||||
"mp3",
|
||||
false,
|
||||
"V9 V8 V7 V6 V5 V4 V3 V2 V1 V0",
|
||||
"V2",
|
||||
"lame.exe",
|
||||
"--vbr-new -%M - %O"));
|
||||
|
||||
encoders.Add(new EncoderSettings("lame.exe (CBR)",
|
||||
"mp3",
|
||||
false,
|
||||
"96 128 192 256 320",
|
||||
"256",
|
||||
"lame.exe",
|
||||
"-m s -q 0 -b %M --noreplaygain - %O"));
|
||||
|
||||
encoders.Add(new EncoderSettings("oggenc.exe",
|
||||
"ogg",
|
||||
false,
|
||||
"-1 -0.5 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8",
|
||||
"3",
|
||||
"oggenc.exe",
|
||||
"-q %M - -o %O"));
|
||||
|
||||
encoders.Add(new EncoderSettings("opusenc.exe",
|
||||
"opus",
|
||||
false,
|
||||
"6 16 32 48 64 96 128 192 256",
|
||||
"128",
|
||||
"opusenc.exe",
|
||||
"--bitrate %M - %O"));
|
||||
|
||||
encoders.Add(new EncoderSettings("neroAacEnc.exe",
|
||||
"m4a",
|
||||
false,
|
||||
"0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9",
|
||||
"0.4",
|
||||
"neroAacEnc.exe",
|
||||
"-q %M -if - -of %O"));
|
||||
|
||||
encoders.Add(new EncoderSettings("qaac.exe (tvbr)",
|
||||
"m4a",
|
||||
false,
|
||||
"10 20 30 40 50 60 70 80 90 100 110 127",
|
||||
"80",
|
||||
"qaac.exe",
|
||||
"-s -V %M -q 2 - -o %O"));
|
||||
|
||||
decoders.Add(new DecoderSettings("takc.exe", "tak", "takc.exe", "-d %I -"));
|
||||
decoders.Add(new DecoderSettings("ffmpeg.exe", "m4a", "ffmpeg.exe", "-v 0 -i %I -f wav -"));
|
||||
}
|
||||
|
||||
// !!!
|
||||
encodersViewModel = new EncoderListViewModel(encoders);
|
||||
decodersViewModel = new DecoderListViewModel(decoders);
|
||||
|
||||
formats = new Dictionary<string, CUEToolsFormat>();
|
||||
|
||||
formats.Add("flac",
|
||||
new CUEToolsFormat("flac",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
encodersViewModel.GetDefault("flac", true),
|
||||
null,
|
||||
decodersViewModel.GetDefault("flac")));
|
||||
|
||||
formats.Add("wv",
|
||||
new CUEToolsFormat("wv",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
encodersViewModel.GetDefault("wv", true),
|
||||
null,
|
||||
decodersViewModel.GetDefault("wv")));
|
||||
|
||||
formats.Add("ape",
|
||||
new CUEToolsFormat("ape",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
encodersViewModel.GetDefault("ape", true),
|
||||
null,
|
||||
decodersViewModel.GetDefault("ape")));
|
||||
|
||||
formats.Add("tta",
|
||||
new CUEToolsFormat("tta",
|
||||
CUEToolsTagger.APEv2,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
encodersViewModel.GetDefault("tta", true),
|
||||
null,
|
||||
decodersViewModel.GetDefault("tta")));
|
||||
|
||||
formats.Add("m2ts",
|
||||
new CUEToolsFormat("m2ts",
|
||||
CUEToolsTagger.APEv2,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
decodersViewModel.GetDefault("m2ts")));
|
||||
|
||||
formats.Add("mpls",
|
||||
new CUEToolsFormat("mpls",
|
||||
CUEToolsTagger.APEv2,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
decodersViewModel.GetDefault("mpls")));
|
||||
|
||||
formats.Add("wav",
|
||||
new CUEToolsFormat("wav",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
encodersViewModel.GetDefault("wav", true),
|
||||
null,
|
||||
decodersViewModel.GetDefault("wav")));
|
||||
|
||||
formats.Add("m4a",
|
||||
new CUEToolsFormat("m4a",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
encodersViewModel.GetDefault("m4a", true),
|
||||
encodersViewModel.GetDefault("m4a", false),
|
||||
decodersViewModel.GetDefault("m4a")));
|
||||
|
||||
formats.Add("tak",
|
||||
new CUEToolsFormat("tak",
|
||||
CUEToolsTagger.APEv2,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
encodersViewModel.GetDefault("tak", true),
|
||||
null,
|
||||
decodersViewModel.GetDefault("tak")));
|
||||
|
||||
formats.Add("wma",
|
||||
new CUEToolsFormat("wma",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
encodersViewModel.GetDefault("wma", true),
|
||||
encodersViewModel.GetDefault("wma", false),
|
||||
decodersViewModel.GetDefault("wma")));
|
||||
|
||||
formats.Add("mp3",
|
||||
new CUEToolsFormat("mp3",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
encodersViewModel.GetDefault("mp3", false),
|
||||
null));
|
||||
|
||||
formats.Add("ogg",
|
||||
new CUEToolsFormat("ogg",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
encodersViewModel.GetDefault("ogg", false),
|
||||
null));
|
||||
|
||||
formats.Add("opus",
|
||||
new CUEToolsFormat("opus",
|
||||
CUEToolsTagger.TagLibSharp,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
encodersViewModel.GetDefault("opus", false),
|
||||
null));
|
||||
|
||||
formats.Add("mlp",
|
||||
new CUEToolsFormat("mlp",
|
||||
CUEToolsTagger.APEv2,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
decodersViewModel.GetDefault("mlp")));
|
||||
|
||||
formats.Add("aob",
|
||||
new CUEToolsFormat("aob",
|
||||
CUEToolsTagger.APEv2,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
decodersViewModel.GetDefault("aob")));
|
||||
}
|
||||
}
|
||||
@@ -1,82 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CUETools.Codecs
|
||||
namespace CUETools.Codecs;
|
||||
|
||||
public interface IAudioSource
|
||||
{
|
||||
public interface IAudioSource
|
||||
{
|
||||
IAudioDecoderSettings Settings { get; }
|
||||
IAudioDecoderSettings Settings { get; }
|
||||
|
||||
AudioPCMConfig PCM { get; }
|
||||
string Path { get; }
|
||||
AudioPCMConfig PCM { get; }
|
||||
string Path { get; }
|
||||
|
||||
TimeSpan Duration { get; }
|
||||
long Length { get; }
|
||||
long Position { get; set; }
|
||||
long Remaining { get; }
|
||||
TimeSpan Duration { get; }
|
||||
long Length { get; }
|
||||
long Position { get; set; }
|
||||
long Remaining { get; }
|
||||
|
||||
int Read(AudioBuffer buffer, int maxLength);
|
||||
void Close();
|
||||
}
|
||||
int Read(AudioBuffer buffer, int maxLength);
|
||||
void Close();
|
||||
}
|
||||
|
||||
public interface IAudioTitle
|
||||
public interface IAudioTitle
|
||||
{
|
||||
List<TimeSpan> Chapters { get; }
|
||||
AudioPCMConfig PCM { get; }
|
||||
string Codec { get; }
|
||||
string Language { get; }
|
||||
int StreamId { get; }
|
||||
|
||||
//IAudioSource Open { get; }
|
||||
}
|
||||
|
||||
public interface IAudioTitleSet
|
||||
{
|
||||
List<IAudioTitle> AudioTitles { get; }
|
||||
}
|
||||
|
||||
public static class IAudioTitleExtensions
|
||||
{
|
||||
public static TimeSpan GetDuration(this IAudioTitle title)
|
||||
{
|
||||
List<TimeSpan> Chapters { get; }
|
||||
AudioPCMConfig PCM { get; }
|
||||
string Codec { get; }
|
||||
string Language { get; }
|
||||
int StreamId { get; }
|
||||
//IAudioSource Open { get; }
|
||||
List<TimeSpan> chapters = title.Chapters;
|
||||
|
||||
return chapters[chapters.Count - 1];
|
||||
}
|
||||
|
||||
public interface IAudioTitleSet
|
||||
|
||||
public static string GetRateString(this IAudioTitle title)
|
||||
{
|
||||
List<IAudioTitle> AudioTitles { get; }
|
||||
int sr = title.PCM.SampleRate;
|
||||
|
||||
if(sr % 1000 == 0) return $"{sr / 1000}KHz";
|
||||
if(sr % 100 == 0) return $"{sr / 100}.{sr / 100 % 10}KHz";
|
||||
|
||||
return $"{sr}Hz";
|
||||
}
|
||||
|
||||
public static class IAudioTitleExtensions
|
||||
public static string GetFormatString(this IAudioTitle title)
|
||||
{
|
||||
public static TimeSpan GetDuration(this IAudioTitle title)
|
||||
switch(title.PCM.ChannelCount)
|
||||
{
|
||||
var chapters = title.Chapters;
|
||||
return chapters[chapters.Count - 1];
|
||||
case 1:
|
||||
return "mono";
|
||||
case 2:
|
||||
return "stereo";
|
||||
default:
|
||||
return "multi-channel";
|
||||
}
|
||||
|
||||
|
||||
public static string GetRateString(this IAudioTitle title)
|
||||
{
|
||||
var sr = title.PCM.SampleRate;
|
||||
if (sr % 1000 == 0) return $"{sr / 1000}KHz";
|
||||
if (sr % 100 == 0) return $"{sr / 100}.{(sr / 100) % 10}KHz";
|
||||
return $"{sr}Hz";
|
||||
}
|
||||
|
||||
public static string GetFormatString(this IAudioTitle title)
|
||||
{
|
||||
switch (title.PCM.ChannelCount)
|
||||
{
|
||||
case 1: return "mono";
|
||||
case 2: return "stereo";
|
||||
default: return "multi-channel";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SingleAudioTitle : IAudioTitle
|
||||
{
|
||||
public SingleAudioTitle(IAudioSource source) { this.source = source; }
|
||||
public List<TimeSpan> Chapters => new List<TimeSpan> { TimeSpan.Zero, source.Duration };
|
||||
public AudioPCMConfig PCM => source.PCM;
|
||||
public string Codec => source.Settings.Extension;
|
||||
public string Language => "";
|
||||
public int StreamId => 0;
|
||||
IAudioSource source;
|
||||
}
|
||||
|
||||
public class SingleAudioTitleSet : IAudioTitleSet
|
||||
{
|
||||
public SingleAudioTitleSet(IAudioSource source) { this.source = source; }
|
||||
public List<IAudioTitle> AudioTitles => new List<IAudioTitle> { new SingleAudioTitle(source) };
|
||||
IAudioSource source;
|
||||
}
|
||||
}
|
||||
|
||||
public class SingleAudioTitle : IAudioTitle
|
||||
{
|
||||
readonly IAudioSource source;
|
||||
public SingleAudioTitle(IAudioSource source) => this.source = source;
|
||||
|
||||
#region IAudioTitle Members
|
||||
|
||||
public List<TimeSpan> Chapters => [TimeSpan.Zero, source.Duration];
|
||||
public AudioPCMConfig PCM => source.PCM;
|
||||
public string Codec => source.Settings.Extension;
|
||||
public string Language => "";
|
||||
public int StreamId => 0;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class SingleAudioTitleSet : IAudioTitleSet
|
||||
{
|
||||
readonly IAudioSource source;
|
||||
public SingleAudioTitleSet(IAudioSource source) => this.source = source;
|
||||
|
||||
#region IAudioTitleSet Members
|
||||
|
||||
public List<IAudioTitle> AudioTitles => [new SingleAudioTitle(source)];
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,56 +1,56 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace CUETools.Codecs
|
||||
namespace CUETools.Codecs;
|
||||
|
||||
/// <summary>
|
||||
/// Localized description attribute
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public class SRDescriptionAttribute : DescriptionAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Localized description attribute
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
|
||||
public class SRDescriptionAttribute : DescriptionAttribute
|
||||
/// <summary>
|
||||
/// Resource manager to use;
|
||||
/// </summary>
|
||||
readonly Type SR;
|
||||
/// <summary>
|
||||
/// Store a flag indicating whether this has been localized
|
||||
/// </summary>
|
||||
bool localized;
|
||||
|
||||
/// <summary>
|
||||
/// Construct the description attribute
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public SRDescriptionAttribute(Type SR, string text) : base(text)
|
||||
{
|
||||
/// <summary>
|
||||
/// Store a flag indicating whether this has been localized
|
||||
/// </summary>
|
||||
private bool localized;
|
||||
localized = false;
|
||||
this.SR = SR;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resource manager to use;
|
||||
/// </summary>
|
||||
private Type SR;
|
||||
/// <summary>
|
||||
/// Override the return of the description text to localize the text
|
||||
/// </summary>
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
if(!localized)
|
||||
{
|
||||
localized = true;
|
||||
|
||||
/// <summary>
|
||||
/// Construct the description attribute
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public SRDescriptionAttribute(Type SR, string text)
|
||||
: base(text)
|
||||
{
|
||||
this.localized = false;
|
||||
this.SR = SR;
|
||||
}
|
||||
DescriptionValue = SR.InvokeMember(DescriptionValue,
|
||||
BindingFlags.GetProperty |
|
||||
BindingFlags.Static |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic,
|
||||
null,
|
||||
null,
|
||||
[]) as string;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override the return of the description text to localize the text
|
||||
/// </summary>
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!localized)
|
||||
{
|
||||
localized = true;
|
||||
this.DescriptionValue = SR.InvokeMember(
|
||||
this.DescriptionValue,
|
||||
System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Static |
|
||||
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic,
|
||||
null,
|
||||
null,
|
||||
new object[] { }) as string;
|
||||
}
|
||||
|
||||
return base.Description;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return base.Description;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,179 +2,181 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace CUETools.Codecs.WAV
|
||||
namespace CUETools.Codecs.WAV;
|
||||
|
||||
public class AudioEncoder : IAudioDest
|
||||
{
|
||||
public class AudioEncoder : IAudioDest
|
||||
readonly EncoderSettings m_settings;
|
||||
BinaryWriter _bw;
|
||||
List<uint> _chunkFCCs;
|
||||
List<byte[]> _chunks;
|
||||
long _finalSampleCount = -1;
|
||||
bool _headersWritten;
|
||||
Stream _IO;
|
||||
long hdrLen;
|
||||
|
||||
public AudioEncoder(EncoderSettings settings, string path, Stream IO = null)
|
||||
{
|
||||
private Stream _IO;
|
||||
private BinaryWriter _bw;
|
||||
private long _sampleLen;
|
||||
private string _path;
|
||||
private long hdrLen = 0;
|
||||
private bool _headersWritten = false;
|
||||
private long _finalSampleCount = -1;
|
||||
private List<byte[]> _chunks = null;
|
||||
private List<uint> _chunkFCCs = null;
|
||||
|
||||
public long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sampleLen;
|
||||
}
|
||||
}
|
||||
|
||||
public long FinalSampleCount
|
||||
{
|
||||
set { _finalSampleCount = value; }
|
||||
}
|
||||
|
||||
private EncoderSettings m_settings;
|
||||
public IAudioEncoderSettings Settings => m_settings;
|
||||
|
||||
public string Path { get { return _path; } }
|
||||
|
||||
public AudioEncoder(EncoderSettings settings, string path, Stream IO = null)
|
||||
{
|
||||
m_settings = settings;
|
||||
_path = path;
|
||||
_IO = IO ?? new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
_bw = new BinaryWriter(_IO);
|
||||
}
|
||||
|
||||
public void WriteChunk(uint fcc, byte[] data)
|
||||
{
|
||||
if (_sampleLen > 0)
|
||||
throw new Exception("data already written, no chunks allowed");
|
||||
if (_chunks == null)
|
||||
{
|
||||
_chunks = new List<byte[]>();
|
||||
_chunkFCCs = new List<uint>();
|
||||
}
|
||||
_chunkFCCs.Add(fcc);
|
||||
_chunks.Add(data);
|
||||
hdrLen += 8 + data.Length + (data.Length & 1);
|
||||
}
|
||||
|
||||
private void WriteHeaders()
|
||||
{
|
||||
const uint fccRIFF = 0x46464952;
|
||||
const uint fccWAVE = 0x45564157;
|
||||
const uint fccFormat = 0x20746D66;
|
||||
const uint fccData = 0x61746164;
|
||||
|
||||
bool wavex = (Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24) || Settings.PCM.ChannelMask != AudioPCMConfig.GetDefaultChannelMask(Settings.PCM.ChannelCount);
|
||||
|
||||
hdrLen += 36 + (wavex ? 24 : 0) + 8;
|
||||
|
||||
uint dataLen = (uint)(_finalSampleCount * Settings.PCM.BlockAlign);
|
||||
uint dataLenPadded = dataLen + (dataLen & 1);
|
||||
|
||||
_bw.Write(fccRIFF);
|
||||
if (_finalSampleCount <= 0)
|
||||
_bw.Write((uint)0xffffffff);
|
||||
else
|
||||
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
|
||||
_bw.Write(fccWAVE);
|
||||
_bw.Write(fccFormat);
|
||||
if (wavex)
|
||||
{
|
||||
_bw.Write((uint)40);
|
||||
_bw.Write((ushort)0xfffe); // WAVEX follows
|
||||
}
|
||||
else
|
||||
{
|
||||
_bw.Write((uint)16);
|
||||
_bw.Write((ushort)1); // PCM
|
||||
}
|
||||
_bw.Write((ushort)Settings.PCM.ChannelCount);
|
||||
_bw.Write((uint)Settings.PCM.SampleRate);
|
||||
_bw.Write((uint)(Settings.PCM.SampleRate * Settings.PCM.BlockAlign));
|
||||
_bw.Write((ushort)Settings.PCM.BlockAlign);
|
||||
_bw.Write((ushort)((Settings.PCM.BitsPerSample + 7) / 8 * 8));
|
||||
if (wavex)
|
||||
{
|
||||
_bw.Write((ushort)22); // length of WAVEX structure
|
||||
_bw.Write((ushort)Settings.PCM.BitsPerSample);
|
||||
_bw.Write((uint)Settings.PCM.ChannelMask);
|
||||
_bw.Write((ushort)1); // PCM Guid
|
||||
_bw.Write((ushort)0);
|
||||
_bw.Write((ushort)0);
|
||||
_bw.Write((ushort)0x10);
|
||||
_bw.Write((byte)0x80);
|
||||
_bw.Write((byte)0x00);
|
||||
_bw.Write((byte)0x00);
|
||||
_bw.Write((byte)0xaa);
|
||||
_bw.Write((byte)0x00);
|
||||
_bw.Write((byte)0x38);
|
||||
_bw.Write((byte)0x9b);
|
||||
_bw.Write((byte)0x71);
|
||||
}
|
||||
if (_chunks != null)
|
||||
for (int i = 0; i < _chunks.Count; i++)
|
||||
{
|
||||
_bw.Write(_chunkFCCs[i]);
|
||||
_bw.Write((uint)_chunks[i].Length);
|
||||
_bw.Write(_chunks[i]);
|
||||
if ((_chunks[i].Length & 1) != 0)
|
||||
_bw.Write((byte)0);
|
||||
}
|
||||
|
||||
_bw.Write(fccData);
|
||||
if (_finalSampleCount <= 0)
|
||||
_bw.Write((uint)0xffffffff);
|
||||
else
|
||||
_bw.Write(dataLen);
|
||||
|
||||
_headersWritten = true;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_finalSampleCount <= 0 && _IO.CanSeek)
|
||||
{
|
||||
long dataLen = _sampleLen * Settings.PCM.BlockAlign;
|
||||
long dataLenPadded = dataLen + (dataLen & 1);
|
||||
if (dataLenPadded + hdrLen - 8 < 0xffffffff)
|
||||
{
|
||||
if ((dataLen & 1) == 1)
|
||||
_bw.Write((byte)0);
|
||||
|
||||
_bw.Seek(4, SeekOrigin.Begin);
|
||||
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
|
||||
|
||||
_bw.Seek((int)hdrLen - 4, SeekOrigin.Begin);
|
||||
_bw.Write((uint)dataLen);
|
||||
}
|
||||
}
|
||||
|
||||
_bw.Close();
|
||||
|
||||
_bw = null;
|
||||
_IO = null;
|
||||
|
||||
if (_finalSampleCount > 0 && _sampleLen != _finalSampleCount)
|
||||
throw new Exception("Samples written differs from the expected sample count.");
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
_bw.Close();
|
||||
_bw = null;
|
||||
_IO = null;
|
||||
if (_path != "")
|
||||
File.Delete(_path);
|
||||
}
|
||||
|
||||
public void Write(AudioBuffer buff)
|
||||
{
|
||||
if (buff.Length == 0)
|
||||
return;
|
||||
buff.Prepare(this);
|
||||
if (!_headersWritten)
|
||||
WriteHeaders();
|
||||
_IO.Write(buff.Bytes, 0, buff.ByteLength);
|
||||
_sampleLen += buff.Length;
|
||||
}
|
||||
m_settings = settings;
|
||||
Path = path;
|
||||
_IO = IO ?? new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
_bw = new BinaryWriter(_IO);
|
||||
}
|
||||
}
|
||||
|
||||
public long Position { get; private set; }
|
||||
|
||||
#region IAudioDest Members
|
||||
|
||||
public long FinalSampleCount
|
||||
{
|
||||
set => _finalSampleCount = value;
|
||||
}
|
||||
|
||||
public IAudioEncoderSettings Settings => m_settings;
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if(_finalSampleCount <= 0 && _IO.CanSeek)
|
||||
{
|
||||
long dataLen = Position * Settings.PCM.BlockAlign;
|
||||
long dataLenPadded = dataLen + (dataLen & 1);
|
||||
|
||||
if(dataLenPadded + hdrLen - 8 < 0xffffffff)
|
||||
{
|
||||
if((dataLen & 1) == 1) _bw.Write((byte)0);
|
||||
|
||||
_bw.Seek(4, SeekOrigin.Begin);
|
||||
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
|
||||
|
||||
_bw.Seek((int)hdrLen - 4, SeekOrigin.Begin);
|
||||
_bw.Write((uint)dataLen);
|
||||
}
|
||||
}
|
||||
|
||||
_bw.Close();
|
||||
|
||||
_bw = null;
|
||||
_IO = null;
|
||||
|
||||
if(_finalSampleCount > 0 && Position != _finalSampleCount)
|
||||
throw new Exception("Samples written differs from the expected sample count.");
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
_bw.Close();
|
||||
_bw = null;
|
||||
_IO = null;
|
||||
if(Path != "") File.Delete(Path);
|
||||
}
|
||||
|
||||
public void Write(AudioBuffer buff)
|
||||
{
|
||||
if(buff.Length == 0) return;
|
||||
buff.Prepare(this);
|
||||
if(!_headersWritten) WriteHeaders();
|
||||
_IO.Write(buff.Bytes, 0, buff.ByteLength);
|
||||
Position += buff.Length;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void WriteChunk(uint fcc, byte[] data)
|
||||
{
|
||||
if(Position > 0) throw new Exception("data already written, no chunks allowed");
|
||||
|
||||
if(_chunks == null)
|
||||
{
|
||||
_chunks = [];
|
||||
_chunkFCCs = [];
|
||||
}
|
||||
|
||||
_chunkFCCs.Add(fcc);
|
||||
_chunks.Add(data);
|
||||
hdrLen += 8 + data.Length + (data.Length & 1);
|
||||
}
|
||||
|
||||
void WriteHeaders()
|
||||
{
|
||||
const uint fccRIFF = 0x46464952;
|
||||
const uint fccWAVE = 0x45564157;
|
||||
const uint fccFormat = 0x20746D66;
|
||||
const uint fccData = 0x61746164;
|
||||
|
||||
bool wavex = Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24 ||
|
||||
Settings.PCM.ChannelMask != AudioPCMConfig.GetDefaultChannelMask(Settings.PCM.ChannelCount);
|
||||
|
||||
hdrLen += 36 + (wavex ? 24 : 0) + 8;
|
||||
|
||||
var dataLen = (uint)(_finalSampleCount * Settings.PCM.BlockAlign);
|
||||
uint dataLenPadded = dataLen + (dataLen & 1);
|
||||
|
||||
_bw.Write(fccRIFF);
|
||||
|
||||
if(_finalSampleCount <= 0)
|
||||
_bw.Write(0xffffffff);
|
||||
else
|
||||
_bw.Write((uint)(dataLenPadded + hdrLen - 8));
|
||||
|
||||
_bw.Write(fccWAVE);
|
||||
_bw.Write(fccFormat);
|
||||
|
||||
if(wavex)
|
||||
{
|
||||
_bw.Write((uint)40);
|
||||
_bw.Write((ushort)0xfffe); // WAVEX follows
|
||||
}
|
||||
else
|
||||
{
|
||||
_bw.Write((uint)16);
|
||||
_bw.Write((ushort)1); // PCM
|
||||
}
|
||||
|
||||
_bw.Write((ushort)Settings.PCM.ChannelCount);
|
||||
_bw.Write((uint)Settings.PCM.SampleRate);
|
||||
_bw.Write((uint)(Settings.PCM.SampleRate * Settings.PCM.BlockAlign));
|
||||
_bw.Write((ushort)Settings.PCM.BlockAlign);
|
||||
_bw.Write((ushort)((Settings.PCM.BitsPerSample + 7) / 8 * 8));
|
||||
|
||||
if(wavex)
|
||||
{
|
||||
_bw.Write((ushort)22); // length of WAVEX structure
|
||||
_bw.Write((ushort)Settings.PCM.BitsPerSample);
|
||||
_bw.Write((uint)Settings.PCM.ChannelMask);
|
||||
_bw.Write((ushort)1); // PCM Guid
|
||||
_bw.Write((ushort)0);
|
||||
_bw.Write((ushort)0);
|
||||
_bw.Write((ushort)0x10);
|
||||
_bw.Write((byte)0x80);
|
||||
_bw.Write((byte)0x00);
|
||||
_bw.Write((byte)0x00);
|
||||
_bw.Write((byte)0xaa);
|
||||
_bw.Write((byte)0x00);
|
||||
_bw.Write((byte)0x38);
|
||||
_bw.Write((byte)0x9b);
|
||||
_bw.Write((byte)0x71);
|
||||
}
|
||||
|
||||
if(_chunks != null)
|
||||
{
|
||||
for(var i = 0; i < _chunks.Count; i++)
|
||||
{
|
||||
_bw.Write(_chunkFCCs[i]);
|
||||
_bw.Write((uint)_chunks[i].Length);
|
||||
_bw.Write(_chunks[i]);
|
||||
if((_chunks[i].Length & 1) != 0) _bw.Write((byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
_bw.Write(fccData);
|
||||
|
||||
if(_finalSampleCount <= 0)
|
||||
_bw.Write(0xffffffff);
|
||||
else
|
||||
_bw.Write(dataLen);
|
||||
|
||||
_headersWritten = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user