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,48 +944,89 @@ namespace CUETools.Codecs.ALAC
encode_residual(frame, ch, 2, estimate_best_window(frame, ch));
}
unsafe int estimate_best_windows_akaike(ALACFrame frame, int ch, int count, bool onePerType)
{
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]++;
}
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.blocksize,
frame.subframes[ch].samples,
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);
}
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_window(ALACFrame frame, int ch)
{
if (_windowcount == 1)
return 0;
return 1;
switch (eparams.window_method)
{
case WindowMethod.Estimate:
{
int order = 4;
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].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++)
{
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_windows[0];
}
case WindowMethod.Evaluate:
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,7 +1145,8 @@ namespace CUETools.Codecs.ALAC
pos += sz;
sz >>= 1;
} while (sz >= 32);
_windowcount++;
windowType[_windowcount] = flag;
_windowcount++;
}
unsafe int encode_frame(ref int size)
@@ -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;