mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
Managed FLAC encoder/decoder based on Flake, initial revision
This commit is contained in:
245
CUETools.Codecs.FLAKE/BitReader.cs
Normal file
245
CUETools.Codecs.FLAKE/BitReader.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.FLAKE
|
||||
{
|
||||
class BitReader
|
||||
{
|
||||
byte[] buffer;
|
||||
byte[] byte_to_unary_table;
|
||||
int pos, len;
|
||||
int _bitaccumulator;
|
||||
|
||||
public int Position
|
||||
{
|
||||
get { return pos; }
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public BitReader(byte[] _buffer, int _pos, int _len)
|
||||
{
|
||||
buffer = _buffer;
|
||||
pos = _pos;
|
||||
len = _len;
|
||||
_bitaccumulator = 0;
|
||||
|
||||
byte_to_unary_table = new byte[] {
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
/* supports reading 1 to 24 bits, in big endian format */
|
||||
public uint readbits_24(int bits)
|
||||
{
|
||||
uint result = (((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16) | (((uint)buffer[pos + 2]) << 8) | ((uint)buffer[pos + 3]);
|
||||
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 */
|
||||
public void skipbits(int bits)
|
||||
{
|
||||
int new_accumulator = (_bitaccumulator + bits);
|
||||
pos += (new_accumulator >> 3);
|
||||
_bitaccumulator = (new_accumulator & 7);
|
||||
}
|
||||
|
||||
/* supports reading 1 to 32 bits, in big endian format */
|
||||
public uint readbits(int bits)
|
||||
{
|
||||
if (bits <= 24)
|
||||
return readbits_24(bits);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint read_unary()
|
||||
{
|
||||
uint val = 0;
|
||||
|
||||
int result = (buffer[pos] << _bitaccumulator) & 0xff;
|
||||
if (result == 0)
|
||||
{
|
||||
val = 8 - (uint)_bitaccumulator;
|
||||
_bitaccumulator = 0;
|
||||
pos++;
|
||||
return val + read_unary();
|
||||
// check eof
|
||||
}
|
||||
|
||||
val = byte_to_unary_table[result];
|
||||
|
||||
int new_accumulator = (_bitaccumulator + (int)val + 1);
|
||||
pos += (new_accumulator / 8);
|
||||
_bitaccumulator = (new_accumulator % 8);
|
||||
return val;
|
||||
}
|
||||
|
||||
public void flush()
|
||||
{
|
||||
if (_bitaccumulator > 0)
|
||||
readbits(8 - _bitaccumulator);
|
||||
}
|
||||
|
||||
public int readbits_signed(int bits)
|
||||
{
|
||||
int 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 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 uval = (msbs << k) | lsbs;
|
||||
return (int)(uval >> 1 ^ -(int)(uval & 1));
|
||||
}
|
||||
|
||||
public int read_unary_signed()
|
||||
{
|
||||
uint uval = read_unary();
|
||||
return (int)(uval >> 1 ^ -(int)(uval & 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
154
CUETools.Codecs.FLAKE/BitWriter.cs
Normal file
154
CUETools.Codecs.FLAKE/BitWriter.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.FLAKE
|
||||
{
|
||||
class BitWriter
|
||||
{
|
||||
uint bit_buf;
|
||||
int bit_left;
|
||||
byte[] buffer;
|
||||
int buf_start, buf_ptr, buf_end;
|
||||
bool eof;
|
||||
|
||||
public BitWriter(byte[] buf, int pos, int len)
|
||||
{
|
||||
buffer = buf;
|
||||
buf_start = pos;
|
||||
buf_ptr = pos;
|
||||
buf_end = pos + len;
|
||||
bit_left = 32;
|
||||
bit_buf = 0;
|
||||
eof = false;
|
||||
}
|
||||
|
||||
public void writebits_signed(int bits, int val)
|
||||
{
|
||||
writebits(bits, val & ((1 << bits) - 1));
|
||||
}
|
||||
|
||||
public void writebits_signed(uint bits, int val)
|
||||
{
|
||||
writebits((int) bits, val & ((1 << (int) bits) - 1));
|
||||
}
|
||||
|
||||
public void writebits(int bits, int val)
|
||||
{
|
||||
writebits(bits, (uint)val);
|
||||
}
|
||||
|
||||
public void writebits(int bits, uint val)
|
||||
{
|
||||
//assert(bits == 32 || val < (1U << bits));
|
||||
|
||||
if (bits == 0 || eof) return;
|
||||
if ((buf_ptr + 3) >= buf_end)
|
||||
{
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
if (bits < bit_left)
|
||||
{
|
||||
bit_buf = (bit_buf << bits) | val;
|
||||
bit_left -= bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint bb = 0;
|
||||
if (bit_left == 32)
|
||||
{
|
||||
//assert(bits == 32);
|
||||
bb = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
bb = (bit_buf << bit_left) | (val >> (bits - bit_left));
|
||||
bit_left += (32 - bits);
|
||||
}
|
||||
if (buffer != null)
|
||||
{
|
||||
buffer[buf_ptr + 3] = (byte)(bb & 0xFF); bb >>= 8;
|
||||
buffer[buf_ptr + 2] = (byte)(bb & 0xFF); bb >>= 8;
|
||||
buffer[buf_ptr + 1] = (byte)(bb & 0xFF); bb >>= 8;
|
||||
buffer[buf_ptr + 0] = (byte)(bb & 0xFF);
|
||||
}
|
||||
buf_ptr += 4;
|
||||
bit_buf = val;
|
||||
}
|
||||
}
|
||||
|
||||
public void write_utf8(int val)
|
||||
{
|
||||
write_utf8((uint)val);
|
||||
}
|
||||
|
||||
public void write_utf8(uint val)
|
||||
{
|
||||
if (val < 0x80)
|
||||
{
|
||||
writebits(8, val);
|
||||
return;
|
||||
}
|
||||
int bytes = (Flake.log2i(val) + 4) / 5;
|
||||
int shift = (bytes - 1) * 6;
|
||||
writebits(8, (256U - (256U >> bytes)) | (val >> shift));
|
||||
while (shift >= 6)
|
||||
{
|
||||
shift -= 6;
|
||||
writebits(8, 0x80 | ((val >> shift) & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
public void write_rice_signed(int k, int val)
|
||||
{
|
||||
int v, q;
|
||||
|
||||
if (k < 0) return;
|
||||
|
||||
// convert signed to unsigned
|
||||
v = -2 * val - 1;
|
||||
v ^= (v >> 31);
|
||||
|
||||
// write quotient in unary
|
||||
q = (v >> k) + 1;
|
||||
while (q > 31)
|
||||
{
|
||||
writebits(31, 0);
|
||||
q -= 31;
|
||||
}
|
||||
writebits(q, 1);
|
||||
|
||||
// write write remainder in binary using 'k' bits
|
||||
writebits(k, v & ((1 << k) - 1));
|
||||
}
|
||||
|
||||
public void flush()
|
||||
{
|
||||
bit_buf <<= bit_left;
|
||||
while (bit_left < 32 && !eof)
|
||||
{
|
||||
if (buf_ptr >= buf_end)
|
||||
{
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
if (buffer != null)
|
||||
buffer[buf_ptr] = (byte)(bit_buf >> 24);
|
||||
buf_ptr++;
|
||||
bit_buf <<= 8;
|
||||
bit_left += 8;
|
||||
}
|
||||
bit_left = 32;
|
||||
bit_buf = 0;
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return buf_ptr - buf_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
CUETools.Codecs.FLAKE/CUETools.Codecs.FLAKE.csproj
Normal file
60
CUETools.Codecs.FLAKE/CUETools.Codecs.FLAKE.csproj
Normal file
@@ -0,0 +1,60 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.50727</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{082D6B9E-326E-4D15-9798-EDAE9EDE70A6}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CUETools.Codecs.FLAKE</RootNamespace>
|
||||
<AssemblyName>CUETools.Codecs.FLAKE</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BitReader.cs" />
|
||||
<Compile Include="BitWriter.cs" />
|
||||
<Compile Include="Flake.cs" />
|
||||
<Compile Include="FlakeReader.cs" />
|
||||
<Compile Include="FlakeWriter.cs" />
|
||||
<Compile Include="lpc.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CUETools.Codecs\CUETools.Codecs.csproj">
|
||||
<Project>{6458A13A-30EF-45A9-9D58-E5031B17BEE2}</Project>
|
||||
<Name>CUETools.Codecs</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
248
CUETools.Codecs.FLAKE/Flake.cs
Normal file
248
CUETools.Codecs.FLAKE/Flake.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.FLAKE
|
||||
{
|
||||
public class Flake
|
||||
{
|
||||
public const int MAX_BLOCKSIZE = 65535;
|
||||
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 int log2i(int v)
|
||||
{
|
||||
return log2i((uint)v);
|
||||
}
|
||||
public static int log2i(uint v)
|
||||
{
|
||||
int i;
|
||||
int n = 0;
|
||||
if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; }
|
||||
if (0 != (v & 0xff00)) { v >>= 8; n += 8; }
|
||||
for (i = 2; i < 256; i <<= 1)
|
||||
{
|
||||
if (v >= i) n++;
|
||||
else break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public static PredictionType LookupPredictionType(string name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "fixed": return PredictionType.Fixed;
|
||||
case "levinson": return PredictionType.Levinson;
|
||||
case "search" : return PredictionType.Search;
|
||||
}
|
||||
return (PredictionType)Int32.Parse(name);
|
||||
}
|
||||
|
||||
public static StereoMethod LookupStereoMethod(string name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "independent": return StereoMethod.Independent;
|
||||
case "estimate": return StereoMethod.Estimate;
|
||||
case "estimate2": return StereoMethod.Estimate2;
|
||||
case "estimate3": return StereoMethod.Estimate3;
|
||||
case "estimate4": return StereoMethod.Estimate4;
|
||||
case "estimate5": return StereoMethod.Estimate5;
|
||||
case "search": return StereoMethod.Search;
|
||||
}
|
||||
return (StereoMethod)Int32.Parse(name);
|
||||
}
|
||||
|
||||
public static OrderMethod LookupOrderMethod(string name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "estimate": return OrderMethod.Estimate;
|
||||
case "logfast": return OrderMethod.LogFast;
|
||||
case "logsearch": return OrderMethod.LogSearch;
|
||||
case "estsearch": return OrderMethod.EstSearch;
|
||||
case "search": return OrderMethod.Search;
|
||||
}
|
||||
return (OrderMethod)Int32.Parse(name);
|
||||
}
|
||||
|
||||
public static WindowFunction LookupWindowFunction(string name)
|
||||
{
|
||||
string[] parts = name.Split(',');
|
||||
WindowFunction res = (WindowFunction)0;
|
||||
foreach (string part in parts)
|
||||
{
|
||||
switch (part)
|
||||
{
|
||||
case "welch": res |= WindowFunction.Welch; break;
|
||||
case "tukey": res |= WindowFunction.Tukey; break;
|
||||
case "hann": res |= WindowFunction.Hann; break;
|
||||
case "flattop": res |= WindowFunction.Flattop; break;
|
||||
default: res |= (WindowFunction)Int32.Parse(name); break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
unsafe public static bool memcmp(int* res, int* smp, int n)
|
||||
{
|
||||
for (int i = n; i > 0; i--)
|
||||
if (*(res++) != *(smp++))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
unsafe public static void memcpy(int* res, int* 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 struct RiceContext
|
||||
{
|
||||
public int porder; /* partition order */
|
||||
public fixed uint rparams[Flake.MAX_PARTITIONS]; /* Rice parameters */
|
||||
public fixed int esc_bps[Flake.MAX_PARTITIONS]; /* bps if using escape code */
|
||||
};
|
||||
|
||||
unsafe struct FlacSubframe
|
||||
{
|
||||
public SubframeType type;
|
||||
public int order;
|
||||
public uint obits;
|
||||
public uint wbits;
|
||||
public int cbits;
|
||||
public int shift;
|
||||
public fixed int coefs[lpc.MAX_LPC_ORDER];
|
||||
public int* samples;
|
||||
public int* residual;
|
||||
public RiceContext rc;
|
||||
public uint size;
|
||||
public fixed uint done_lpcs[lpc.MAX_LPC_WINDOWS];
|
||||
public uint done_fixed;
|
||||
public int window;
|
||||
};
|
||||
|
||||
unsafe struct FlacFrame
|
||||
{
|
||||
public int blocksize;
|
||||
public int bs_code0, bs_code1;
|
||||
public ChannelMode ch_mode;
|
||||
public int ch_order0, ch_order1;
|
||||
public byte crc8;
|
||||
public FlacSubframe* subframes;
|
||||
public uint frame_count;
|
||||
public FlacSubframe current;
|
||||
}
|
||||
|
||||
public enum OrderMethod
|
||||
{
|
||||
Max = 0,
|
||||
Estimate = 1,
|
||||
LogFast = 2,
|
||||
LogSearch = 3,
|
||||
EstSearch = 4,
|
||||
Search = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of linear prediction
|
||||
/// </summary>
|
||||
public enum PredictionType
|
||||
{
|
||||
/// <summary>
|
||||
/// verbatim
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Fixed only
|
||||
/// </summary>
|
||||
Fixed = 1,
|
||||
/// <summary>
|
||||
/// Levinson-Durbin recursion
|
||||
/// </summary>
|
||||
Levinson = 2,
|
||||
/// <summary>
|
||||
/// Exhaustive search
|
||||
/// </summary>
|
||||
Search = 3,
|
||||
/// <summary>
|
||||
/// Internal; Use prediction type from previous estimation
|
||||
/// </summary>
|
||||
Estimated = 4
|
||||
}
|
||||
|
||||
public enum StereoMethod
|
||||
{
|
||||
Independent = 0,
|
||||
Estimate = 1,
|
||||
Estimate2 = 2,
|
||||
Estimate3 = 3,
|
||||
Estimate4 = 4,
|
||||
Estimate5 = 5,
|
||||
Search = 9
|
||||
}
|
||||
|
||||
public enum SubframeType
|
||||
{
|
||||
Constant = 0,
|
||||
Verbatim = 1,
|
||||
Fixed = 8,
|
||||
LPC = 32
|
||||
};
|
||||
|
||||
public enum ChannelMode
|
||||
{
|
||||
NotStereo = 0,
|
||||
LeftRight = 1,
|
||||
LeftSide = 8,
|
||||
RightSide = 9,
|
||||
MidSide = 10
|
||||
}
|
||||
|
||||
public enum WindowFunction
|
||||
{
|
||||
Welch = 1,
|
||||
Tukey = 2,
|
||||
Hann = 4,
|
||||
Flattop = 8
|
||||
}
|
||||
|
||||
public enum MetadataType
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block
|
||||
/// </summary>
|
||||
FLAC__METADATA_TYPE_STREAMINFO = 0,
|
||||
|
||||
/// <summary>
|
||||
/// <A HREF="../format.html#metadata_block_padding">PADDING</A> block
|
||||
/// </summary>
|
||||
FLAC__METADATA_TYPE_PADDING = 1,
|
||||
|
||||
FLAC__METADATA_TYPE_APPLICATION = 2,
|
||||
/**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
|
||||
|
||||
FLAC__METADATA_TYPE_SEEKTABLE = 3,
|
||||
/**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
|
||||
|
||||
FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
|
||||
/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
|
||||
|
||||
FLAC__METADATA_TYPE_CUESHEET = 5,
|
||||
/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
|
||||
|
||||
FLAC__METADATA_TYPE_PICTURE = 6,
|
||||
/**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
|
||||
|
||||
FLAC__METADATA_TYPE_UNDEFINED = 7
|
||||
/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
|
||||
};
|
||||
}
|
||||
644
CUETools.Codecs.FLAKE/FlakeReader.cs
Normal file
644
CUETools.Codecs.FLAKE/FlakeReader.cs
Normal file
@@ -0,0 +1,644 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
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;
|
||||
|
||||
Crc8 crc8;
|
||||
Crc16 crc16;
|
||||
int channels;
|
||||
uint bits_per_sample;
|
||||
int sample_rate = 44100;
|
||||
|
||||
uint min_block_size = 0;
|
||||
uint max_block_size = 0;
|
||||
uint min_frame_size = 0;
|
||||
uint max_frame_size = 0;
|
||||
|
||||
uint _samplesInBuffer, _samplesBufferOffset;
|
||||
ulong _sampleCount = 0;
|
||||
ulong _sampleOffset = 0;
|
||||
|
||||
string _path;
|
||||
Stream _IO;
|
||||
|
||||
public int[] Samples
|
||||
{
|
||||
get
|
||||
{
|
||||
return samplesBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
crc8 = new Crc8();
|
||||
crc16 = new Crc16();
|
||||
|
||||
_framesBuffer = new byte[0x10000];
|
||||
decode_metadata();
|
||||
|
||||
//max_frame_size = 16 + ((Flake.MAX_BLOCKSIZE * (int)(bits_per_sample * channels + 1) + 7) >> 3);
|
||||
if (max_frame_size * 2 > _framesBuffer.Length)
|
||||
{
|
||||
byte[] temp = _framesBuffer;
|
||||
_framesBuffer = new byte[max_frame_size * 2];
|
||||
if (_framesBufferLength > 0)
|
||||
Array.Copy(temp, _framesBufferOffset, _framesBuffer, 0, _framesBufferLength);
|
||||
_framesBufferOffset = 0;
|
||||
}
|
||||
_samplesInBuffer = 0;
|
||||
|
||||
if (bits_per_sample != 16 || channels != 2 || sample_rate != 44100)
|
||||
throw new Exception("invalid flac file");
|
||||
|
||||
samplesBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
||||
residualBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
channels = _channels;
|
||||
bits_per_sample = _bits_per_sample;
|
||||
samplesBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
||||
residualBuffer = new int[Flake.MAX_BLOCKSIZE * channels];
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_IO.Close();
|
||||
}
|
||||
|
||||
public int[,] Read(int[,] buff)
|
||||
{
|
||||
return AudioSamples.Read(this, buff);
|
||||
}
|
||||
|
||||
public ulong Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sampleCount;
|
||||
}
|
||||
}
|
||||
|
||||
public ulong Remaining
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sampleCount - _sampleOffset + _samplesInBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
public ulong Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sampleOffset - _samplesInBuffer;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new Exception("seeking not yet supported");
|
||||
}
|
||||
}
|
||||
|
||||
public int BitsPerSample
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)bits_per_sample;
|
||||
}
|
||||
}
|
||||
|
||||
public int ChannelCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return channels;
|
||||
}
|
||||
}
|
||||
|
||||
public int SampleRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return sample_rate;
|
||||
}
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
public uint Read(int[,] buff, uint sampleCount)
|
||||
{
|
||||
uint offset = 0;
|
||||
|
||||
while (_samplesInBuffer < sampleCount)
|
||||
{
|
||||
if (_samplesInBuffer > 0)
|
||||
{
|
||||
interlace(buff, (int)offset, (int)_samplesInBuffer);
|
||||
sampleCount -= (uint)_samplesInBuffer;
|
||||
offset += _samplesInBuffer;
|
||||
_samplesInBuffer = 0;
|
||||
_samplesBufferOffset = 0;
|
||||
}
|
||||
|
||||
fill_frames_buffer();
|
||||
|
||||
if (_framesBufferLength == 0)
|
||||
return offset;
|
||||
|
||||
int bytesDecoded = DecodeFrame(_framesBuffer, _framesBufferOffset, _framesBufferLength);
|
||||
_framesBufferLength -= bytesDecoded;
|
||||
_framesBufferOffset += bytesDecoded;
|
||||
|
||||
_samplesInBuffer -= _samplesBufferOffset; // can be set by Seek, otherwise zero
|
||||
_sampleOffset += _samplesInBuffer;
|
||||
}
|
||||
|
||||
interlace(buff, (int)offset, (int)sampleCount);
|
||||
_samplesInBuffer -= sampleCount;
|
||||
_samplesBufferOffset += sampleCount;
|
||||
if (_samplesInBuffer == 0)
|
||||
_samplesBufferOffset = 0;
|
||||
return (uint)offset + sampleCount;
|
||||
}
|
||||
|
||||
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);
|
||||
_framesBufferOffset = 0;
|
||||
}
|
||||
while (_framesBufferLength < _framesBuffer.Length / 2)
|
||||
{
|
||||
int read = _IO.Read(_framesBuffer, _framesBufferOffset + _framesBufferLength, _framesBuffer.Length - _framesBufferOffset - _framesBufferLength);
|
||||
_framesBufferLength += read;
|
||||
if (read == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe void decode_frame_header(BitReader bitreader, FlacFrame* frame)
|
||||
{
|
||||
int header_start = bitreader.Position;
|
||||
|
||||
if (bitreader.readbits(16) != 0xFFF8)
|
||||
throw new Exception("invalid frame");
|
||||
|
||||
frame->bs_code0 = (int) bitreader.readbits(4);
|
||||
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)
|
||||
throw new Exception("unsupported bps coding");
|
||||
uint t1 = bitreader.readbit(); // == 0?????
|
||||
if (t1 != 0)
|
||||
throw new Exception("unsupported frame coding");
|
||||
frame->frame_count = bitreader.read_utf8();
|
||||
|
||||
// custom block size
|
||||
if (frame->bs_code0 == 6)
|
||||
{
|
||||
frame->bs_code1 = (int)bitreader.readbits(8);
|
||||
frame->blocksize = frame->bs_code1 + 1;
|
||||
}
|
||||
else if (frame->bs_code0 == 7)
|
||||
{
|
||||
frame->bs_code1 = (int)bitreader.readbits(16);
|
||||
frame->blocksize = frame->bs_code1 + 1;
|
||||
}
|
||||
else
|
||||
frame->blocksize = flac_blocksizes[frame->bs_code0];
|
||||
|
||||
// custom sample rate
|
||||
if (sr_code0 < 4 || sr_code0 > 11)
|
||||
{
|
||||
// sr_code0 == 12 -> sr == bitreader.readbits(8) * 1000;
|
||||
// sr_code0 == 13 -> sr == bitreader.readbits(16);
|
||||
// sr_code0 == 14 -> sr == bitreader.readbits(16) * 10;
|
||||
throw new Exception("invalid sample rate mode");
|
||||
}
|
||||
|
||||
int frame_channels = (int)frame->ch_mode + 1;
|
||||
if (frame_channels > 11)
|
||||
throw new Exception("invalid channel mode");
|
||||
if (frame_channels == 2 || frame_channels > 8) // Mid/Left/Right Side Stereo
|
||||
frame_channels = 2;
|
||||
else
|
||||
frame->ch_mode = ChannelMode.NotStereo;
|
||||
if (frame_channels != channels)
|
||||
throw new Exception("invalid channel mode");
|
||||
|
||||
// CRC-8 of frame header
|
||||
byte crc = crc8.ComputeChecksum(bitreader.Buffer, header_start, bitreader.Position - header_start);
|
||||
frame->crc8 = (byte)bitreader.readbits(8);
|
||||
if (frame->crc8 != crc)
|
||||
throw new Exception("header crc mismatch");
|
||||
}
|
||||
|
||||
unsafe void decode_subframe_constant(BitReader bitreader, FlacFrame* frame, int ch)
|
||||
{
|
||||
int obits = (int)frame->subframes[ch].obits;
|
||||
frame->subframes[ch].residual[0] = bitreader.readbits_signed(obits);
|
||||
}
|
||||
|
||||
unsafe void decode_subframe_verbatim(BitReader bitreader, FlacFrame* frame, int ch)
|
||||
{
|
||||
int obits = (int)frame->subframes[ch].obits;
|
||||
for (int i = 0; i < frame->blocksize; i++)
|
||||
frame->subframes[ch].residual[i] = bitreader.readbits_signed(obits);
|
||||
}
|
||||
|
||||
unsafe void decode_residual(BitReader bitreader, FlacFrame* frame, int ch)
|
||||
{
|
||||
// rice-encoded block
|
||||
uint coding_method = bitreader.readbits(2); // ????? == 0
|
||||
if (coding_method != 0) // 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);
|
||||
if (frame->subframes[ch].rc.porder > 8)
|
||||
throw new Exception("invalid partition order");
|
||||
int psize = frame->blocksize >> frame->subframes[ch].rc.porder;
|
||||
int res_cnt = psize - frame->subframes[ch].order;
|
||||
|
||||
// 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)
|
||||
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);
|
||||
else
|
||||
for (int i = n; i > 0; i--)
|
||||
*(r++) = bitreader.read_rice_signed((int)k);
|
||||
j += n;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe void decode_subframe_fixed(BitReader bitreader, FlacFrame* frame, int ch)
|
||||
{
|
||||
// warm-up samples
|
||||
int obits = (int)frame->subframes[ch].obits;
|
||||
for (int i = 0; i < frame->subframes[ch].order; i++)
|
||||
frame->subframes[ch].residual[i] = bitreader.readbits_signed(obits);
|
||||
|
||||
// residual
|
||||
decode_residual(bitreader, frame, ch);
|
||||
}
|
||||
|
||||
unsafe void decode_subframe_lpc(BitReader bitreader, FlacFrame* frame, int ch)
|
||||
{
|
||||
// warm-up samples
|
||||
int obits = (int)frame->subframes[ch].obits;
|
||||
for (int i = 0; i < frame->subframes[ch].order; i++)
|
||||
frame->subframes[ch].residual[i] = bitreader.readbits_signed(obits);
|
||||
|
||||
// LPC coefficients
|
||||
frame->subframes[ch].cbits = (int)bitreader.readbits(4) + 1; // lpc_precision
|
||||
frame->subframes[ch].shift = bitreader.readbits_signed(5);
|
||||
for (int i = 0; i < frame->subframes[ch].order; i++)
|
||||
frame->subframes[ch].coefs[i] = bitreader.readbits_signed(frame->subframes[ch].cbits);
|
||||
|
||||
// residual
|
||||
decode_residual(bitreader, frame, ch);
|
||||
}
|
||||
|
||||
unsafe void decode_subframes(BitReader bitreader, FlacFrame* frame)
|
||||
{
|
||||
fixed (int *r = residualBuffer, s = samplesBuffer)
|
||||
for (int ch = 0; ch < channels; ch++)
|
||||
{
|
||||
// subframe header
|
||||
uint t1 = bitreader.readbit(); // ?????? == 0
|
||||
if (t1 != 0)
|
||||
throw new Exception("unsupported subframe coding");
|
||||
int type_code = (int)bitreader.readbits(6);
|
||||
frame->subframes[ch].wbits = bitreader.readbit();
|
||||
if (frame->subframes[ch].wbits != 0)
|
||||
frame->subframes[ch].wbits += bitreader.read_unary();
|
||||
|
||||
frame->subframes[ch].obits = bits_per_sample - frame->subframes[ch].wbits;
|
||||
switch (frame->ch_mode)
|
||||
{
|
||||
case ChannelMode.MidSide: frame->subframes[ch].obits += (uint)ch; break;
|
||||
case ChannelMode.LeftSide: frame->subframes[ch].obits += (uint)ch; break;
|
||||
case ChannelMode.RightSide: frame->subframes[ch].obits += 1 - (uint)ch; break;
|
||||
}
|
||||
|
||||
frame->subframes[ch].type = (SubframeType)type_code;
|
||||
frame->subframes[ch].order = 0;
|
||||
|
||||
if ((type_code & (uint)SubframeType.LPC) != 0)
|
||||
{
|
||||
frame->subframes[ch].order = (type_code - (int)SubframeType.LPC) + 1;
|
||||
frame->subframes[ch].type = SubframeType.LPC;
|
||||
}
|
||||
else if ((type_code & (uint)SubframeType.Fixed) != 0)
|
||||
{
|
||||
frame->subframes[ch].order = (type_code - (int)SubframeType.Fixed);
|
||||
frame->subframes[ch].type = SubframeType.Fixed;
|
||||
}
|
||||
|
||||
frame->subframes[ch].residual = r + ch * Flake.MAX_BLOCKSIZE;
|
||||
frame->subframes[ch].samples = s + ch * Flake.MAX_BLOCKSIZE;
|
||||
|
||||
// subframe
|
||||
switch (frame->subframes[ch].type)
|
||||
{
|
||||
case SubframeType.Constant:
|
||||
decode_subframe_constant(bitreader, frame, ch);
|
||||
break;
|
||||
case SubframeType.Verbatim:
|
||||
decode_subframe_verbatim(bitreader, frame, ch);
|
||||
break;
|
||||
case SubframeType.Fixed:
|
||||
decode_subframe_fixed(bitreader, frame, ch);
|
||||
break;
|
||||
case SubframeType.LPC:
|
||||
decode_subframe_lpc(bitreader, frame, ch);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("invalid subframe type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe void restore_samples_fixed(FlacFrame* frame, int ch)
|
||||
{
|
||||
FlacSubframe* sub = frame->subframes + ch;
|
||||
|
||||
Flake.memcpy(sub->samples, sub->residual, sub->order);
|
||||
int* data = sub->samples + sub->order;
|
||||
int* residual = sub->residual + sub->order;
|
||||
int data_len = frame->blocksize - sub->order;
|
||||
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];
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < data_len; i++)
|
||||
data[i] = residual[i] + (data[i - 1] << 1) - data[i - 2];
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < data_len; i++)
|
||||
data[i] = residual[i] + (((data[i - 1] - data[i - 2]) << 1) + (data[i - 1] - data[i - 2])) + data[i - 3];
|
||||
break;
|
||||
case 4:
|
||||
for (int i = 0; i < data_len; i++)
|
||||
data[i] = residual[i] + ((data[i - 1] + data[i - 3]) << 2) - ((data[i - 2] << 2) + (data[i - 2] << 1)) - data[i - 4];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe void restore_samples(FlacFrame* frame)
|
||||
{
|
||||
for (int ch = 0; ch < channels; ch++)
|
||||
{
|
||||
switch (frame->subframes[ch].type)
|
||||
{
|
||||
case SubframeType.Constant:
|
||||
Flake.memset(frame->subframes[ch].samples, frame->subframes[ch].residual[0], frame->blocksize);
|
||||
break;
|
||||
case SubframeType.Verbatim:
|
||||
Flake.memcpy(frame->subframes[ch].samples, frame->subframes[ch].residual, frame->blocksize);
|
||||
break;
|
||||
case SubframeType.Fixed:
|
||||
restore_samples_fixed(frame, ch);
|
||||
break;
|
||||
case SubframeType.LPC:
|
||||
restore_samples_lpc(frame, ch);
|
||||
break;
|
||||
}
|
||||
if (frame->subframes[ch].wbits != 0)
|
||||
{
|
||||
int x = (int) frame->subframes[ch].wbits;
|
||||
for (int i = 0; i < frame->blocksize; i++)
|
||||
frame->subframes[ch].samples[i] <<= x;
|
||||
}
|
||||
}
|
||||
switch (frame->ch_mode)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool skip_bytes(int bytes)
|
||||
{
|
||||
for (int j = 0; j < bytes; j++)
|
||||
if (0 == _IO.Read(_framesBuffer, 0, 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void decode_metadata()
|
||||
{
|
||||
byte x;
|
||||
int i, id;
|
||||
bool first = true;
|
||||
byte[] FLAC__STREAM_SYNC_STRING = new byte[] { (byte)'f', (byte)'L', (byte)'a', (byte)'C' };
|
||||
byte[] ID3V2_TAG_ = new byte[] { (byte)'I', (byte)'D', (byte)'3' };
|
||||
|
||||
for (i = id = 0; i < 4; )
|
||||
{
|
||||
if (_IO.Read(_framesBuffer, 0, 1) == 0)
|
||||
throw new Exception("FLAC stream not found");
|
||||
x = _framesBuffer[0];
|
||||
if (x == FLAC__STREAM_SYNC_STRING[i])
|
||||
{
|
||||
first = true;
|
||||
i++;
|
||||
id = 0;
|
||||
continue;
|
||||
}
|
||||
if (id < 3 && x == ID3V2_TAG_[id])
|
||||
{
|
||||
id++;
|
||||
i = 0;
|
||||
if (id == 3)
|
||||
{
|
||||
if (!skip_bytes(3))
|
||||
throw new Exception("FLAC stream not found");
|
||||
int skip = 0;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (0 == _IO.Read(_framesBuffer, 0, 1))
|
||||
throw new Exception("FLAC stream not found");
|
||||
skip <<= 7;
|
||||
skip |= ((int)_framesBuffer[0] & 0x7f);
|
||||
}
|
||||
if (!skip_bytes(skip))
|
||||
throw new Exception("FLAC stream not found");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
id = 0;
|
||||
if (x == 0xff) /* MAGIC NUMBER for the first 8 frame sync bits */
|
||||
{
|
||||
do
|
||||
{
|
||||
if (_IO.Read(_framesBuffer, 0, 1) == 0)
|
||||
throw new Exception("FLAC stream not found");
|
||||
x = _framesBuffer[0];
|
||||
} while (x == 0xff);
|
||||
if (x >> 2 == 0x3e) /* MAGIC NUMBER for the last 6 sync bits */
|
||||
{
|
||||
//_IO.Position -= 2;
|
||||
// state = frame
|
||||
throw new Exception("headerless file unsupported");
|
||||
}
|
||||
}
|
||||
throw new Exception("FLAC stream not found");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
if (_framesBufferLength < 4 + len)
|
||||
{
|
||||
_IO.Position = pos + 4 + len;
|
||||
_framesBufferLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_framesBufferLength -= 4 + len;
|
||||
_framesBufferOffset += 4 + len;
|
||||
}
|
||||
if (is_last)
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
1656
CUETools.Codecs.FLAKE/FlakeWriter.cs
Normal file
1656
CUETools.Codecs.FLAKE/FlakeWriter.cs
Normal file
File diff suppressed because it is too large
Load Diff
35
CUETools.Codecs.FLAKE/Properties/AssemblyInfo.cs
Normal file
35
CUETools.Codecs.FLAKE/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("CUETools.Codecs.FLAKE")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("CUETools.Codecs.FLAKE")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("af385bb5-1d2e-409b-97db-b96d9ed491a0")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
650
CUETools.Codecs.FLAKE/lpc.cs
Normal file
650
CUETools.Codecs.FLAKE/lpc.cs
Normal file
@@ -0,0 +1,650 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.FLAKE
|
||||
{
|
||||
class lpc
|
||||
{
|
||||
public const int MAX_LPC_ORDER = 32;
|
||||
public const int MAX_LPC_WINDOWS = 4;
|
||||
|
||||
/**
|
||||
* Apply Welch window function to audio block
|
||||
*/
|
||||
static unsafe void
|
||||
apply_welch_window(/*const*/int* data, uint len, double* w_data)
|
||||
{
|
||||
double c = (2.0 / (len - 1.0)) - 1.0;
|
||||
for (uint i = 0; i < (len >> 1); i++)
|
||||
{
|
||||
double w = 1.0 - ((c - i) * (c - i));
|
||||
w_data[i] = data[i] * w;
|
||||
w_data[len - 1 - i] = data[len - 1 - i] * w;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates autocorrelation data from audio samples
|
||||
* A Welch window function is applied before calculation.
|
||||
*/
|
||||
static unsafe void
|
||||
compute_autocorr(/*const*/ int* data, uint len, uint lag, double* autoc, double* window)
|
||||
{
|
||||
double* data1 = stackalloc double[(int)len + 16];
|
||||
uint i, j;
|
||||
double temp, temp2;
|
||||
|
||||
if (window == null)
|
||||
apply_welch_window(data, len, data1);
|
||||
else
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
data1[i] = data[i] * window[i];
|
||||
}
|
||||
data1[len] = 0;
|
||||
|
||||
for (i = 0; i <= lag; ++i)
|
||||
{
|
||||
temp = 1.0;
|
||||
temp2 = 1.0;
|
||||
for (j = 0; j <= lag - i; ++j)
|
||||
temp += data1[j + i] * data1[j];
|
||||
|
||||
double* finish = data1 + len - i;
|
||||
for (double* pdata = data1 + lag + 1 - i; pdata < finish; pdata += 2)
|
||||
{
|
||||
temp += pdata[i] * pdata[0];
|
||||
temp2 += pdata[i + 1] * pdata[1];
|
||||
}
|
||||
autoc[i] = temp + temp2;
|
||||
}
|
||||
|
||||
//int sample, coeff;
|
||||
//for (coeff = 0; coeff <= lag; coeff++)
|
||||
// autoc[coeff] = 0.0;
|
||||
//int data_len = (int)len;
|
||||
//int limit = data_len - (int)lag - 1;
|
||||
//for (sample = 0; sample <= limit; sample++)
|
||||
//{
|
||||
// double d = data1[sample];
|
||||
// for (coeff = 0; coeff <= lag; coeff++)
|
||||
// autoc[coeff] += d * data1[sample + coeff];
|
||||
//}
|
||||
//for (; sample < data_len; sample++)
|
||||
//{
|
||||
// double d = data1[sample];
|
||||
// for (coeff = 0; coeff < data_len - sample; coeff++)
|
||||
// autoc[coeff] += d * data1[sample + coeff];
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
* Levinson-Durbin recursion.
|
||||
* Produces LPC coefficients from autocorrelation data.
|
||||
*/
|
||||
static unsafe void
|
||||
compute_lpc_coefs(/*const*/ double* autoc, uint max_order, double* reff,
|
||||
double* lpc/*[][MAX_LPC_ORDER]*/)
|
||||
{
|
||||
double* lpc_tmp = stackalloc double[MAX_LPC_ORDER];
|
||||
|
||||
int i, j, i2;
|
||||
double r, err, tmp;
|
||||
|
||||
if (max_order > MAX_LPC_ORDER)
|
||||
throw new Exception("wierd");
|
||||
|
||||
for (i = 0; i < max_order; i++)
|
||||
lpc_tmp[i] = 0;
|
||||
|
||||
err = 1.0;
|
||||
if (autoc != null)
|
||||
err = autoc[0];
|
||||
|
||||
for (i = 0; i < max_order; i++)
|
||||
{
|
||||
if (reff != null)
|
||||
{
|
||||
r = reff[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
r = -autoc[i + 1];
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
r -= lpc_tmp[j] * autoc[i - j];
|
||||
}
|
||||
r /= err;
|
||||
err *= 1.0 - (r * r);
|
||||
}
|
||||
|
||||
i2 = (i >> 1);
|
||||
lpc_tmp[i] = r;
|
||||
for (j = 0; j < i2; j++)
|
||||
{
|
||||
tmp = lpc_tmp[j];
|
||||
lpc_tmp[j] += r * lpc_tmp[i - 1 - j];
|
||||
lpc_tmp[i - 1 - j] += r * tmp;
|
||||
}
|
||||
if (0 != (i & 1))
|
||||
{
|
||||
lpc_tmp[j] += lpc_tmp[j] * r;
|
||||
}
|
||||
|
||||
for (j = 0; j <= i; j++)
|
||||
{
|
||||
lpc[i * MAX_LPC_ORDER + j] = -lpc_tmp[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute LPC coefs for Flake.OrderMethod._EST
|
||||
* Faster LPC coeff computation by first calculating the reflection coefficients
|
||||
* using Schur recursion. That allows for estimating the optimal order before
|
||||
* running Levinson recursion.
|
||||
*/
|
||||
static unsafe uint
|
||||
compute_lpc_coefs_est(/*const*/ double* autoc, uint max_order,
|
||||
double* lpc/*[][MAX_LPC_ORDER]*/)
|
||||
{
|
||||
double* gen0 = stackalloc double[MAX_LPC_ORDER];
|
||||
double* gen1 = stackalloc double[MAX_LPC_ORDER];
|
||||
double* reff = stackalloc double[MAX_LPC_ORDER];
|
||||
|
||||
// Schur recursion
|
||||
for (uint i = 0; i < max_order; i++)
|
||||
gen0[i] = gen1[i] = autoc[i + 1];
|
||||
|
||||
double error = autoc[0];
|
||||
reff[0] = -gen1[0] / error;
|
||||
error += gen1[0] * reff[0];
|
||||
for (uint i = 1; i < max_order; i++)
|
||||
{
|
||||
for (uint j = 0; j < max_order - i; j++)
|
||||
{
|
||||
gen1[j] = gen1[j + 1] + reff[i - 1] * gen0[j];
|
||||
gen0[j] = gen1[j + 1] * reff[i - 1] + gen0[j];
|
||||
}
|
||||
reff[i] = -gen1[0] / error;
|
||||
error += gen1[0] * reff[i];
|
||||
}
|
||||
|
||||
// Estimate optimal order using reflection coefficients
|
||||
uint order_est = 1;
|
||||
for (int i = (int)max_order - 1; i >= 0; i--)
|
||||
{
|
||||
if (Math.Abs(reff[i]) > 0.10)
|
||||
{
|
||||
order_est = (uint)i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Levinson recursion
|
||||
compute_lpc_coefs(null, order_est, reff, lpc);
|
||||
return order_est;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quantize LPC coefficients
|
||||
*/
|
||||
public static unsafe void
|
||||
quantize_lpc_coefs(double* lpc_in, int order, uint precision, int* lpc_out,
|
||||
out int shift)
|
||||
{
|
||||
int i;
|
||||
double d, cmax, error;
|
||||
int qmax;
|
||||
int sh, q;
|
||||
|
||||
// define maximum levels
|
||||
qmax = (1 << ((int)precision - 1)) - 1;
|
||||
|
||||
// find maximum coefficient value
|
||||
cmax = 0.0;
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
d = Math.Abs(lpc_in[i]);
|
||||
if (d > cmax)
|
||||
cmax = d;
|
||||
}
|
||||
// if maximum value quantizes to zero, return all zeros
|
||||
if (cmax * (1 << 15) < 1.0)
|
||||
{
|
||||
shift = 0;
|
||||
for (i = 0; i < order; i++)
|
||||
lpc_out[i] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate level shift which scales max coeff to available bits
|
||||
sh = 15;
|
||||
while ((cmax * (1 << sh) > qmax) && (sh > 0))
|
||||
{
|
||||
sh--;
|
||||
}
|
||||
|
||||
// since negative shift values are unsupported in decoder, scale down
|
||||
// coefficients instead
|
||||
if (sh == 0 && cmax > qmax)
|
||||
{
|
||||
double scale = ((double)qmax) / cmax;
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
lpc_in[i] *= scale;
|
||||
}
|
||||
}
|
||||
|
||||
// output quantized coefficients and level shift
|
||||
error = 0;
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
error += lpc_in[i] * (1 << sh);
|
||||
q = (int)(error + 0.5);
|
||||
if (q <= -qmax) q = -qmax + 1;
|
||||
if (q > qmax) q = qmax;
|
||||
error -= q;
|
||||
lpc_out[i] = q;
|
||||
}
|
||||
shift = sh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate LPC coefficients for multiple orders
|
||||
*/
|
||||
public static unsafe uint
|
||||
calc_coefs(/*const*/ int* samples, uint blocksize, uint max_order, OrderMethod omethod, double* lpcs, double* window)
|
||||
{
|
||||
double* autoc = stackalloc double[MAX_LPC_ORDER + 1];
|
||||
|
||||
compute_autocorr(samples, blocksize, max_order + 1, autoc, window);
|
||||
|
||||
uint opt_order = max_order;
|
||||
if (omethod == OrderMethod.Estimate || omethod == OrderMethod.EstSearch)
|
||||
opt_order = compute_lpc_coefs_est(autoc, max_order, lpcs);
|
||||
else
|
||||
compute_lpc_coefs(autoc, max_order, null, lpcs);
|
||||
|
||||
return opt_order;
|
||||
}
|
||||
|
||||
public static unsafe void
|
||||
encode_residual(int* res, int* smp, int n, int order,
|
||||
int* coefs, int shift)
|
||||
{
|
||||
for (int i = 0; i < order; i++)
|
||||
res[i] = smp[i];
|
||||
|
||||
int* s = smp;
|
||||
int* r = res + order;
|
||||
int c0 = coefs[0];
|
||||
int c1 = coefs[1];
|
||||
switch (order)
|
||||
{
|
||||
case 1:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *(s--) - (pred >> shift);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
s -= 2;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
s -= 3;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
s -= 4;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
s -= 5;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[6] * *(s++);
|
||||
pred += coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
s -= 6;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[7] * *(s++);
|
||||
pred += coefs[6] * *(s++);
|
||||
pred += coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
s -= 7;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (int i = order; i < n; i++)
|
||||
{
|
||||
s = smp + i - order;
|
||||
int pred = 0;
|
||||
int* co = coefs + order - 1;
|
||||
int* c7 = coefs + 7;
|
||||
while (co > c7)
|
||||
pred += *(co--) * *(s++);
|
||||
pred += coefs[7] * *(s++);
|
||||
pred += coefs[6] * *(s++);
|
||||
pred += coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(r++) = *s - (pred >> shift);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void
|
||||
decode_residual(int* res, int* smp, int n, int order,
|
||||
int* coefs, int shift)
|
||||
{
|
||||
for (int i = 0; i < order; i++)
|
||||
smp[i] = res[i];
|
||||
|
||||
int* s = smp;
|
||||
int* r = res + order;
|
||||
int c0 = coefs[0];
|
||||
int c1 = coefs[1];
|
||||
switch (order)
|
||||
{
|
||||
case 1:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*(s--) = *(r++) + (pred >> shift);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
s -= 2;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
s -= 3;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
s -= 4;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
s -= 5;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[6] * *(s++);
|
||||
pred += coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
s -= 6;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
int pred = coefs[7] * *(s++);
|
||||
pred += coefs[6] * *(s++);
|
||||
pred += coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
s -= 7;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (int i = order; i < n; i++)
|
||||
{
|
||||
s = smp + i - order;
|
||||
int pred = 0;
|
||||
int* co = coefs + order - 1;
|
||||
int* c7 = coefs + 7;
|
||||
while (co > c7)
|
||||
pred += *(co--) * *(s++);
|
||||
pred += coefs[7] * *(s++);
|
||||
pred += coefs[6] * *(s++);
|
||||
pred += coefs[5] * *(s++);
|
||||
pred += coefs[4] * *(s++);
|
||||
pred += coefs[3] * *(s++);
|
||||
pred += coefs[2] * *(s++);
|
||||
pred += c1 * *(s++);
|
||||
pred += c0 * *(s++);
|
||||
*s = *(r++) + (pred >> shift);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
public static unsafe void
|
||||
decode_residual_long(int* res, int* smp, int n, int order,
|
||||
int* coefs, int shift)
|
||||
{
|
||||
for (int i = 0; i < order; i++)
|
||||
smp[i] = res[i];
|
||||
|
||||
int* s = smp;
|
||||
int* r = res + order;
|
||||
int c0 = coefs[0];
|
||||
int c1 = coefs[1];
|
||||
switch (order)
|
||||
{
|
||||
case 1:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*(s--) = *(r++) + (int)(pred >> shift);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = coefs[2] * (long)*(s++);
|
||||
pred += c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
s -= 2;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = coefs[3] * (long)*(s++);
|
||||
pred += coefs[2] * (long)*(s++);
|
||||
pred += c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
s -= 3;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = coefs[4] * (long)*(s++);
|
||||
pred += coefs[3] * (long)*(s++);
|
||||
pred += coefs[2] * (long)*(s++);
|
||||
pred += c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
s -= 4;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = coefs[5] * (long)*(s++);
|
||||
pred += coefs[4] * (long)*(s++);
|
||||
pred += coefs[3] * (long)*(s++);
|
||||
pred += coefs[2] * (long)*(s++);
|
||||
pred += c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
s -= 5;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = coefs[6] * (long)*(s++);
|
||||
pred += coefs[5] * (long)*(s++);
|
||||
pred += coefs[4] * (long)*(s++);
|
||||
pred += coefs[3] * (long)*(s++);
|
||||
pred += coefs[2] * (long)*(s++);
|
||||
pred += c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
s -= 6;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
for (int i = n - order; i > 0; i--)
|
||||
{
|
||||
long pred = coefs[7] * (long)*(s++);
|
||||
pred += coefs[6] * (long)*(s++);
|
||||
pred += coefs[5] * (long)*(s++);
|
||||
pred += coefs[4] * (long)*(s++);
|
||||
pred += coefs[3] * (long)*(s++);
|
||||
pred += coefs[2] * (long)*(s++);
|
||||
pred += c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
s -= 7;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (int i = order; i < n; i++)
|
||||
{
|
||||
s = smp + i - order;
|
||||
long pred = 0;
|
||||
int* co = coefs + order - 1;
|
||||
int* c7 = coefs + 7;
|
||||
while (co > c7)
|
||||
pred += *(co--) * (long)*(s++);
|
||||
pred += coefs[7] * (long)*(s++);
|
||||
pred += coefs[6] * (long)*(s++);
|
||||
pred += coefs[5] * (long)*(s++);
|
||||
pred += coefs[4] * (long)*(s++);
|
||||
pred += coefs[3] * (long)*(s++);
|
||||
pred += coefs[2] * (long)*(s++);
|
||||
pred += c1 * (long)*(s++);
|
||||
pred += c0 * (long)*(s++);
|
||||
*s = *(r++) + (int)(pred >> shift);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user