mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
Flake: slight optimisation for new window functions (partial_tukey, punchout_tukey).
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
{
|
||||
Estimate = 0,
|
||||
Evaluate = 1,
|
||||
Search = 2
|
||||
Search = 2,
|
||||
EstimateN = 3,
|
||||
EvaluateN = 4,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -7,5 +7,7 @@ namespace CUETools.Codecs.FLAKE
|
||||
Estimate = 1,
|
||||
Evaluate = 2,
|
||||
Search = 3,
|
||||
EstimateX = 4,
|
||||
EvaluateX = 5,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user