Flake: use new window functions (partial_tukey, punchout_tukey).

This commit is contained in:
Grigory Chudov
2014-08-26 23:48:16 -04:00
parent 5e784881f1
commit 52879ed70c
15 changed files with 1314 additions and 214 deletions

View File

@@ -6,12 +6,14 @@
public int* samples;
public uint done_fixed;
public LpcContext[] lpc_ctx;
public LpcSubframeInfo sf;
public ALACSubframeInfo()
{
best = new ALACSubframe();
lpc_ctx = new LpcContext[Alac.MAX_LPC_WINDOWS];
for (int i = 0; i < Alac.MAX_LPC_WINDOWS; i++)
sf = new LpcSubframeInfo();
lpc_ctx = new LpcContext[lpc.MAX_LPC_WINDOWS];
for (int i = 0; i < lpc.MAX_LPC_WINDOWS; i++)
lpc_ctx[i] = new LpcContext();
}
@@ -21,7 +23,8 @@
best.residual = r;
best.size = AudioSamples.UINT32_MAX;
best.order = 0;
for (int iWindow = 0; iWindow < Alac.MAX_LPC_WINDOWS; iWindow++)
sf.Reset();
for (int iWindow = 0; iWindow < lpc.MAX_LPC_WINDOWS; iWindow++)
lpc_ctx[iWindow].Reset();
done_fixed = 0;
}

View File

@@ -36,7 +36,7 @@ namespace CUETools.Codecs.ALAC
public class ALACWriterSettings: AudioEncoderSettings
{
public ALACWriterSettings()
: base("0 1 2 3 4 5 6 7 8 9 10", "3")
: base("0 1 2 3 4 5 6 7 8 9 10", "5")
{
}
@@ -91,6 +91,7 @@ namespace CUETools.Codecs.ALAC
int[] verifyBuffer;
int[] residualBuffer;
float[] windowBuffer;
LpcWindowSection[,] windowSections;
int samplesInBuffer = 0;
int m_blockSize = 0;
@@ -122,7 +123,8 @@ namespace CUETools.Codecs.ALAC
samplesBuffer = new int[Alac.MAX_BLOCKSIZE * (Settings.PCM.ChannelCount == 2 ? 5 : Settings.PCM.ChannelCount)];
residualBuffer = new int[Alac.MAX_BLOCKSIZE * (Settings.PCM.ChannelCount == 2 ? 6 : Settings.PCM.ChannelCount + 1)];
windowBuffer = new float[Alac.MAX_BLOCKSIZE * 2 * Alac.MAX_LPC_WINDOWS];
windowBuffer = new float[Alac.MAX_BLOCKSIZE * 2 * lpc.MAX_LPC_WINDOWS];
windowSections = new LpcWindowSection[lpc.MAX_LPC_WINDOWS, lpc.MAX_LPC_SECTIONS];
eparams.set_defaults(m_settings.EncoderModeIndex);
@@ -875,7 +877,11 @@ namespace CUETools.Codecs.ALAC
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
lpc_ctx.GetReflection(max_order, smp, n, frame.window_buffer + iWindow * Alac.MAX_BLOCKSIZE * 2);
fixed (LpcWindowSection* sections = &windowSections[iWindow, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, max_order, smp,
frame.window_buffer + iWindow * Alac.MAX_BLOCKSIZE * 2, sections,
Settings.PCM.BitsPerSample * 2 + BitReader.log2i(frame.blocksize) >= 61);
lpc_ctx.ComputeLPC(lpcs);
lpc_ctx.SortOrdersAkaike(frame.blocksize, eparams.estimation_depth, min_order, max_order, 5.0, 1.0/18);
for (i = 0; i < eparams.estimation_depth && i < max_order; i++)
@@ -945,20 +951,36 @@ namespace CUETools.Codecs.ALAC
{
case WindowMethod.Estimate:
{
int best_window = -1;
double best_error = 0;
int order = 2;
int order = 4;
float* err = stackalloc float[lpc.MAX_LPC_ORDER];
for (int i = 0; i < _windowcount; i++)
{
frame.subframes[ch].lpc_ctx[i].GetReflection(order, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer + i * Alac.MAX_BLOCKSIZE * 2);
double err = frame.subframes[ch].lpc_ctx[i].prediction_error[order - 1] / frame.subframes[ch].lpc_ctx[i].autocorr_values[0];
if (best_window == -1 || best_error > err)
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[i];
fixed (LpcWindowSection* sections = &windowSections[i, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, order,
frame.subframes[ch].samples,
frame.window_buffer + i * Alac.MAX_BLOCKSIZE * 2, sections,
Settings.PCM.BitsPerSample * 2 + BitReader.log2i(frame.blocksize) >= 61);
lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, order, 4.5, 0.0);
err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) - frame.blocksize * Math.Log(lpc_ctx.autocorr_values[0]) / 2);
}
int* best_windows = stackalloc int[lpc.MAX_LPC_ORDER];
for (int i = 0; i < _windowcount; i++)
best_windows[i] = i;
for (int i = 0; i < _windowcount; i++)
{
best_window = i;
best_error = err;
for (int j = i + 1; j < _windowcount; j++)
{
if (err[best_windows[i]] > err[best_windows[j]])
{
int tmp = best_windows[j];
best_windows[j] = best_windows[i];
best_windows[i] = tmp;
}
}
return best_window;
}
return best_windows[0];
}
case WindowMethod.Evaluate:
encode_residual_pass1(frame, ch, -1);
@@ -978,10 +1000,16 @@ namespace CUETools.Codecs.ALAC
case StereoMethod.Estimate:
for (int ch = 0; ch < subframes; ch++)
{
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[0];
int iWindow = 0;
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
int stereo_order = Math.Min(8, eparams.max_prediction_order);
double alpha = 1.5; // 4.5 + eparams.max_prediction_order / 10.0;
lpc_ctx.GetReflection(stereo_order, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer);
fixed (LpcWindowSection* sections = &windowSections[iWindow, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, stereo_order,
frame.subframes[ch].samples,
frame.window_buffer + iWindow * Alac.MAX_BLOCKSIZE * 2, sections,
Settings.PCM.BitsPerSample * 2 + BitReader.log2i(frame.blocksize) >= 61);
lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, stereo_order, alpha, 0);
frame.subframes[ch].best.size = (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], alpha, 0));
}
@@ -1060,13 +1088,17 @@ namespace CUETools.Codecs.ALAC
unsafe void calculate_window(float * window, window_function func, WindowFunction flag)
{
if ((eparams.window_function & flag) == 0 || _windowcount == Alac.MAX_LPC_WINDOWS)
if ((eparams.window_function & flag) == 0 || _windowcount == lpc.MAX_LPC_WINDOWS)
return;
int sz = _windowsize;
float* pos = window + _windowcount * Alac.MAX_BLOCKSIZE * 2;
do
{
windowSections[_windowcount, 0].setData(0, sz);
for (int j = 1; j < lpc.MAX_LPC_SECTIONS; j++)
windowSections[_windowcount, j].setZero(sz, sz);
func(pos, sz);
break;
if ((sz & 1) != 0)
break;
pos += sz;
@@ -1091,8 +1123,32 @@ namespace CUETools.Codecs.ALAC
calculate_window(window, lpc.window_tukey, WindowFunction.Tukey);
calculate_window(window, lpc.window_hann, WindowFunction.Hann);
calculate_window(window, lpc.window_flattop, WindowFunction.Flattop);
int tukey_parts = 2;
double overlap = -0.3;
double overlap_units = overlap / (1.0 - overlap);
for (int m = 0; m < tukey_parts; m++)
calculate_window(window, (w, wsz) =>
{
lpc.window_punchout_tukey(w, wsz, 0.1,
m / (tukey_parts + overlap_units),
(m + 1 + overlap_units) / (tukey_parts + overlap_units));
}, WindowFunction.PartialTukey);
tukey_parts = 3;
overlap = -0.1;
//overlap = 0.1;
overlap_units = overlap / (1.0 - overlap);
for (int m = 0; m < tukey_parts; m++)
calculate_window(window, (w, wsz) =>
{
lpc.window_punchout_tukey(w, wsz, 0.1,
m / (tukey_parts + overlap_units),
(m + 1 + overlap_units) / (tukey_parts + overlap_units));
}, WindowFunction.PunchoutTukey);
if (_windowcount == 0)
throw new Exception("invalid windowfunction");
fixed (LpcWindowSection* sections = &windowSections[0, 0])
LpcWindowSection.Detect(_windowcount, window, Alac.MAX_BLOCKSIZE * 2, _windowsize, sections);
}
frame.window_buffer = window;
@@ -1793,11 +1849,13 @@ namespace CUETools.Codecs.ALAC
case 4:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PartialTukey | WindowFunction.PunchoutTukey;
max_prediction_order = 8;
break;
case 5:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PartialTukey | WindowFunction.PunchoutTukey;
break;
case 6:
stereo_method = StereoMethod.Estimate;

View File

@@ -28,7 +28,6 @@ namespace CUETools.Codecs.ALAC
public const int MAX_RICE_PARAM = 14;
public const int MAX_PARTITION_ORDER = 8;
public const int MAX_PARTITIONS = 1 << MAX_PARTITION_ORDER;
public const int MAX_LPC_WINDOWS = 4;
public const uint UINT32_MAX = 0xffffffff;

View File

@@ -7,6 +7,8 @@
Hann = 4,
Flattop = 8,
Bartlett = 16,
TukFlat = 10
TukFlat = 10,
PartialTukey = 32,
PunchoutTukey = 64,
}
}

View File

@@ -270,6 +270,8 @@ namespace CUETools.Codecs.FLACCL
string _path;
long _position;
public const int MAX_LPC_WINDOWS = 2;
// number of audio channels
// valid values are 1 to 8
int channels, ch_code;
@@ -1090,7 +1092,7 @@ namespace CUETools.Codecs.FLACCL
unsafe void calculate_window(FLACCLTask task, window_function func, WindowFunction flag)
{
if ((eparams.window_function & flag) == 0 || task.nWindowFunctions == lpc.MAX_LPC_WINDOWS)
if ((eparams.window_function & flag) == 0 || task.nWindowFunctions == MAX_LPC_WINDOWS)
return;
func(((float*)task.clWindowFunctionsPtr) + task.nWindowFunctions * task.frameSize, task.frameSize);
@@ -2508,10 +2510,10 @@ namespace CUETools.Codecs.FLACCL
int residualBufferLen = sizeof(int) * MAX_CHANNELSIZE * channels; // need to adjust residualOffset?
int partitionsLen = sizeof(int) * ((writer.Settings.PCM.BitsPerSample > 16 ? 31 : 15) * 2 << 8) * channels * MAX_FRAMES;
int riceParamsLen = sizeof(int) * (4 << 8) * channels * MAX_FRAMES;
int autocorLen = sizeof(float) * (MAX_ORDER + 1) * lpc.MAX_LPC_WINDOWS * channelsCount * MAX_FRAMES;
int autocorLen = sizeof(float) * (MAX_ORDER + 1) * FLACCLWriter.MAX_LPC_WINDOWS * channelsCount * MAX_FRAMES;
int lpcDataLen = autocorLen * 32;
int resOutLen = sizeof(int) * channelsCount * (lpc.MAX_LPC_WINDOWS * lpc.MAX_LPC_ORDER + 8) * MAX_FRAMES;
int wndLen = sizeof(float) * MAX_CHANNELSIZE /** 2*/ * lpc.MAX_LPC_WINDOWS;
int resOutLen = sizeof(int) * channelsCount * (FLACCLWriter.MAX_LPC_WINDOWS * lpc.MAX_LPC_ORDER + 8) * MAX_FRAMES;
int wndLen = sizeof(float) * MAX_CHANNELSIZE /** 2*/ * FLACCLWriter.MAX_LPC_WINDOWS;
int selectedLen = sizeof(int) * 32 * channelsCount * MAX_FRAMES;
int riceLen = sizeof(int) * channels * MAX_CHANNELSIZE;

View File

@@ -11,6 +11,7 @@
public int frame_number;
public FlacSubframe current;
public float* window_buffer;
public int nSeg = 0;
public BitWriter writer = null;
public int writer_offset = 0;

View File

@@ -7,6 +7,7 @@ namespace CUETools.Codecs.FLAKE
public FlacSubframeInfo()
{
best = new FlacSubframe();
sf = new LpcSubframeInfo();
lpc_ctx = new LpcContext[lpc.MAX_LPC_WINDOWS];
for (int i = 0; i < lpc.MAX_LPC_WINDOWS; i++)
lpc_ctx[i] = new LpcContext();
@@ -22,8 +23,10 @@ namespace CUETools.Codecs.FLAKE
best.residual = r;
best.type = SubframeType.Verbatim;
best.size = AudioSamples.UINT32_MAX;
sf.Reset();
for (int iWindow = 0; iWindow < lpc.MAX_LPC_WINDOWS; iWindow++)
lpc_ctx[iWindow].Reset();
//sf.obits = obits;
done_fixed = 0;
}
@@ -33,5 +36,6 @@ namespace CUETools.Codecs.FLAKE
public int* samples;
public uint done_fixed;
public LpcContext[] lpc_ctx;
public LpcSubframeInfo sf;
};
}

View File

@@ -20,6 +20,7 @@
*/
#define NOINTEROP
#define VARIANT1
using System;
using System.ComponentModel;
@@ -84,14 +85,14 @@ namespace CUETools.Codecs.FLAKE
}
[DefaultValue(-1)]
[DefaultValueForMode(3, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0)]
[DefaultValueForMode(2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0)]
[Browsable(false)]
[DisplayName("MinFixedOrder")]
[SRDescription(typeof(Properties.Resources), "MinFixedOrderDescription")]
public int MinFixedOrder { get; set; }
[DefaultValue(-1)]
[DefaultValueForMode(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4)]
[DefaultValueForMode(2, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4)]
[Browsable(false)]
[DisplayName("MaxFixedOrder")]
[SRDescription(typeof(Properties.Resources), "MaxFixedOrderDescription")]
@@ -104,7 +105,7 @@ namespace CUETools.Codecs.FLAKE
public int MinLPCOrder { get; set; }
[DefaultValue(-1)]
[DefaultValueForMode(6, 8, 12, 8, 12, 12, 12, 12, 12, 32, 32, 32)]
[DefaultValueForMode(8, 8, 8, 12, 12, 12, 12, 12, 12, 32, 32, 32)]
[Browsable(false)]
[DisplayName("MaxLPCOrder")]
[SRDescription(typeof(Properties.Resources), "MaxLPCOrderDescription")]
@@ -117,7 +118,7 @@ namespace CUETools.Codecs.FLAKE
public int MinPartitionOrder { get; set; }
[DefaultValue(-1)]
[DefaultValueForMode(6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8)]
[DefaultValueForMode(6, 8, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8)]
[DisplayName("MaxPartitionOrder")]
[Browsable(false)]
[SRDescription(typeof(Properties.Resources), "MaxPartitionOrderDescription")]
@@ -192,6 +193,9 @@ namespace CUETools.Codecs.FLAKE
int[] residualBuffer;
float[] windowBuffer;
double[] windowScale;
LpcWindowSection[, ,] windowSections;
WindowFunction[] windowType;
int samplesInBuffer = 0;
int m_blockSize = 0;
@@ -230,6 +234,8 @@ namespace CUETools.Codecs.FLAKE
residualBuffer = new int[Flake.MAX_BLOCKSIZE * (channels == 2 ? 10 : channels + 1)];
windowBuffer = new float[Flake.MAX_BLOCKSIZE * 2 * lpc.MAX_LPC_WINDOWS];
windowScale = new double[lpc.MAX_LPC_WINDOWS];
windowType = new WindowFunction[lpc.MAX_LPC_WINDOWS];
windowSections = new LpcWindowSection[12, lpc.MAX_LPC_WINDOWS, lpc.MAX_LPC_SECTIONS];
eparams.flake_set_defaults(m_settings);
@@ -526,57 +532,291 @@ namespace CUETools.Codecs.FLAKE
unsafe static void encode_residual_fixed(int* res, int* smp, int n, int order)
{
int i;
int s0, s1, s2;
switch (order)
int next_error_0, next_error_1, next_error_2, next_error_3, next_error_4;
int last_error_0, last_error_1, last_error_2, last_error_3;
int* end = smp + n;
if (order == 0)
{
case 0:
AudioSamples.MemCpy(res, smp, n);
return;
case 1:
*(res++) = s1 = *(smp++);
for (i = n - 1; i > 0; i--)
{
s0 = *(smp++);
*(res++) = s0 - s1;
s1 = s0;
}
return;
case 2:
*(res++) = s2 = *(smp++);
*(res++) = s1 = *(smp++);
for (i = n - 2; i > 0; i--)
{
s0 = *(smp++);
*(res++) = s0 - 2 * s1 + s2;
s2 = s1;
s1 = s0;
}
return;
case 3:
res[0] = smp[0];
res[1] = smp[1];
res[2] = smp[2];
for (i = 3; i < n; i++)
{
res[i] = smp[i] - 3 * smp[i - 1] + 3 * smp[i - 2] - smp[i - 3];
}
return;
case 4:
res[0] = smp[0];
res[1] = smp[1];
res[2] = smp[2];
res[3] = smp[3];
for (i = 4; i < n; i++)
{
res[i] = smp[i] - 4 * smp[i - 1] + 6 * smp[i - 2] - 4 * smp[i - 3] + smp[i - 4];
}
return;
default:
return;
}
}
next_error_0 = *(res++) = *(smp++);
last_error_0 = next_error_0;
if (order == 1)
{
while (smp < end)
{
#if VARIANT1
int error, save;
error = *(smp++); save = error;
error -= last_error_0; *(res++) = error; last_error_0 = save;
#else
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
last_error_0 = next_error_0;
*(res++) = (int)next_error_1;
#endif
}
return;
}
next_error_0 = *(res++) = *(smp++);
next_error_1 = next_error_0 - last_error_0;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
if (order == 2)
{
while (smp < end)
{
#if VARIANT1
int error, save;
error = *(smp++); save = error;
error -= last_error_0; last_error_0 = save; save = error;
error -= last_error_1; *(res++) = error; last_error_1 = save;
#else
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
*(res++) = (int)next_error_2;
#endif
}
return;
}
next_error_0 = *(res++) = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
if (order == 3)
{
while (smp < end)
{
#if VARIANT1
int error, save;
error = *(smp++); save = error;
error -= last_error_0; last_error_0 = save; save = error;
error -= last_error_1; last_error_1 = save; save = error;
error -= last_error_2; *(res++) = error; last_error_2 = save;
#else
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
next_error_3 = next_error_2 - last_error_2;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
*(res++) = (int)next_error_3;
#endif
}
return;
}
next_error_0 = *(res++) = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
next_error_3 = next_error_2 - last_error_2;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
last_error_3 = next_error_3;
if (order == 4)
{
while (smp < end)
{
#if VARIANT1
int error, save;
error = *(smp++); save = error;
error -= last_error_0; last_error_0 = save; save = error;
error -= last_error_1; last_error_1 = save; save = error;
error -= last_error_2; last_error_2 = save; save = error;
error -= last_error_3; *(res++) = error; last_error_3 = save;
#else
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
next_error_3 = next_error_2 - last_error_2;
next_error_4 = next_error_3 - last_error_3;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
last_error_3 = next_error_3;
*(res++) = (int)next_error_4;
#endif
}
return;
}
throw new ArgumentOutOfRangeException();
}
#if XXX
unsafe static int encode_residual_fixed_estimate_best_order(int* res, int* smp, int n, int order)
{
int next_error_0, next_error_1, next_error_2, next_error_3, next_error_4;
int last_error_0, last_error_1, last_error_2, last_error_3;
int* end = smp + n;
ulong total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
if (order == 0)
{
AudioSamples.MemCpy(res, smp, n);
return 0;
}
next_error_0 = *(res++) = *(smp++);
last_error_0 = next_error_0;
if (order == 1)
{
while (smp < end)
{
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
last_error_0 = next_error_0;
total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31));
total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31));
*(res++) = (int)next_error_1;
}
if ((total_error_0 < total_error_1))
return 0;
return 1;
}
next_error_0 = *(res++) = *(smp++);
next_error_1 = next_error_0 - last_error_0;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
if (order == 2)
{
while (smp < end)
{
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31));
total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31));
total_error_2 += (ulong)((next_error_2 << 1) ^ (next_error_2 >> 31));
*(res++) = (int)next_error_2;
}
if ((total_error_0 < total_error_1) & (total_error_0 < total_error_2))
return 0;
else if ((total_error_1 < total_error_2))
return 1;
return 2;
}
next_error_0 = *(res++) = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
if (order == 3)
{
while (smp < end)
{
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
next_error_3 = next_error_2 - last_error_2;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31));
total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31));
total_error_2 += (ulong)((next_error_2 << 1) ^ (next_error_2 >> 31));
total_error_3 += (ulong)((next_error_3 << 1) ^ (next_error_3 >> 31));
*(res++) = (int)next_error_3;
}
if ((total_error_0 < total_error_1) & (total_error_0 < total_error_2) & (total_error_0 < total_error_3))
return 0;
else if ((total_error_1 < total_error_2) & (total_error_1 < total_error_3))
return 1;
else if ((total_error_2 < total_error_3))
return 2;
return 3;
}
next_error_0 = *(res++) = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
next_error_3 = next_error_2 - last_error_2;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
last_error_3 = next_error_3;
if (order == 4)
{
while (smp < end)
{
next_error_0 = *(smp++);
next_error_1 = next_error_0 - last_error_0;
next_error_2 = next_error_1 - last_error_1;
next_error_3 = next_error_2 - last_error_2;
next_error_4 = next_error_3 - last_error_3;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
last_error_3 = next_error_3;
total_error_0 += (ulong)((next_error_0 << 1) ^ (next_error_0 >> 31));
total_error_1 += (ulong)((next_error_1 << 1) ^ (next_error_1 >> 31));
total_error_2 += (ulong)((next_error_2 << 1) ^ (next_error_2 >> 31));
total_error_3 += (ulong)((next_error_3 << 1) ^ (next_error_3 >> 31));
total_error_4 += (ulong)((next_error_4 << 1) ^ (next_error_4 >> 31));
*(res++) = (int)next_error_4;
}
if ((total_error_0 < total_error_1) & (total_error_0 < total_error_2) & (total_error_0 < total_error_3) & (total_error_0 < total_error_4))
return 0;
else if ((total_error_1 < total_error_2) & (total_error_1 < total_error_3) & (total_error_1 < total_error_4))
return 1;
else if ((total_error_2 < total_error_3) & (total_error_2 < total_error_4))
return 2;
else if (total_error_3 < total_error_4)
return 3;
return 4;
}
throw new ArgumentOutOfRangeException();
}
#endif
static unsafe uint calc_optimal_rice_params(int porder, int* parm, ulong* sums, uint n, uint pred_order, ref int method)
{
uint part = (1U << porder);
@@ -1079,6 +1319,21 @@ new int[] { // 30
frame.current.order = order;
frame.current.type = SubframeType.Fixed;
#if XXX
int best_order = order;
if (frame.subframes[ch].done_fixed == 0)
{
best_order = encode_residual_fixed_estimate_best_order(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order);
if (best_order != order)
{
//frame.subframes[ch].done_fixed |= (1U << order);
order = best_order;
frame.current.order = order;
encode_residual_fixed(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order);
}
}
else
#endif
encode_residual_fixed(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order);
int pmax = get_max_p_order(m_settings.MaxPartitionOrder, frame.blocksize, frame.current.order);
@@ -1091,7 +1346,78 @@ new int[] { // 30
frame.ChooseBestSubframe(ch);
}
unsafe void encode_residual(FlacFrame frame, int ch, PredictionType predict, OrderMethod omethod, int pass, int best_window)
unsafe void fixed_compute_best_predictor(int* data, uint data_len, ulong* errors)//, float* residual_bits_per_sample)
{
long last_error_0 = data[-1];
long last_error_1 = data[-1] - data[-2];
long last_error_2 = last_error_1 - (data[-2] - data[-3]);
long last_error_3 = last_error_2 - (data[-2] - 2 * data[-3] + data[-4]);
ulong total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
#if VARIANT1
long error, save;
int* finish = data + data_len;
while (data < finish)
{
error = *(data++); total_error_0 += (ulong)((error << 1) ^ (error >> 63)); save = error;
error -= last_error_0; total_error_1 += (ulong)((error << 1) ^ (error >> 63)); last_error_0 = save; save = error;
error -= last_error_1; total_error_2 += (ulong)((error << 1) ^ (error >> 63)); last_error_1 = save; save = error;
error -= last_error_2; total_error_3 += (ulong)((error << 1) ^ (error >> 63)); last_error_2 = save; save = error;
error -= last_error_3; total_error_4 += (ulong)((error << 1) ^ (error >> 63)); last_error_3 = save;
}
#else
int* finish = data + data_len;
while (data < finish)
{
long next_error_0 = *(data++);
long next_error_1 = next_error_0 - last_error_0;
long next_error_2 = next_error_1 - last_error_1;
long next_error_3 = next_error_2 - last_error_2;
long next_error_4 = next_error_3 - last_error_3;
last_error_0 = next_error_0;
last_error_1 = next_error_1;
last_error_2 = next_error_2;
last_error_3 = next_error_3;
total_error_0 += (ulong)((last_error_0 << 1) ^ (last_error_0 >> 63));
total_error_1 += (ulong)((last_error_1 << 1) ^ (last_error_1 >> 63));
total_error_2 += (ulong)((last_error_2 << 1) ^ (last_error_2 >> 63));
total_error_3 += (ulong)((last_error_3 << 1) ^ (last_error_3 >> 63));
total_error_4 += (ulong)((next_error_4 << 1) ^ (next_error_4 >> 63));
}
#endif
errors[0] = total_error_0;
errors[1] = total_error_1;
errors[2] = total_error_2;
errors[3] = total_error_3;
errors[4] = total_error_4;
//residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
}
unsafe int fixed_compute_best_predictor_order(ulong* error)
{
int order;
if ((error[0] < error[1]) & (error[0] < error[2]) & (error[0] < error[3]) & (error[0] < error[4]))
order = 0;
else if ((error[1] < error[2]) & (error[1] < error[3]) & (error[1] < error[4]))
order = 1;
else if ((error[2] < error[3]) & (error[2] < error[4]))
order = 2;
else if (error[3] < error[4])
order = 3;
else
order = 4;
return order;
}
unsafe void encode_residual(FlacFrame frame, int ch, PredictionType predict, OrderMethod omethod, int pass, int windows_mask)
{
int* smp = frame.subframes[ch].samples;
int i, n = frame.blocksize;
@@ -1132,12 +1458,14 @@ new int[] { // 30
for (int iWindow = 0; iWindow < _windowcount; iWindow++)
{
if (best_window != -1 && iWindow != best_window)
if ((windows_mask & (1 << iWindow)) == 0)
continue;
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
lpc_ctx.GetReflection(max_order, smp, n, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2);
fixed (LpcWindowSection* sections = &windowSections[frame.nSeg, iWindow, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, max_order, smp, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2, sections,
frame.subframes[ch].obits * 2 + BitReader.log2i(frame.blocksize) >= 61);
lpc_ctx.ComputeLPC(lpcs);
//int frameSize = n;
@@ -1217,9 +1545,22 @@ new int[] { // 30
int max_fixed_order = Math.Min(m_settings.MaxFixedOrder, 4);
int min_fixed_order = Math.Min(m_settings.MinFixedOrder, max_fixed_order);
for (i = min_fixed_order; i <= max_fixed_order; i++)
if (min_fixed_order == 0 && max_fixed_order == 4)
{
if (frame.subframes[ch].done_fixed == 0)
{
ulong* fixed_errors = stackalloc ulong[5];
fixed_compute_best_predictor(smp + 4, (uint)n - 4, fixed_errors);
i = fixed_compute_best_predictor_order(fixed_errors);
encode_residual_fixed_sub(frame, i, ch);
}
}
else
{
for (i = max_fixed_order; i >= min_fixed_order; i--)
encode_residual_fixed_sub(frame, i, ch);
}
}
}
@@ -1379,25 +1720,25 @@ new int[] { // 30
bitwriter.flush();
}
unsafe void encode_residual_pass1(FlacFrame frame, int ch, int best_window)
unsafe void encode_residual_pass1(FlacFrame frame, int ch, int windows_mask)
{
int max_prediction_order = m_settings.MaxLPCOrder;
int max_fixed_order = m_settings.MaxFixedOrder;
int min_fixed_order = m_settings.MinFixedOrder;
//int max_fixed_order = m_settings.MaxFixedOrder;
//int min_fixed_order = m_settings.MinFixedOrder;
int lpc_min_precision_search = eparams.lpc_min_precision_search;
int lpc_max_precision_search = eparams.lpc_max_precision_search;
int max_partition_order = m_settings.MaxPartitionOrder;
int estimation_depth = eparams.estimation_depth;
var development_mode = eparams.development_mode;
m_settings.MinFixedOrder = 2;
m_settings.MaxFixedOrder = 2;
//m_settings.MinFixedOrder = 2;
//m_settings.MaxFixedOrder = 2;
eparams.lpc_min_precision_search = eparams.lpc_max_precision_search;
m_settings.MaxLPCOrder = Math.Min(m_settings.MaxLPCOrder, Math.Max(m_settings.MinLPCOrder, 8));
eparams.estimation_depth = 1;
eparams.development_mode = Math.Min(eparams.development_mode, -1);
encode_residual(frame, ch, eparams.prediction_type, OrderMethod.Akaike, 1, best_window);
m_settings.MinFixedOrder = min_fixed_order;
m_settings.MaxFixedOrder = max_fixed_order;
encode_residual(frame, ch, eparams.prediction_type, OrderMethod.Akaike, 1, windows_mask);
//m_settings.MinFixedOrder = min_fixed_order;
//m_settings.MaxFixedOrder = max_fixed_order;
m_settings.MaxLPCOrder = max_prediction_order;
eparams.lpc_min_precision_search = lpc_min_precision_search;
eparams.lpc_max_precision_search = lpc_max_precision_search;
@@ -1408,36 +1749,140 @@ new int[] { // 30
unsafe void encode_residual_pass2(FlacFrame frame, int ch)
{
encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 2, estimate_best_window(frame, ch));
encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 2, estimate_best_windows(frame, ch));
}
unsafe int estimate_best_window(FlacFrame frame, int ch)
unsafe int estimate_best_windows_akaike(FlacFrame frame, int ch, int count, bool onePerType)
{
if (_windowcount == 1)
return 0;
int* windows_present = stackalloc int[_windowcount];
for (int i = 0; i < _windowcount; i++)
windows_present[i] = 0;
if (onePerType)
{
for (int i = 0; i < _windowcount; i++)
for (int j = 0; j < _windowcount; j++)
if (windowType[j] == windowType[i])
windows_present[j]++;
}
float* err = stackalloc float[lpc.MAX_LPC_ORDER];
for (int i = 0; i < _windowcount; i++)
{
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[i];
if (onePerType && windows_present[i] <= count)
{
err[i] = 0;
continue;
}
int estimate_order = 4;
fixed (LpcWindowSection* sections = &windowSections[frame.nSeg, i, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, estimate_order,
frame.subframes[ch].samples, frame.window_buffer + i * Flake.MAX_BLOCKSIZE * 2, sections,
frame.subframes[ch].obits * 2 + BitReader.log2i(frame.blocksize) >= 61);
lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, estimate_order, 4.5, 0.0);
//err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0));
//err[i] = (float)((frame.blocksize * lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1] / windowScale[i]) + lpc_ctx.best_orders[0] * 4.5);
//err[i] = (float)((frame.blocksize * lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1] / windowScale[i]) + lpc_ctx.best_orders[0] * frame.subframes[ch].obits);
// realistic
//err[i] = (float)(frame.blocksize * Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1]) / Math.Log(2) / 2.5
//- windowScale[i] / 2 + lpc_ctx.best_orders[0] * frame.subframes[ch].obits / 2);
//err[i] = (float)(frame.blocksize * Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1]) / Math.Log(2) / 2.5
//- frame.blocksize * Math.Log(lpc_ctx.autocorr_values[0]) / 2.1
//+ Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5 / 2.5 / Math.Log(2));
// Akaike
//err[i] = (float)(frame.blocksize * (Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1])) + Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5);
//err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) - frame.blocksize * (frame.subframes[ch].obits + Math.Log(windowScale[i] / frame.blocksize) / 2));
// tested good
err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) - frame.blocksize * Math.Log(lpc_ctx.autocorr_values[0]) / 2);
}
int* best_windows = stackalloc int[lpc.MAX_LPC_ORDER];
for (int i = 0; i < _windowcount; i++)
best_windows[i] = i;
for (int i = 0; i < _windowcount; i++)
{
for (int j = i + 1; j < _windowcount; j++)
{
if (err[best_windows[i]] > err[best_windows[j]])
{
int tmp = best_windows[j];
best_windows[j] = best_windows[i];
best_windows[i] = tmp;
}
}
}
int window_mask = 0;
if (onePerType)
{
for (int i = 0; i < _windowcount; i++)
windows_present[i] = count;
for (int i = 0; i < _windowcount; i++)
{
int w = best_windows[i];
if (windows_present[w] > 0)
{
for (int j = 0; j < _windowcount; j++)
if (windowType[j] == windowType[w])
windows_present[j]--;
window_mask |= 1 << w;
}
}
}
else
{
for (int i = 0; i < _windowcount && i < count; i++)
window_mask |= 1 << best_windows[i];
}
return window_mask;
}
unsafe int estimate_best_windows(FlacFrame frame, int ch)
{
if (_windowcount == 1 || eparams.prediction_type == PredictionType.Fixed)
return 1;
switch (eparams.window_method)
{
case WindowMethod.Estimate:
return estimate_best_windows_akaike(frame, ch, 1, false);
case WindowMethod.Estimate2:
return estimate_best_windows_akaike(frame, ch, 2, false);
case WindowMethod.Estimate3:
return estimate_best_windows_akaike(frame, ch, 3, false);
case WindowMethod.EstimateN:
return estimate_best_windows_akaike(frame, ch, 1, true);
case WindowMethod.Evaluate2:
encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 2, false));
return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0;
case WindowMethod.Evaluate3:
encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 3, false));
return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0;
case WindowMethod.EvaluateN:
encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 1, true));
#if XXX
if (frame.subframes[ch].best.type == SubframeType.LPC && frame.subframes[ch].best.order <= 4)
{
int best_window = -1;
double best_error = 0;
int order = 2;
for (int i = 0; i < _windowcount; i++)
{
frame.subframes[ch].lpc_ctx[i].GetReflection(order, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer + i * Flake.MAX_BLOCKSIZE * 2);
double err = frame.subframes[ch].lpc_ctx[i].prediction_error[order - 1] / frame.subframes[ch].lpc_ctx[i].autocorr_values[0];
//double err = frame.subframes[ch].lpc_ctx[i].autocorr_values[0] / frame.subframes[ch].lpc_ctx[i].autocorr_values[2];
if (best_window == -1 || best_error > err)
{
best_window = i;
best_error = err;
}
}
return best_window;
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[frame.subframes[ch].best.window];
double err = lpc_ctx.prediction_error[frame.subframes[ch].best.order - 1] / lpc_ctx.autocorr_values[0];
double est = frame.blocksize * (frame.subframes[ch].obits * (1 - err));
double est1 = frame.blocksize * (frame.subframes[ch].obits * (err));
if (est < 0 || est1 < 0) return -1;
}
#endif
return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0;
case WindowMethod.Evaluate2N:
encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 2, true));
return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0;
case WindowMethod.Evaluate3N:
encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 3, true));
return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0;
case WindowMethod.Evaluate:
encode_residual_pass1(frame, ch, -1);
return frame.subframes[ch].best.type == SubframeType.LPC ? frame.subframes[ch].best.window : -1;
return frame.subframes[ch].best.type == SubframeType.LPC ? 1 << frame.subframes[ch].best.window : 0;
case WindowMethod.Search:
return -1;
}
@@ -1453,15 +1898,33 @@ new int[] { // 30
case StereoMethod.Estimate:
for (int ch = 0; ch < subframes; ch++)
{
#if XXX
ulong* fixed_errors = stackalloc ulong[5];
fixed_compute_best_predictor(frame.subframes[ch].samples + 4, (uint)frame.blocksize - 4, fixed_errors);
int best_order = fixed_compute_best_predictor_order(fixed_errors);
//residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
frame.subframes[ch].best.size = (uint)fixed_errors[best_order];
#else
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[0];
lpc_ctx.GetReflection(4, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer);
lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, 4, 4.5, 0.0);
frame.subframes[ch].best.size = (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) + 7.1 * frame.subframes[ch].obits * m_settings.MaxLPCOrder);
int estimate_order = 4;
int iWindow = 0;
fixed (LpcWindowSection* sections = &windowSections[frame.nSeg, iWindow, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, estimate_order,
frame.subframes[ch].samples, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2, sections,
frame.subframes[ch].obits * 2 + BitReader.log2i(frame.blocksize) >= 61);
lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, estimate_order, 4.5, 0.0);
frame.subframes[ch].best.size
= (uint)Math.Max(0, frame.blocksize * (Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1])) + Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5
//= (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0)
//* 2.0 / Math.Log(windowScale[0] / frame.blocksize)
+ 7.1 * frame.subframes[ch].obits * m_settings.MaxLPCOrder);
#endif
}
break;
case StereoMethod.Evaluate:
for (int ch = 0; ch < subframes; ch++)
encode_residual_pass1(frame, ch, 0);
encode_residual_pass1(frame, ch, 1);
break;
case StereoMethod.Search:
for (int ch = 0; ch < subframes; ch++)
@@ -1538,11 +2001,18 @@ new int[] { // 30
int sz = _windowsize;
float* pos1 = window + _windowcount * Flake.MAX_BLOCKSIZE * 2;
float* pos = pos1;
int nSeg = 0;
do
{
windowSections[nSeg, _windowcount, 0].setData(0, sz);
for (int j = 1; j < lpc.MAX_LPC_SECTIONS; j++)
windowSections[nSeg, _windowcount, j].setZero(sz, sz);
fixed (LpcWindowSection* sections = &windowSections[nSeg, _windowcount, 0])
func(pos, sz);
if ((sz & 1) != 0)
break;
nSeg++;
pos += sz;
sz >>= 1;
} while (sz >= 32);
@@ -1550,6 +2020,7 @@ new int[] { // 30
for (int i = 0; i < _windowsize; i++)
scale += pos1[i] * pos1[i];
windowScale[_windowcount] = scale;
windowType[_windowcount] = flag;
_windowcount++;
}
@@ -1569,13 +2040,77 @@ new int[] { // 30
calculate_window(window, lpc.window_flattop, WindowFunction.Flattop);
calculate_window(window, lpc.window_hann, WindowFunction.Hann);
calculate_window(window, lpc.window_bartlett, WindowFunction.Bartlett);
int tukey_parts = 2;
double overlap = -0.3;
double overlap_units = overlap / (1.0 - overlap);
for (int m = 0; m < tukey_parts; m++)
calculate_window(window, (w, wsz) =>
{
lpc.window_punchout_tukey(w, wsz, 0.1,
m / (tukey_parts + overlap_units),
(m + 1 + overlap_units) / (tukey_parts + overlap_units));
}, WindowFunction.PartialTukey);
tukey_parts = 3;
overlap = -0.1;
//overlap = 0.1;
overlap_units = overlap / (1.0 - overlap);
for (int m = 0; m < tukey_parts; m++)
calculate_window(window, (w, wsz) =>
{
lpc.window_punchout_tukey(w, wsz, 0.1,
m / (tukey_parts + overlap_units),
(m + 1 + overlap_units) / (tukey_parts + overlap_units));
}, WindowFunction.PunchoutTukey);
if (_windowcount == 0)
throw new Exception("invalid windowfunction");
int nSeg = 0;
int sz = _windowsize;
float* window_segment = window;
do
{
fixed (LpcWindowSection* sections = &windowSections[nSeg, 0, 0])
LpcWindowSection.Detect(_windowcount, window_segment, Flake.MAX_BLOCKSIZE * 2, sz, sections);
if ((sz & 1) != 0)
break;
window_segment += sz;
nSeg++;
sz >>= 1;
} while (sz >= 32);
#if NONONO
using (TextWriter tx = File.CreateText("C:\\Temp\\w.csv"))
{
int totaltotal = 0;
for (int i = 0; i < _windowcount; i++)
{
int total = 0;
for (int sec = 0; sec < lpc.MAX_LPC_SECTIONS; sec++)
if (windowSections[0, i, sec].m_type != LpcWindowSection.SectionType.Zero || windowSections[0, i, sec].m_start != windowSections[0, i, sec].m_end)
{
tx.WriteLine("{0}\t{1}\t{2}", windowSections[0, i, sec].m_start, windowSections[0, i, sec].m_end, windowSections[0, i, sec].m_type);
if (windowSections[0, i, sec].m_type != LpcWindowSection.SectionType.One)
total += windowSections[0, i, sec].m_end - windowSections[0, i, sec].m_start;
}
totaltotal += total;
tx.WriteLine("{0} total window data", total);
}
tx.WriteLine("{0} grand total window data", totaltotal);
for (int x = 0; x < frame.blocksize; x++)
{
for (int i = 0; i < _windowcount; i++)
{
tx.Write("{0}\t", window[i * Flake.MAX_BLOCKSIZE * 2 + x]);
}
tx.WriteLine();
}
}
#endif
}
if (channels != 2 || frame.blocksize <= 32 || eparams.stereo_method == StereoMethod.Independent)
{
frame.window_buffer = window;
frame.nSeg = 0;
frame.current.residual = r + channels * Flake.MAX_BLOCKSIZE;
frame.ch_mode = channels != 2 ? ChannelMode.NotStereo : ChannelMode.LeftRight;
for (int ch = 0; ch < channels; ch++)
@@ -1589,6 +2124,7 @@ new int[] { // 30
{
//channel_decorrelation(s, s + Flake.MAX_BLOCKSIZE, s + 2 * Flake.MAX_BLOCKSIZE, s + 3 * Flake.MAX_BLOCKSIZE, frame.blocksize);
frame.window_buffer = window;
frame.nSeg = 0;
frame.current.residual = r + 4 * Flake.MAX_BLOCKSIZE;
for (int ch = 0; ch < 4; ch++)
frame.subframes[ch].Init(s + ch * Flake.MAX_BLOCKSIZE, r + ch * Flake.MAX_BLOCKSIZE,
@@ -1610,6 +2146,7 @@ new int[] { // 30
{
frame2.InitSize(frame.blocksize / 2, true);
frame2.window_buffer = frame.window_buffer + frame.blocksize;
frame2.nSeg++;
frame2.current.residual = r + tumbler * 5 * Flake.MAX_BLOCKSIZE;
for (int ch = 0; ch < 4; ch++)
frame2.subframes[ch].Init(frame.subframes[ch].samples, frame2.current.residual + (ch + 1) * frame2.blocksize,
@@ -1621,6 +2158,7 @@ new int[] { // 30
{
frame3.InitSize(frame2.blocksize, true);
frame3.window_buffer = frame2.window_buffer;
frame3.nSeg = frame2.nSeg;
frame3.current.residual = frame2.current.residual + 5 * frame2.blocksize;
for (int ch = 0; ch < 4; ch++)
frame3.subframes[ch].Init(frame2.subframes[ch].samples + frame2.blocksize, frame3.current.residual + (ch + 1) * frame3.blocksize,
@@ -2071,12 +2609,12 @@ new int[] { // 30
public int flake_set_defaults(FlakeWriterSettings settings)
{
// default to level 7 params
window_function = WindowFunction.Flattop | WindowFunction.Tukey;
window_function = WindowFunction.PunchoutTukey | WindowFunction.PartialTukey | WindowFunction.Tukey;
order_method = OrderMethod.Akaike;
stereo_method = StereoMethod.Evaluate;
window_method = WindowMethod.Evaluate;
window_method = WindowMethod.EvaluateN;
block_time_ms = 105;
prediction_type = PredictionType.Search;
prediction_type = PredictionType.Levinson;
estimation_depth = 1;
variable_block_size = 0;
lpc_min_precision_search = 1;
@@ -2088,37 +2626,45 @@ new int[] { // 30
switch (settings.EncoderModeIndex)
{
case 0:
block_time_ms = 53;
prediction_type = PredictionType.Fixed;
stereo_method = StereoMethod.Independent;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.Tukey;
break;
case 1:
prediction_type = PredictionType.Levinson;
prediction_type = PredictionType.Fixed;
stereo_method = StereoMethod.Independent;
window_function = WindowFunction.Bartlett;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.Tukey;
break;
case 2:
stereo_method = StereoMethod.Independent;
window_function = WindowFunction.Bartlett;
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PartialTukey;
break;
case 3:
stereo_method = StereoMethod.Estimate;
window_function = WindowFunction.Bartlett;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PunchoutTukey;
break;
case 4:
stereo_method = StereoMethod.Estimate;
window_function = WindowFunction.Bartlett;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PunchoutTukey;
estimation_depth = 2;
break;
case 5:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PunchoutTukey;
break;
case 6:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.EstimateN;
window_function = WindowFunction.PunchoutTukey | WindowFunction.PartialTukey;
break;
case 7:
break;
case 8:
prediction_type = PredictionType.Search;
estimation_depth = 2;
lpc_min_precision_search = 0;
break;

View File

@@ -6,6 +6,6 @@ namespace CUETools.Codecs.FLAKE
Independent = 0,
Estimate = 1,
Evaluate = 2,
Search = 3
Search = 3,
}
}

View File

@@ -2,11 +2,17 @@
{
public enum WindowFunction
{
None = 0,
Welch = 1,
Tukey = 2,
Hann = 4,
Flattop = 8,
Bartlett = 16,
TukeyFlattop = 10
TukeyFlattop = 10,
PartialTukey = 32,
TukeyPartialTukey = 34,
TukeyFlattopPartialTukey = 42,
PunchoutTukey = 64,
TukeyFlattopPartialTukeyPunchoutTukey = 106,
}
}

View File

@@ -2,8 +2,16 @@
{
public enum WindowMethod
{
Estimate = 0,
Evaluate = 1,
Search = 2
Evaluate,
Search,
Estimate,
Estimate2,
Estimate3,
EstimateN,
Evaluate2,
Evaluate2N,
Evaluate3,
Evaluate3N,
EvaluateN,
}
}

View File

@@ -73,6 +73,19 @@ namespace CUETools.Codecs
}
}
public bool HasDefaultValuesForMode(int index)
{
bool res = true;
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
foreach (var attribute in property.Attributes)
if (attribute is DefaultValueForModeAttribute)
{
var defaultValueForMode = attribute as DefaultValueForModeAttribute;
res &= (int)property.GetValue(this) == defaultValueForMode.m_values[index];
}
return res;
}
[Browsable(false)]
[XmlIgnore]
public AudioPCMConfig PCM

View File

@@ -5,8 +5,9 @@ namespace CUETools.Codecs
public class lpc
{
public const int MAX_LPC_ORDER = 32;
public const int MAX_LPC_WINDOWS = 2;
public const int MAX_LPC_WINDOWS = 8;
public const int MAX_LPC_PRECISIONS = 4;
public const int MAX_LPC_SECTIONS = 32;
public unsafe static void window_welch(float* window, int L)
{
@@ -48,17 +49,47 @@ namespace CUETools.Codecs
public unsafe static void window_tukey(float* window, int L)
{
window_rectangle(window, L);
double p = 0.5;
int Np = (int)(p / 2.0 * L) - 1;
int z = 0;
int Np = (int)(p / 2.0 * L) - z;
if (Np > 0)
{
for (int n = 0; n <= Np; n++)
{
window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * n / Np));
window[L - Np - 1 + n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * (n + Np) / Np));
for (int n = 0; n < z; n++)
window[n] = window[L - n - 1] = 0;
for (int n = 0; n < Np - 1; n++)
window[n + z] = window[L - n - 1 - z] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * (n + 1) / Np));
for (int n = z + Np - 1; n < L - z - Np + 1; n++)
window[n] = 1.0F;
}
}
public unsafe static void window_punchout_tukey(float* window, int L, double p, double start, double end)
{
int start_n = (int)(start * L);
int end_n = (int)(end * L);
int Np = (int)(p / 2.0 * L);
int i, n = 0;
if (start_n != 0)
{
for (i = 1; n < Np; n++, i++)
window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np));
for (; n < start_n - Np; n++)
window[n] = 1.0f;
for (i = Np; n < start_n; n++, i--)
window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np));
}
for (; n < end_n; n++)
window[n] = 0.0f;
if (end_n != L)
{
for (i = 1; n < end_n + Np; n++, i++)
window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np));
for (; n < L - Np; n++)
window[n] = 1.0f;
for (i = Np; n < L; n++, i--)
window[n] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * i / Np));
}
}
public unsafe static void window_hann(float* window, int L)
@@ -73,6 +104,7 @@ namespace CUETools.Codecs
return (short)((val >> 31) + ((val - 1) >> 31) + 1);
}
#if XXX
static public unsafe void
compute_corr_int(/*const*/ short* data1, short* data2, int len, int min, int lag, int* autoc)
{
@@ -92,13 +124,14 @@ namespace CUETools.Codecs
autoc[i] = temp + temp2;
}
}
#endif
/**
* Calculates autocorrelation data from audio samples
* A window function is applied before calculation.
*/
static public unsafe void
compute_autocorr(/*const*/ int* data, int len, int min, int lag, double* autoc, float* window)
compute_autocorr(/*const*/ int* data, float* window, int len, int min, int lag, double* autoc, int prev, int next)
{
#if FPAC
short* data1 = stackalloc short[len + 1];
@@ -125,29 +158,223 @@ namespace CUETools.Codecs
for (int coeff = min; coeff <= lag; coeff++)
autoc[coeff] = (c1[coeff] * (double)(1 << 18) + (c2[coeff] + c3[coeff]) * (double)(1 << 9) + c4[coeff]);
#else
double* data1 = stackalloc double[(int)len + 16];
#if XXX
if (min == 0 && lag >= 4)
{
int* pdata = data;
float* pwindow = window;
double temp0 = 1.0;
double temp1 = 1.0;
double temp2 = 1.0;
double temp3 = 1.0;
double temp4 = 1.0;
double c0 = *(pdata++) * *(pwindow++);
float c1 = *(pdata++) * *(pwindow++);
float c2 = *(pdata++) * *(pwindow++);
float c3 = *(pdata++) * *(pwindow++);
float c4 = *(pdata++) * *(pwindow++);
int* finish = data + len;
while (pdata <= finish)
{
temp0 += c0 * c0;
temp1 += c0 * c1;
temp2 += c0 * c2;
temp3 += c0 * c3;
temp4 += c0 * c4;
c0 = c1;
c1 = c2;
c2 = c3;
c3 = c4;
c4 = *(pdata++) * *(pwindow++);
}
temp0 += c0 * c0;
temp1 += c0 * c1;
temp2 += c0 * c2;
temp3 += c0 * c3;
c0 = c1;
c1 = c2;
c2 = c3;
temp0 += c0 * c0;
temp1 += c0 * c1;
temp2 += c0 * c2;
c0 = c1;
c1 = c2;
temp0 += c0 * c0;
temp1 += c0 * c1;
c0 = c1;
temp0 += c0 * c0;
autoc[0] += temp0;
autoc[1] += temp1;
autoc[2] += temp2;
autoc[3] += temp3;
autoc[4] += temp4;
min = 5;
if (lag < min) return;
}
#endif
double* data1 = stackalloc double[lag + len + lag];
int i;
for (i = 0; i < lag; i++)
data1[i] = prev != 0 ? data[i - lag] : 0;
for (i = 0; i < len; i++)
data1[i] = data[i] * window[i];
data1[len] = 0;
data1[lag + i] = data[i] * window[i];
for (i = 0; i < lag; i++)
data1[lag + len + i] = next != 0 ? data[len + i] : 0;
for (i = min; i <= lag; ++i)
{
double temp = 1.0;
double temp2 = 1.0;
double* finish = data1 + len - i;
double temp = 0;
double temp2 = 0;
double* pdata = data1 + lag - i;
double* finish = data1 + lag + len - 1;
for (double* pdata = data1; pdata < finish; pdata += 2)
while (pdata < finish)
{
temp += pdata[i] * pdata[0];
temp2 += pdata[i + 1] * pdata[1];
temp += pdata[i] * (*pdata++);
temp2 += pdata[i] * (*pdata++);
}
autoc[i] = temp + temp2;
if (pdata <= finish)
temp += pdata[i] * (*pdata++);
autoc[i] += temp + temp2;
}
#endif
}
static public unsafe void
compute_autocorr_windowless(/*const*/ int* data, int len, int min, int lag, double* autoc)
{
// if databits*2 + log2(len) <= 64
#if !XXX
#if XXX
if (min == 0 && lag >= 4)
{
long temp0 = 0;
long temp1 = 0;
long temp2 = 0;
long temp3 = 0;
long temp4 = 0;
int* pdata = data;
int* finish = data + len - 4;
while (pdata < finish)
{
long c0 = *(pdata++);
temp0 += c0 * c0;
temp1 += c0 * pdata[0];
temp2 += c0 * pdata[1];
temp3 += c0 * pdata[2];
temp4 += c0 * pdata[3];
}
{
long c0 = *(pdata++);
temp0 += c0 * c0;
temp1 += c0 * pdata[0];
temp2 += c0 * pdata[1];
temp3 += c0 * pdata[2];
}
{
long c0 = *(pdata++);
temp0 += c0 * c0;
temp1 += c0 * pdata[0];
temp2 += c0 * pdata[1];
}
{
long c0 = *(pdata++);
temp0 += c0 * c0;
temp1 += c0 * pdata[0];
}
{
long c0 = *(pdata++);
temp0 += c0 * c0;
}
autoc[0] += temp0;
autoc[1] += temp1;
autoc[2] += temp2;
autoc[3] += temp3;
autoc[4] += temp4;
min = 5;
if (lag < min) return;
}
#endif
for (int i = min; i <= lag; ++i)
{
long temp = 0;
long temp2 = 0;
int* pdata = data;
int* finish = data + len - i - 1;
while (pdata < finish)
{
temp += (long)pdata[i] * (*pdata++);
temp2 += (long)pdata[i] * (*pdata++);
}
if (pdata <= finish)
temp += (long)pdata[i] * (*pdata++);
autoc[i] += temp + temp2;
}
#else
for (int i = min; i <= lag; ++i)
{
double temp = 0;
double temp2 = 0;
int* pdata = data;
int* finish = data + len - i - 1;
while (pdata < finish)
{
temp += (double)pdata[i] * (double)(*pdata++);
temp2 += (double)pdata[i] * (double)(*pdata++);
}
if (pdata <= finish)
temp += (double)pdata[i] * (double)(*pdata++);
autoc[i] += temp + temp2;
}
#endif
}
static public unsafe void
compute_autocorr_windowless_large(/*const*/ int* data, int len, int min, int lag, double* autoc)
{
for (int i = min; i <= lag; ++i)
{
double temp = 0;
double temp2 = 0;
int* pdata = data;
int* finish = data + len - i - 1;
while (pdata < finish)
{
temp += (long)pdata[i] * (*pdata++);
temp2 += (long)pdata[i] * (*pdata++);
}
if (pdata <= finish)
temp += (long)pdata[i] * (*pdata++);
autoc[i] += temp + temp2;
}
}
static public unsafe void
compute_autocorr_glue(/*const*/ int* data, int min, int lag, double* autoc)
{
for (int i = min; i <= lag; ++i)
{
long temp = 0;
int* pdata = data - i;
int* finish = data;
while (pdata < finish)
temp += (long)pdata[i] * (*pdata++);
autoc[i] += temp;
}
}
/**
* Levinson-Durbin recursion.
* Produces LPC coefficients from autocorrelation data.

View File

@@ -1,7 +1,173 @@
using System;
using System.Collections.Generic;
namespace CUETools.Codecs
{
unsafe public class LpcSubframeInfo
{
public LpcSubframeInfo()
{
autocorr_section_values = new double[lpc.MAX_LPC_SECTIONS, lpc.MAX_LPC_ORDER + 1];
autocorr_section_orders = new int[lpc.MAX_LPC_SECTIONS];
}
// public LpcContext[] lpc_ctx;
public double[,] autocorr_section_values;
public int[] autocorr_section_orders;
//public int obits;
public void Reset()
{
for (int sec = 0; sec < autocorr_section_orders.Length; sec++)
autocorr_section_orders[sec] = 0;
}
}
unsafe public struct LpcWindowSection
{
public enum SectionType
{
Zero,
One,
Data,
Glue
};
public int m_start;
public int m_end;
public SectionType m_type;
public int m_id;
public LpcWindowSection(int end)
{
m_id = -1;
m_start = 0;
m_end = end;
m_type = SectionType.Data;
}
public void setData(int start, int end)
{
m_id = -1;
m_start = start;
m_end = end;
m_type = SectionType.Data;
}
public void setOne(int start, int end)
{
m_id = -1;
m_start = start;
m_end = end;
m_type = SectionType.One;
}
public void setGlue(int start)
{
m_id = -1;
m_start = start;
m_end = start;
m_type = SectionType.Glue;
}
public void setZero(int start, int end)
{
m_id = -1;
m_start = start;
m_end = end;
m_type = SectionType.Zero;
}
unsafe public static void Detect(int _windowcount, float* window_segment, int stride, int sz, LpcWindowSection* sections)
{
int section_id = 0;
var boundaries = new List<int>();
var types = new LpcWindowSection.SectionType[_windowcount, lpc.MAX_LPC_SECTIONS * 2];
for (int x = 0; x < sz; x++)
{
for (int i = 0; i < _windowcount; i++)
{
float w = window_segment[i * stride + x];
types[i, boundaries.Count] =
boundaries.Count >= lpc.MAX_LPC_SECTIONS * 2 - 2 ?
LpcWindowSection.SectionType.Data : w == 0.0 ?
LpcWindowSection.SectionType.Zero : w == 1.0 ?
LpcWindowSection.SectionType.One :
LpcWindowSection.SectionType.Data;
}
bool isBoundary = false;
for (int i = 0; i < _windowcount; i++)
{
isBoundary |= boundaries.Count == 0 ||
types[i, boundaries.Count - 1] != types[i, boundaries.Count];
}
if (isBoundary) boundaries.Add(x);
}
boundaries.Add(sz);
var ones = new int[boundaries.Count - 1];
// Reconstruct segments list.
for (int i = 0; i < _windowcount; i++)
{
int secs = 0;
for (int j = 0; j < boundaries.Count - 1; j++)
{
if (types[i, j] == LpcWindowSection.SectionType.Zero)
{
if (secs > 0 && sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_end == boundaries[j] && sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_type == LpcWindowSection.SectionType.Zero)
{
sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_end = boundaries[j + 1];
continue;
}
sections[i * lpc.MAX_LPC_SECTIONS + secs++].setZero(boundaries[j], boundaries[j + 1]);
continue;
}
if (types[i, j] == LpcWindowSection.SectionType.Data
|| secs + 1 >= lpc.MAX_LPC_SECTIONS
|| (boundaries[j + 1] - boundaries[j] < lpc.MAX_LPC_ORDER))
{
if (secs > 0 && sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_end == boundaries[j] && sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_type == LpcWindowSection.SectionType.Data)
{
sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_end = boundaries[j + 1];
continue;
}
sections[i * lpc.MAX_LPC_SECTIONS + secs++].setData(boundaries[j], boundaries[j + 1]);
continue;
}
if (secs > 0 && sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_end == boundaries[j] && sections[i * lpc.MAX_LPC_SECTIONS + secs - 1].m_type == LpcWindowSection.SectionType.One)
sections[i * lpc.MAX_LPC_SECTIONS + secs++].setGlue(boundaries[j]);
sections[i * lpc.MAX_LPC_SECTIONS + secs++].setOne(boundaries[j], boundaries[j + 1]);
ones[j] |= 1 << i;
}
while (secs < lpc.MAX_LPC_SECTIONS)
sections[i * lpc.MAX_LPC_SECTIONS + secs++].setZero(sz, sz);
}
for (int j = 0; j < boundaries.Count - 1; j++)
{
if (j > 0 && ones[j - 1] == ones[j])
{
for (int i = 0; i < _windowcount; i++)
{
for (int sec = 0; sec < lpc.MAX_LPC_SECTIONS; sec++)
if (sections[i * lpc.MAX_LPC_SECTIONS + sec].m_type == LpcWindowSection.SectionType.Glue &&
sections[i * lpc.MAX_LPC_SECTIONS + sec].m_start == boundaries[j])
{
sections[i * lpc.MAX_LPC_SECTIONS + sec - 1].m_end = sections[i * lpc.MAX_LPC_SECTIONS + sec + 1].m_end;
for (int sec1 = sec; sec1 + 2 < lpc.MAX_LPC_SECTIONS; sec1++)
sections[i * lpc.MAX_LPC_SECTIONS + sec1] = sections[i * lpc.MAX_LPC_SECTIONS + sec1 + 2];
}
}
continue;
}
if ((ones[j] & (ones[j] - 1)) != 0 && section_id < lpc.MAX_LPC_SECTIONS)
{
for (int i = 0; i < _windowcount; i++)
for (int sec = 0; sec < lpc.MAX_LPC_SECTIONS; sec++)
if (sections[i * lpc.MAX_LPC_SECTIONS + sec].m_type == LpcWindowSection.SectionType.One &&
sections[i * lpc.MAX_LPC_SECTIONS + sec].m_start == boundaries[j])
{
sections[i * lpc.MAX_LPC_SECTIONS + sec].m_id = section_id;
}
section_id++;
}
}
}
}
/// <summary>
/// Context for LPC coefficients calculation and order estimation
/// </summary>
@@ -36,18 +202,62 @@ namespace CUETools.Codecs
/// <param name="samples">Samples pointer</param>
/// <param name="blocksize">Block size</param>
/// <param name="window">Window function</param>
public void GetReflection(int order, int* samples, int blocksize, float* window)
public void GetReflection(LpcSubframeInfo subframe, int order, int* samples, float* window, LpcWindowSection* sections, bool large)
{
if (autocorr_order > order)
return;
fixed (double* reff = reflection_coeffs, autoc = autocorr_values, err = prediction_error)
{
lpc.compute_autocorr(samples, blocksize, autocorr_order, order, autoc, window);
for (int i = autocorr_order; i <= order; i++) autoc[i] = 0;
int prev = 0;
for (int section = 0; section < lpc.MAX_LPC_SECTIONS; section++)
{
if (sections[section].m_type == LpcWindowSection.SectionType.Zero)
{
prev = 0;
continue;
}
if (sections[section].m_type == LpcWindowSection.SectionType.Data)
{
int next = section + 1 < lpc.MAX_LPC_SECTIONS && sections[section + 1].m_type == LpcWindowSection.SectionType.One ? 1 : 0;
lpc.compute_autocorr(samples + sections[section].m_start, window + sections[section].m_start, sections[section].m_end - sections[section].m_start, autocorr_order, order, autoc, prev, next);
}
else if (sections[section].m_type == LpcWindowSection.SectionType.Glue)
lpc.compute_autocorr_glue(samples + sections[section].m_start, autocorr_order, order, autoc);
else if (sections[section].m_type == LpcWindowSection.SectionType.One)
{
if (sections[section].m_id >= 0)
{
if (subframe.autocorr_section_orders[sections[section].m_id] <= order)
{
fixed (double* autocsec = &subframe.autocorr_section_values[sections[section].m_id, 0])
{
for (int i = subframe.autocorr_section_orders[sections[section].m_id]; i <= order; i++) autocsec[i] = 0;
if (large)
lpc.compute_autocorr_windowless_large(samples + sections[section].m_start, sections[section].m_end - sections[section].m_start, subframe.autocorr_section_orders[sections[section].m_id], order, autocsec);
else
lpc.compute_autocorr_windowless(samples + sections[section].m_start, sections[section].m_end - sections[section].m_start, subframe.autocorr_section_orders[sections[section].m_id], order, autocsec);
}
subframe.autocorr_section_orders[sections[section].m_id] = order + 1;
}
for (int i = autocorr_order; i <= order; i++)
autoc[i] += subframe.autocorr_section_values[sections[section].m_id, i];
}
else
{
if (large)
lpc.compute_autocorr_windowless_large(samples + sections[section].m_start, sections[section].m_end - sections[section].m_start, autocorr_order, order, autoc);
else
lpc.compute_autocorr_windowless(samples + sections[section].m_start, sections[section].m_end - sections[section].m_start, autocorr_order, order, autoc);
}
prev = 1;
}
}
lpc.compute_schur_reflection(autoc, (uint)order, reff, err);
autocorr_order = order + 1;
}
}
#if XXX
public void GetReflection1(int order, int* samples, int blocksize, float* window)
{
if (autocorr_order > order)
@@ -83,11 +293,12 @@ namespace CUETools.Codecs
autocorr_order = order + 1;
}
}
#endif
public double Akaike(int blocksize, int order, double alpha, double beta)
{
//return (blocksize - order) * (Math.Log(prediction_error[order - 1]) - Math.Log(1.0)) + Math.Log(blocksize) * order * (alpha + beta * order);
return blocksize * Math.Log(prediction_error[order - 1]) + Math.Log(blocksize) * order * (alpha + beta * order);
//return blocksize * (Math.Log(prediction_error[order - 1]) - Math.Log(autocorr_values[0]) / 2) + Math.Log(blocksize) * order * (alpha + beta * order);
return blocksize * (Math.Log(prediction_error[order - 1])) + Math.Log(blocksize) * order * (alpha + beta * order);
}
/// <summary>

View File

@@ -475,25 +475,45 @@ namespace CUETools.FlakeExe
if (debug)
{
settings = flake.Settings as FlakeWriterSettings;
Console.SetOut(stdout);
Console.Out.WriteLine("{0}\t{1:0.00}\t{2}\t{3}\t{4}\t{5}\t{6}..{7}\t{8}..{9}\t{10}..{11}\t{12}..{13}\t{14}\t{15}\t{16}",
Console.Out.WriteLine("{17}\t{0}\t{1:0.00}\t{2}\t{3}\t{4}\t{5}\t{6}..{7}\t{8}..{9}\t{10}..{11}\t{12}..{13}\t{14}\t{15}\t{16}\t{18}",
flake.TotalSize,
flake.UserProcessorTime.TotalSeconds > 0 ? flake.UserProcessorTime.TotalSeconds : totalElapsed.TotalSeconds,
flake.PredictionType.ToString().PadRight(15),
flake.StereoMethod.ToString().PadRight(15),
(flake.OrderMethod.ToString() + "(" + flake.EstimationDepth.ToString() + ")").PadRight(15),
flake.WindowFunction,
(flake.Settings as FlakeWriterSettings).MinPartitionOrder,
(flake.Settings as FlakeWriterSettings).MaxPartitionOrder,
(flake.Settings as FlakeWriterSettings).MinLPCOrder,
(flake.Settings as FlakeWriterSettings).MaxLPCOrder,
(flake.Settings as FlakeWriterSettings).MinFixedOrder,
(flake.Settings as FlakeWriterSettings).MaxFixedOrder,
(flake.WindowMethod.ToString().PadRight(10) + "(" +
((flake.WindowFunction & WindowFunction.Tukey) != 0 ? "T" : " ") +
((flake.WindowFunction & WindowFunction.PartialTukey) != 0 ? "P" : " ") +
(((flake.WindowFunction & WindowFunction.PunchoutTukey) != 0 ? "O" : "") +
((flake.WindowFunction & WindowFunction.Welch) == 0 ? "" : "W") +
((flake.WindowFunction & WindowFunction.Hann) == 0 ? "" : "H") +
((flake.WindowFunction & WindowFunction.Flattop) == 0 ? "" : "F") +
((flake.WindowFunction & WindowFunction.Bartlett) == 0 ? "" : "B")).PadRight(1))
+")",
settings.MinPartitionOrder,
settings.MaxPartitionOrder,
settings.MinLPCOrder,
settings.MaxLPCOrder,
settings.MinFixedOrder,
settings.MaxFixedOrder,
flake.MinPrecisionSearch,
flake.MaxPrecisionSearch,
flake.Settings.BlockSize,
flake.VBRMode,
coeffs ?? ""
coeffs ?? "",
audioSource.Position * audioSource.PCM.BlockAlign,
(flake.PredictionType == PredictionType.Search && flake.StereoMethod == StereoMethod.Evaluate && flake.WindowMethod == WindowMethod.EvaluateN && flake.WindowFunction == (WindowFunction.PunchoutTukey | WindowFunction.PartialTukey | WindowFunction.Tukey) && flake.EstimationDepth == 2 && flake.MinPrecisionSearch == 0 && settings.HasDefaultValuesForMode(8)) ? "8" :
(flake.PredictionType == PredictionType.Levinson && flake.StereoMethod == StereoMethod.Evaluate && flake.WindowMethod == WindowMethod.EvaluateN && flake.WindowFunction == (WindowFunction.PunchoutTukey | WindowFunction.PartialTukey | WindowFunction.Tukey) && flake.EstimationDepth == 1 && flake.MinPrecisionSearch == 1 && settings.HasDefaultValuesForMode(7)) ? "7" :
(flake.PredictionType == PredictionType.Levinson && flake.StereoMethod == StereoMethod.Evaluate && flake.WindowMethod == WindowMethod.EstimateN && flake.WindowFunction == (WindowFunction.PunchoutTukey | WindowFunction.PartialTukey) && flake.EstimationDepth == 1 && flake.MinPrecisionSearch == 1 && settings.HasDefaultValuesForMode(6)) ? "6" :
(flake.PredictionType == PredictionType.Levinson && flake.StereoMethod == StereoMethod.Evaluate && flake.WindowMethod == WindowMethod.Estimate && flake.WindowFunction == WindowFunction.PunchoutTukey && flake.EstimationDepth == 1 && flake.MinPrecisionSearch == 1 && settings.HasDefaultValuesForMode(5)) ? "5" :
(flake.PredictionType == PredictionType.Levinson && flake.StereoMethod == StereoMethod.Estimate && flake.WindowMethod == WindowMethod.Estimate && flake.WindowFunction == WindowFunction.PunchoutTukey && flake.EstimationDepth == 2 && flake.MinPrecisionSearch == 1 && settings.HasDefaultValuesForMode(4)) ? "4" :
(flake.PredictionType == PredictionType.Levinson && flake.StereoMethod == StereoMethod.Estimate && flake.WindowMethod == WindowMethod.Estimate && flake.WindowFunction == WindowFunction.PunchoutTukey && flake.EstimationDepth == 1 && flake.MinPrecisionSearch == 1 && settings.HasDefaultValuesForMode(3)) ? "3" :
(flake.PredictionType == PredictionType.Levinson && flake.StereoMethod == StereoMethod.Estimate && flake.WindowMethod == WindowMethod.Estimate && flake.WindowFunction == WindowFunction.PartialTukey && flake.EstimationDepth == 1 && flake.MinPrecisionSearch == 1 && settings.HasDefaultValuesForMode(2)) ? "2" :
(flake.PredictionType == PredictionType.Fixed && flake.StereoMethod == StereoMethod.Independent && flake.WindowMethod == WindowMethod.Estimate && flake.MinPrecisionSearch == 1 && flake.WindowFunction == WindowFunction.Tukey && settings.HasDefaultValuesForMode(1)) ? "1" :
(flake.PredictionType == PredictionType.Fixed && flake.StereoMethod == StereoMethod.Independent && flake.WindowMethod == WindowMethod.Estimate && flake.MinPrecisionSearch == 1 && flake.WindowFunction == WindowFunction.Tukey && settings.HasDefaultValuesForMode(0)) ? "0" :
"?"
);
}
#endif