Flake: slight optimisation for new window functions (partial_tukey, punchout_tukey).

This commit is contained in:
Grigory Chudov
2014-09-15 00:48:31 -04:00
parent 4dc1169c41
commit 98189de625
7 changed files with 310 additions and 197 deletions

View File

@@ -91,6 +91,7 @@ namespace CUETools.Codecs.ALAC
int[] verifyBuffer;
int[] residualBuffer;
float[] windowBuffer;
WindowFunction[] windowType;
LpcWindowSection[,] windowSections;
int samplesInBuffer = 0;
@@ -124,6 +125,7 @@ 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 * lpc.MAX_LPC_WINDOWS];
windowType = new WindowFunction[lpc.MAX_LPC_WINDOWS];
windowSections = new LpcWindowSection[lpc.MAX_LPC_WINDOWS, lpc.MAX_LPC_SECTIONS];
eparams.set_defaults(m_settings.EncoderModeIndex);
@@ -836,7 +838,7 @@ namespace CUETools.Codecs.ALAC
}
}
unsafe void encode_residual(ALACFrame frame, int ch, int pass, int best_window)
unsafe void encode_residual(ALACFrame frame, int ch, int pass, int best_windows)
{
int* smp = frame.subframes[ch].samples;
int i, n = frame.blocksize;
@@ -872,16 +874,15 @@ namespace CUETools.Codecs.ALAC
for (int iWindow = 0; iWindow < _windowcount; iWindow++)
{
if (best_window != -1 && iWindow != best_window)
if (0 == (best_windows & (1 << iWindow)))
continue;
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
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);
frame.subframes[ch].sf, max_order, frame.blocksize, smp,
frame.window_buffer + iWindow * Alac.MAX_BLOCKSIZE * 2, sections);
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++)
@@ -921,7 +922,7 @@ namespace CUETools.Codecs.ALAC
bitwriter.flush();
}
unsafe void encode_residual_pass1(ALACFrame frame, int ch, int best_window)
unsafe void encode_residual_pass1(ALACFrame frame, int ch, int best_windows)
{
int max_prediction_order = eparams.max_prediction_order;
int estimation_depth = eparams.estimation_depth;
@@ -931,7 +932,7 @@ namespace CUETools.Codecs.ALAC
eparams.estimation_depth = 1;
eparams.min_modifier = eparams.max_modifier;
eparams.adaptive_passes = 0;
encode_residual(frame, ch, 1, best_window);
encode_residual(frame, ch, 1, best_windows);
eparams.max_prediction_order = max_prediction_order;
eparams.estimation_depth = estimation_depth;
eparams.min_modifier = min_modifier;
@@ -943,25 +944,29 @@ namespace CUETools.Codecs.ALAC
encode_residual(frame, ch, 2, estimate_best_window(frame, ch));
}
unsafe int estimate_best_window(ALACFrame frame, int ch)
unsafe int estimate_best_windows_akaike(ALACFrame frame, int ch, int count, bool onePerType)
{
if (_windowcount == 1)
return 0;
switch (eparams.window_method)
int* windows_present = stackalloc int[_windowcount];
for (int i = 0; i < _windowcount; i++)
windows_present[i] = 0;
if (onePerType)
{
case WindowMethod.Estimate:
{
int order = 4;
for (int i = 0; i < _windowcount; i++)
for (int j = 0; j < _windowcount; j++)
if (windowType[j] == windowType[i])
windows_present[j]++;
}
int order = Math.Min(4, eparams.max_prediction_order);
float* err = stackalloc float[lpc.MAX_LPC_ORDER];
for (int i = 0; i < _windowcount; i++)
{
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].sf, order, frame.blocksize,
frame.subframes[ch].samples,
frame.window_buffer + i * Alac.MAX_BLOCKSIZE * 2, sections,
Settings.PCM.BitsPerSample * 2 + BitReader.log2i(frame.blocksize) >= 61);
frame.window_buffer + i * Alac.MAX_BLOCKSIZE * 2, sections);
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);
}
@@ -980,11 +985,48 @@ namespace CUETools.Codecs.ALAC
}
}
}
return best_windows[0];
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_window(ALACFrame frame, int ch)
{
if (_windowcount == 1)
return 1;
switch (eparams.window_method)
{
case WindowMethod.Estimate:
return estimate_best_windows_akaike(frame, ch, 1, false);
case WindowMethod.EstimateN:
return estimate_best_windows_akaike(frame, ch, 1, true);
case WindowMethod.EvaluateN:
encode_residual_pass1(frame, ch, estimate_best_windows_akaike(frame, ch, 1, true));
return 1 << frame.subframes[ch].best.window;
case WindowMethod.Evaluate:
encode_residual_pass1(frame, ch, -1);
return frame.subframes[ch].best.window;
return 1 << frame.subframes[ch].best.window;
case WindowMethod.Search:
return -1;
}
@@ -1006,17 +1048,16 @@ namespace CUETools.Codecs.ALAC
double alpha = 1.5; // 4.5 + eparams.max_prediction_order / 10.0;
fixed (LpcWindowSection* sections = &windowSections[iWindow, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, stereo_order,
frame.subframes[ch].sf, stereo_order, frame.blocksize,
frame.subframes[ch].samples,
frame.window_buffer + iWindow * Alac.MAX_BLOCKSIZE * 2, sections,
Settings.PCM.BitsPerSample * 2 + BitReader.log2i(frame.blocksize) >= 61);
frame.window_buffer + iWindow * Alac.MAX_BLOCKSIZE * 2, sections);
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));
}
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++)
@@ -1104,6 +1145,7 @@ namespace CUETools.Codecs.ALAC
pos += sz;
sz >>= 1;
} while (sz >= 32);
windowType[_windowcount] = flag;
_windowcount++;
}
@@ -1148,7 +1190,7 @@ namespace CUETools.Codecs.ALAC
if (_windowcount == 0)
throw new Exception("invalid windowfunction");
fixed (LpcWindowSection* sections = &windowSections[0, 0])
LpcWindowSection.Detect(_windowcount, window, Alac.MAX_BLOCKSIZE * 2, _windowsize, sections);
LpcWindowSection.Detect(_windowcount, window, Alac.MAX_BLOCKSIZE * 2, _windowsize, Settings.PCM.BitsPerSample, sections);
}
frame.window_buffer = window;
@@ -1809,10 +1851,10 @@ namespace CUETools.Codecs.ALAC
}
// default to level 5 params
window_function = WindowFunction.Flattop | WindowFunction.Tukey;
window_function = WindowFunction.PartialTukey | WindowFunction.PunchoutTukey;
order_method = OrderMethod.Estimate;
stereo_method = StereoMethod.Evaluate;
window_method = WindowMethod.Evaluate;
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
block_time_ms = 105;
min_modifier = 4;
max_modifier = 4;
@@ -1828,53 +1870,50 @@ namespace CUETools.Codecs.ALAC
{
case 0:
stereo_method = StereoMethod.Independent;
window_function = WindowFunction.Hann;
max_prediction_order = 6;
break;
case 1:
stereo_method = StereoMethod.Independent;
window_function = WindowFunction.Hann;
max_prediction_order = 8;
break;
case 2:
stereo_method = StereoMethod.Estimate;
window_function = WindowFunction.Hann;
max_prediction_order = 6;
break;
case 3:
stereo_method = StereoMethod.Estimate;
window_function = WindowFunction.Hann;
window_function = WindowFunction.PartialTukey;
max_prediction_order = 8;
break;
case 4:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PartialTukey | WindowFunction.PunchoutTukey;
window_function = WindowFunction.PunchoutTukey;
max_prediction_order = 8;
break;
case 5:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
window_function = WindowFunction.PartialTukey | WindowFunction.PunchoutTukey;
window_function = WindowFunction.PunchoutTukey;
break;
case 6:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.EvaluateN;
break;
case 7:
stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.EvaluateN;
adaptive_passes = 1;
min_modifier = 2;
break;
case 8:
stereo_method = StereoMethod.Evaluate;
window_method = WindowMethod.EvaluateN;
adaptive_passes = 1;
min_modifier = 2;
break;
case 9:
stereo_method = StereoMethod.Evaluate;
window_method = WindowMethod.EvaluateN;
adaptive_passes = 1;
max_prediction_order = 30;
min_modifier = 2;
break;
case 10:
stereo_method = StereoMethod.Evaluate;
window_method = WindowMethod.EvaluateN;
estimation_depth = 2;
adaptive_passes = 2;
max_prediction_order = 30;

View File

@@ -4,6 +4,8 @@
{
Estimate = 0,
Evaluate = 1,
Search = 2
Search = 2,
EstimateN = 3,
EvaluateN = 4,
}
}

View File

@@ -1464,8 +1464,8 @@ new int[] { // 30
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
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);
frame.subframes[ch].sf, max_order, frame.blocksize,
smp, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2, sections);
lpc_ctx.ComputeLPC(lpcs);
//int frameSize = n;
@@ -1777,9 +1777,8 @@ new int[] { // 30
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);
frame.subframes[ch].sf, estimate_order, frame.blocksize,
frame.subframes[ch].samples, frame.window_buffer + i * Flake.MAX_BLOCKSIZE * 2, sections);
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);
@@ -1898,34 +1897,62 @@ 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];
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);
frame.subframes[ch].sf, estimate_order, frame.blocksize,
frame.subframes[ch].samples, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2, sections);
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);
}
break;
#if XXX
case StereoMethod.EstimateFixed:
for (int ch = 0; ch < subframes; ch++)
{
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];
}
break;
#endif
case StereoMethod.EstimateX:
for (int ch = 0; ch < subframes; ch++)
for (int iWindow = 0; iWindow < _windowcount; iWindow++)
{
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
int estimate_order = 4;
fixed (LpcWindowSection* sections = &windowSections[frame.nSeg, iWindow, 0])
lpc_ctx.GetReflection(
frame.subframes[ch].sf, estimate_order, frame.blocksize,
frame.subframes[ch].samples, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2, sections);
lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, estimate_order, 4.5, 0.0);
uint estimate
= (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);
if (iWindow == 0 || frame.subframes[ch].best.size > estimate)
frame.subframes[ch].best.size = estimate;
}
break;
case StereoMethod.Evaluate:
for (int ch = 0; ch < subframes; ch++)
encode_residual_pass1(frame, ch, 1);
break;
case StereoMethod.EvaluateX:
for (int ch = 0; ch < subframes; ch++)
encode_residual_pass1(frame, ch,
estimate_best_windows_akaike(frame, ch, 1, false));
break;
case StereoMethod.Search:
for (int ch = 0; ch < subframes; ch++)
encode_residual_pass2(frame, ch);
@@ -1977,6 +2004,7 @@ new int[] { // 30
switch (eparams.stereo_method)
{
case StereoMethod.Estimate:
case StereoMethod.EstimateX:
for (int ch = 0; ch < channels; ch++)
{
frame.subframes[ch].best.size = AudioSamples.UINT32_MAX;
@@ -1984,6 +2012,7 @@ new int[] { // 30
}
break;
case StereoMethod.Evaluate:
case StereoMethod.EvaluateX:
for (int ch = 0; ch < channels; ch++)
encode_residual_pass2(frame, ch);
break;
@@ -2070,7 +2099,7 @@ new int[] { // 30
do
{
fixed (LpcWindowSection* sections = &windowSections[nSeg, 0, 0])
LpcWindowSection.Detect(_windowcount, window_segment, Flake.MAX_BLOCKSIZE * 2, sz, sections);
LpcWindowSection.Detect(_windowcount, window_segment, Flake.MAX_BLOCKSIZE * 2, sz, Settings.PCM.BitsPerSample, sections);
if ((sz & 1) != 0)
break;
window_segment += sz;
@@ -2087,7 +2116,7 @@ new int[] { // 30
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);
tx.WriteLine("{0}\t{1}\t{2}\t{3}", windowSections[0, i, sec].m_start, windowSections[0, i, sec].m_end, windowSections[0, i, sec].m_type, windowSections[0, i, sec].m_id);
if (windowSections[0, i, sec].m_type != LpcWindowSection.SectionType.One)
total += windowSections[0, i, sec].m_end - windowSections[0, i, sec].m_start;
}

View File

@@ -7,5 +7,7 @@ namespace CUETools.Codecs.FLAKE
Estimate = 1,
Evaluate = 2,
Search = 3,
EstimateX = 4,
EvaluateX = 5,
}
}

View File

@@ -131,7 +131,7 @@ namespace CUETools.Codecs
* A window function is applied before calculation.
*/
static public unsafe void
compute_autocorr(/*const*/ int* data, float* window, int len, int min, int lag, double* autoc, int prev, int next)
compute_autocorr(/*const*/ int* data, float* window, int len, int min, int lag, double* autoc)
{
#if FPAC
short* data1 = stackalloc short[len + 1];
@@ -220,22 +220,18 @@ namespace CUETools.Codecs
if (lag < min) return;
}
#endif
double* data1 = stackalloc double[lag + len + lag];
double* data1 = stackalloc double[len];
int i;
for (i = 0; i < lag; i++)
data1[i] = prev != 0 ? data[i - lag] : 0;
for (i = 0; i < len; i++)
data1[lag + i] = data[i] * window[i];
for (i = 0; i < lag; i++)
data1[lag + len + i] = next != 0 ? data[len + i] : 0;
data1[i] = data[i] * window[i];
for (i = min; i <= lag; ++i)
{
double temp = 0;
double temp2 = 0;
double* pdata = data1 + lag - i;
double* finish = data1 + lag + len - 1;
double* pdata = data1;
double* finish = data1 + len - 1 - i;
while (pdata < finish)
{
@@ -361,6 +357,23 @@ namespace CUETools.Codecs
}
}
static public unsafe void
compute_autocorr_glue(/*const*/ int* data, float* window, int offs, int sz, int min, int lag, double* autoc)
{
double* data1 = stackalloc double[lag + lag];
for (int i = -lag; i < lag; i++)
data1[i + lag] = offs + i >= 0 && offs + i < sz ? data[offs + i] * window[offs + i] : 0;
for (int i = min; i <= lag; ++i)
{
double temp = 0;
double* pdata = data1 + lag - i;
double* finish = data1 + lag;
while (pdata < finish)
temp += pdata[i] * (*pdata++);
autoc[i] += temp;
}
}
static public unsafe void
compute_autocorr_glue(/*const*/ int* data, int min, int lag, double* autoc)
{

View File

@@ -29,7 +29,9 @@ namespace CUETools.Codecs
{
Zero,
One,
OneLarge,
Data,
OneGlue,
Glue
};
public int m_start;
@@ -72,22 +74,48 @@ namespace CUETools.Codecs
m_type = SectionType.Zero;
}
unsafe public static void Detect(int _windowcount, float* window_segment, int stride, int sz, LpcWindowSection* sections)
unsafe public void compute_autocorr(/*const*/ int* data, float* window, int min_order, int order, int blocksize, double* autoc)
{
if (m_type == SectionType.OneLarge)
lpc.compute_autocorr_windowless_large(data + m_start, m_end - m_start, min_order, order, autoc);
else if (m_type == SectionType.One)
lpc.compute_autocorr_windowless(data + m_start, m_end - m_start, min_order, order, autoc);
else if (m_type == SectionType.Data)
lpc.compute_autocorr(data + m_start, window + m_start, m_end - m_start, min_order, order, autoc);
else if (m_type == SectionType.Glue)
lpc.compute_autocorr_glue(data, window, m_start, blocksize, min_order, order, autoc);
else if (m_type == SectionType.OneGlue)
lpc.compute_autocorr_glue(data + m_start, min_order, order, autoc);
}
unsafe public static void Detect(int _windowcount, float* window_segment, int stride, int sz, int bps, LpcWindowSection* sections)
{
int section_id = 0;
var boundaries = new List<int>();
var types = new LpcWindowSection.SectionType[_windowcount, lpc.MAX_LPC_SECTIONS * 2];
var alias = new int[_windowcount, lpc.MAX_LPC_SECTIONS * 2];
var alias_set = new int[_windowcount, lpc.MAX_LPC_SECTIONS * 2];
for (int x = 0; x < sz; x++)
{
for (int i = 0; i < _windowcount; i++)
{
int a = alias[i, boundaries.Count];
float w = window_segment[i * stride + x];
float wa = window_segment[a * stride + x];
if (wa != w)
{
for (int i1 = i; i1 < _windowcount; i1++)
if (alias[i1, boundaries.Count] == a
&& w == window_segment[i1 * stride + x])
alias[i1, boundaries.Count] = i;
}
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;
LpcWindowSection.SectionType.Zero : w != 1.0 ?
LpcWindowSection.SectionType.Data : bps * 2 + BitReader.log2i(sz) >= 61 ?
LpcWindowSection.SectionType.OneLarge :
LpcWindowSection.SectionType.One ;
}
bool isBoundary = false;
for (int i = 0; i < _windowcount; i++)
@@ -95,75 +123,91 @@ namespace CUETools.Codecs
isBoundary |= boundaries.Count == 0 ||
types[i, boundaries.Count - 1] != types[i, boundaries.Count];
}
if (isBoundary) boundaries.Add(x);
if (isBoundary)
{
for (int i = 0; i < _windowcount; i++)
for (int i1 = 0; i1 < _windowcount; i1++)
if (i != i1 && alias[i, boundaries.Count] == alias[i1, boundaries.Count])
alias_set[i, boundaries.Count] |= 1 << i1;
boundaries.Add(x);
}
}
boundaries.Add(sz);
var ones = new int[boundaries.Count - 1];
var secs = new int[_windowcount];
// 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])
LpcWindowSection* window_sections = sections + i * lpc.MAX_LPC_SECTIONS;
// leave room for glue
if (secs[i] >= lpc.MAX_LPC_SECTIONS - 1)
{
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];
}
}
window_sections[secs[i] - 1].m_type = LpcWindowSection.SectionType.Data;
window_sections[secs[i] - 1].m_end = boundaries[j + 1];
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;
window_sections[secs[i]].setData(boundaries[j], boundaries[j + 1]);
window_sections[secs[i]++].m_type = types[i, j];
}
for (int i = 0; i < _windowcount; i++)
{
LpcWindowSection* window_sections = sections + i * lpc.MAX_LPC_SECTIONS;
int sec = secs[i] - 1;
if (sec > 0
&& j > 0 && (alias_set[i, j] == alias_set[i, j - 1] || window_sections[sec].m_type == SectionType.Zero)
&& window_sections[sec].m_start == boundaries[j]
&& window_sections[sec].m_end == boundaries[j + 1]
&& window_sections[sec - 1].m_end == boundaries[j]
&& window_sections[sec - 1].m_type == window_sections[sec].m_type)
{
window_sections[sec - 1].m_end = window_sections[sec].m_end;
secs[i]--;
continue;
}
if (alias_set[i, j] != 0
&& types[i, j] != SectionType.Zero
&& section_id < lpc.MAX_LPC_SECTIONS)
{
for (int i1 = i; i1 < _windowcount; i1++)
if (alias[i1, j] == i && secs[i1] > 0)
sections[i1 * lpc.MAX_LPC_SECTIONS + secs[i1] - 1].m_id = section_id;
section_id++;
}
// TODO: section_id for glue?
if (sec > 0
&& (window_sections[sec].m_type == SectionType.One || window_sections[sec].m_type == SectionType.OneLarge)
&& window_sections[sec].m_end - window_sections[sec].m_start >= lpc.MAX_LPC_ORDER
&& (window_sections[sec - 1].m_type == SectionType.One || window_sections[sec - 1].m_type == SectionType.OneLarge)
&& window_sections[sec - 1].m_end - window_sections[sec - 1].m_start >= lpc.MAX_LPC_ORDER)
{
window_sections[sec + 1] = window_sections[sec];
window_sections[sec].m_end = window_sections[sec].m_start;
window_sections[sec].m_type = SectionType.OneGlue;
window_sections[sec].m_id = -1;
secs[i]++;
continue;
}
if (sec > 0
&& window_sections[sec].m_type != SectionType.Zero
&& window_sections[sec - 1].m_type != SectionType.Zero)
{
window_sections[sec + 1] = window_sections[sec];
window_sections[sec].m_end = window_sections[sec].m_start;
window_sections[sec].m_type = SectionType.Glue;
window_sections[sec].m_id = -1;
secs[i]++;
continue;
}
}
}
for (int i = 0; i < _windowcount; i++)
{
while (secs[i] < lpc.MAX_LPC_SECTIONS)
{
LpcWindowSection* window_sections = sections + i * lpc.MAX_LPC_SECTIONS;
window_sections[secs[i]++].setZero(sz, sz);
}
}
}
}
@@ -202,41 +246,28 @@ namespace CUETools.Codecs
/// <param name="samples">Samples pointer</param>
/// <param name="blocksize">Block size</param>
/// <param name="window">Window function</param>
public void GetReflection(LpcSubframeInfo subframe, int order, int* samples, float* window, LpcWindowSection* sections, bool large)
public void GetReflection(LpcSubframeInfo subframe, int order, int blocksize, int* samples, float* window, LpcWindowSection* sections)
{
if (autocorr_order > order)
return;
fixed (double* reff = reflection_coeffs, autoc = autocorr_values, err = prediction_error)
{
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);
int min_order = subframe.autocorr_section_orders[sections[section].m_id];
for (int i = min_order; i <= order; i++) autocsec[i] = 0;
sections[section].compute_autocorr(samples, window, min_order, order, blocksize, autocsec);
}
subframe.autocorr_section_orders[sections[section].m_id] = order + 1;
}
@@ -245,12 +276,7 @@ namespace CUETools.Codecs
}
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;
sections[section].compute_autocorr(samples, window, autocorr_order, order, blocksize, autoc);
}
}
lpc.compute_schur_reflection(autoc, (uint)order, reff, err);

View File

@@ -114,10 +114,12 @@ namespace CUETools.FlakeExe
Console.WriteLine();
Console.WriteLine(" -m <method> Prediction order search (akaike).");
Console.WriteLine(" -e # Prediction order search depth (1..32).");
Console.WriteLine(" -w <func>[,<func>] One or more window functions (bartlett,welch,hann,flattop,tukey).");
Console.WriteLine(" -w <func>[,<func>] One or more window functions (tukey,partialtukey,");
Console.WriteLine(" punchouttukey,bartlett,welch,hann,flattop).");
Console.WriteLine(" -l #[,#] Prediction order {max} or {min},{max} (1..32).");
Console.WriteLine(" --window-method Window selection method (estimate,evaluate,search).");
Console.WriteLine(" --max-precision Coefficients precision search (0..1).");
Console.WriteLine(" --window-method <wm> Window selection method (estimate,estimateN,");
Console.WriteLine(" evaluate,evaluateN,search).");
Console.WriteLine(" --max-precision #,# Coefficients precision search (0..1).");
Console.WriteLine();
Console.WriteLine("Fixed prediction options:");
Console.WriteLine();