optimizations

This commit is contained in:
chudov
2009-12-24 16:11:22 +00:00
parent c9c6d7b545
commit ebaa2d79a0
3 changed files with 79 additions and 33 deletions

View File

@@ -55,6 +55,11 @@ namespace CUETools.Codecs.FLAKE
return (StereoMethod)(Enum.Parse(typeof(StereoMethod), name, true)); return (StereoMethod)(Enum.Parse(typeof(StereoMethod), name, true));
} }
public static WindowMethod LookupWindowMethod(string name)
{
return (WindowMethod)(Enum.Parse(typeof(WindowMethod), name, true));
}
public static OrderMethod LookupOrderMethod(string name) public static OrderMethod LookupOrderMethod(string name)
{ {
return (OrderMethod)(Enum.Parse(typeof(OrderMethod), name, true)); return (OrderMethod)(Enum.Parse(typeof(OrderMethod), name, true));
@@ -226,9 +231,12 @@ namespace CUETools.Codecs.FLAKE
//public int ch_order0, ch_order1; //public int ch_order0, ch_order1;
public byte crc8; public byte crc8;
public FlacSubframeInfo[] subframes; public FlacSubframeInfo[] subframes;
public uint frame_count; public int frame_number;
public FlacSubframe current; public FlacSubframe current;
public float* window_buffer; public float* window_buffer;
public BitWriter writer = null;
public int writer_offset = 0;
} }
public enum OrderMethod public enum OrderMethod
@@ -270,6 +278,13 @@ namespace CUETools.Codecs.FLAKE
Search = 3 Search = 3
} }
public enum WindowMethod
{
Estimate = 0,
Evaluate = 1,
Search = 2
}
public enum SubframeType public enum SubframeType
{ {
Constant = 0, Constant = 0,

View File

@@ -325,7 +325,7 @@ namespace CUETools.Codecs.FLAKE
uint t1 = bitreader.readbit(); // == 0????? uint t1 = bitreader.readbit(); // == 0?????
if (t1 != 0) if (t1 != 0)
throw new Exception("unsupported frame coding"); throw new Exception("unsupported frame coding");
frame.frame_count = bitreader.read_utf8(); frame.frame_number = (int)bitreader.read_utf8();
// custom block size // custom block size
if (frame.bs_code0 == 6) if (frame.bs_code0 == 6)

View File

@@ -85,6 +85,7 @@ namespace CUETools.Codecs.FLAKE
int[] verifyBuffer; int[] verifyBuffer;
int[] residualBuffer; int[] residualBuffer;
float[] windowBuffer; float[] windowBuffer;
double[] windowScale;
int samplesInBuffer = 0; int samplesInBuffer = 0;
int _compressionLevel = 7; int _compressionLevel = 7;
@@ -123,6 +124,7 @@ namespace CUETools.Codecs.FLAKE
samplesBuffer = new int[Flake.MAX_BLOCKSIZE * (channels == 2 ? 4 : channels)]; samplesBuffer = new int[Flake.MAX_BLOCKSIZE * (channels == 2 ? 4 : channels)];
residualBuffer = new int[Flake.MAX_BLOCKSIZE * (channels == 2 ? 10 : channels + 1)]; residualBuffer = new int[Flake.MAX_BLOCKSIZE * (channels == 2 ? 10 : channels + 1)];
windowBuffer = new float[Flake.MAX_BLOCKSIZE * 2 * lpc.MAX_LPC_WINDOWS]; windowBuffer = new float[Flake.MAX_BLOCKSIZE * 2 * lpc.MAX_LPC_WINDOWS];
windowScale = new double[lpc.MAX_LPC_WINDOWS];
eparams.flake_set_defaults(_compressionLevel); eparams.flake_set_defaults(_compressionLevel);
eparams.padding_size = 8192; eparams.padding_size = 8192;
@@ -267,6 +269,12 @@ namespace CUETools.Codecs.FLAKE
set { eparams.stereo_method = value; } set { eparams.stereo_method = value; }
} }
public WindowMethod WindowMethod
{
get { return eparams.window_method; }
set { eparams.window_method = value; }
}
public int MinPrecisionSearch public int MinPrecisionSearch
{ {
get { return eparams.lpc_min_precision_search; } get { return eparams.lpc_min_precision_search; }
@@ -823,12 +831,11 @@ namespace CUETools.Codecs.FLAKE
frame.ChooseBestSubframe(ch); frame.ChooseBestSubframe(ch);
} }
unsafe void encode_residual(FlacFrame frame, int ch, PredictionType predict, OrderMethod omethod, int pass) unsafe void encode_residual(FlacFrame frame, int ch, PredictionType predict, OrderMethod omethod, int pass, int best_window)
{ {
int* smp = frame.subframes[ch].samples; int* smp = frame.subframes[ch].samples;
int i, n = frame.blocksize; int i, n = frame.blocksize;
// save best.window, because we can overwrite it later with fixed frame // save best.window, because we can overwrite it later with fixed frame
int best_window = frame.subframes[ch].best.type == SubframeType.LPC ? frame.subframes[ch].best.window : -1;
// CONSTANT // CONSTANT
for (i = 1; i < n; i++) for (i = 1; i < n; i++)
@@ -879,7 +886,7 @@ namespace CUETools.Codecs.FLAKE
for (int iWindow = 0; iWindow < _windowcount; iWindow++) for (int iWindow = 0; iWindow < _windowcount; iWindow++)
{ {
if (pass == 2 && iWindow != best_window) if (best_window != -1 && iWindow != best_window)
continue; continue;
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow]; LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];
@@ -940,7 +947,8 @@ namespace CUETools.Codecs.FLAKE
switch (omethod) switch (omethod)
{ {
case OrderMethod.Akaike: case OrderMethod.Akaike:
lpc_ctx.SortOrdersAkaike(frame.blocksize, eparams.estimation_depth); //lpc_ctx.SortOrdersAkaike(frame.blocksize, eparams.estimation_depth, max_order, 7.1, 0.0);
lpc_ctx.SortOrdersAkaike(frame.blocksize, eparams.estimation_depth, max_order, 4.5, 0.0);
break; break;
default: default:
throw new Exception("unknown order method"); throw new Exception("unknown order method");
@@ -1107,7 +1115,7 @@ namespace CUETools.Codecs.FLAKE
bitwriter.flush(); bitwriter.flush();
} }
unsafe void encode_residual_pass1(FlacFrame frame, int ch) unsafe void encode_residual_pass1(FlacFrame frame, int ch, int best_window)
{ {
int max_prediction_order = eparams.max_prediction_order; int max_prediction_order = eparams.max_prediction_order;
int max_fixed_order = eparams.max_fixed_order; int max_fixed_order = eparams.max_fixed_order;
@@ -1121,7 +1129,7 @@ namespace CUETools.Codecs.FLAKE
eparams.lpc_min_precision_search = eparams.lpc_max_precision_search; eparams.lpc_min_precision_search = eparams.lpc_max_precision_search;
eparams.max_prediction_order = 8; eparams.max_prediction_order = 8;
eparams.estimation_depth = 1; eparams.estimation_depth = 1;
encode_residual(frame, ch, eparams.prediction_type, OrderMethod.Akaike, 1); encode_residual(frame, ch, eparams.prediction_type, OrderMethod.Akaike, 1, best_window);
eparams.min_fixed_order = min_fixed_order; eparams.min_fixed_order = min_fixed_order;
eparams.max_fixed_order = max_fixed_order; eparams.max_fixed_order = max_fixed_order;
eparams.max_prediction_order = max_prediction_order; eparams.max_prediction_order = max_prediction_order;
@@ -1133,17 +1141,40 @@ namespace CUETools.Codecs.FLAKE
unsafe void encode_residual_pass2(FlacFrame frame, int ch) unsafe void encode_residual_pass2(FlacFrame frame, int ch)
{ {
encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 2); encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 2, estimate_best_window(frame, ch));
} }
unsafe void encode_residual_onepass(FlacFrame frame, int ch) unsafe int estimate_best_window(FlacFrame frame, int ch)
{ {
if (_windowcount > 1) if (_windowcount == 1)
return 0;
switch (eparams.window_method)
{ {
encode_residual_pass1(frame, ch); case WindowMethod.Estimate:
encode_residual_pass2(frame, ch); {
} else int best_window = -1;
encode_residual(frame, ch, eparams.prediction_type, eparams.order_method, 0); 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;
}
case WindowMethod.Evaluate:
encode_residual_pass1(frame, ch, -1);
return frame.subframes[ch].best.type == SubframeType.LPC ? frame.subframes[ch].best.window : -1;
case WindowMethod.Search:
return -1;
}
return -1;
} }
unsafe void estimate_frame(FlacFrame frame, bool do_midside) unsafe void estimate_frame(FlacFrame frame, bool do_midside)
@@ -1157,22 +1188,17 @@ namespace CUETools.Codecs.FLAKE
{ {
LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[0]; LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[0];
lpc_ctx.GetReflection(4, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer); lpc_ctx.GetReflection(4, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer);
lpc_ctx.SortOrdersAkaike(frame.blocksize, 1); lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 4, 4.5, 0.0);
frame.subframes[ch].best.size = Math.Max(0U, (uint)lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[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 * eparams.max_prediction_order);
} }
break; break;
case StereoMethod.Evaluate: case StereoMethod.Evaluate:
for (int ch = 0; ch < subframes; ch++) for (int ch = 0; ch < subframes; ch++)
{ encode_residual_pass1(frame, ch, 0);
int windowcount = _windowcount;
_windowcount = 1;
encode_residual_pass1(frame, ch);
_windowcount = windowcount;
}
break; break;
case StereoMethod.Search: case StereoMethod.Search:
for (int ch = 0; ch < subframes; ch++) for (int ch = 0; ch < subframes; ch++)
encode_residual_onepass(frame, ch); encode_residual_pass2(frame, ch);
break; break;
} }
} }
@@ -1224,16 +1250,12 @@ namespace CUETools.Codecs.FLAKE
for (int ch = 0; ch < channels; ch++) for (int ch = 0; ch < channels; ch++)
{ {
frame.subframes[ch].best.size = AudioSamples.UINT32_MAX; frame.subframes[ch].best.size = AudioSamples.UINT32_MAX;
encode_residual_onepass(frame, ch); encode_residual_pass2(frame, ch);
} }
break; break;
case StereoMethod.Evaluate: case StereoMethod.Evaluate:
for (int ch = 0; ch < channels; ch++) for (int ch = 0; ch < channels; ch++)
{
if (_windowcount > 1)
encode_residual_pass1(frame, ch);
encode_residual_pass2(frame, ch); encode_residual_pass2(frame, ch);
}
break; break;
case StereoMethod.Search: case StereoMethod.Search:
break; break;
@@ -1247,7 +1269,8 @@ namespace CUETools.Codecs.FLAKE
if ((eparams.window_function & flag) == 0 || _windowcount == lpc.MAX_LPC_WINDOWS) if ((eparams.window_function & flag) == 0 || _windowcount == lpc.MAX_LPC_WINDOWS)
return; return;
int sz = _windowsize; int sz = _windowsize;
float* pos = window + _windowcount * Flake.MAX_BLOCKSIZE * 2; float* pos1 = window + _windowcount * Flake.MAX_BLOCKSIZE * 2;
float* pos = pos1;
do do
{ {
func(pos, sz); func(pos, sz);
@@ -1256,6 +1279,10 @@ namespace CUETools.Codecs.FLAKE
pos += sz; pos += sz;
sz >>= 1; sz >>= 1;
} while (sz >= 32); } while (sz >= 32);
double scale = 0.0;
for (int i = 0; i < _windowsize; i++)
scale += pos1[i] * pos1[i];
windowScale[_windowcount] = scale;
_windowcount++; _windowcount++;
} }
@@ -1272,8 +1299,8 @@ namespace CUETools.Codecs.FLAKE
_windowcount = 0; _windowcount = 0;
calculate_window(window, lpc.window_welch, WindowFunction.Welch); calculate_window(window, lpc.window_welch, WindowFunction.Welch);
calculate_window(window, lpc.window_tukey, WindowFunction.Tukey); calculate_window(window, lpc.window_tukey, WindowFunction.Tukey);
calculate_window(window, lpc.window_hann, WindowFunction.Hann);
calculate_window(window, lpc.window_flattop, WindowFunction.Flattop); calculate_window(window, lpc.window_flattop, WindowFunction.Flattop);
calculate_window(window, lpc.window_hann, WindowFunction.Hann);
calculate_window(window, lpc.window_bartlett, WindowFunction.Bartlett); calculate_window(window, lpc.window_bartlett, WindowFunction.Bartlett);
if (_windowcount == 0) if (_windowcount == 0)
throw new Exception("invalid windowfunction"); throw new Exception("invalid windowfunction");
@@ -1289,7 +1316,7 @@ namespace CUETools.Codecs.FLAKE
bits_per_sample, get_wasted_bits(s + ch * Flake.MAX_BLOCKSIZE, frame.blocksize)); bits_per_sample, get_wasted_bits(s + ch * Flake.MAX_BLOCKSIZE, frame.blocksize));
for (int ch = 0; ch < channels; ch++) for (int ch = 0; ch < channels; ch++)
encode_residual_onepass(frame, ch); encode_residual_pass2(frame, ch);
} }
else else
{ {
@@ -1739,6 +1766,8 @@ namespace CUETools.Codecs.FLAKE
// 1 = mid-side encoding // 1 = mid-side encoding
public StereoMethod stereo_method; public StereoMethod stereo_method;
public WindowMethod window_method;
// block size in samples // block size in samples
// set by the user prior to calling flake_encode_init // set by the user prior to calling flake_encode_init
// if set to 0, a block size is chosen based on block_time_ms // if set to 0, a block size is chosen based on block_time_ms
@@ -1834,6 +1863,7 @@ namespace CUETools.Codecs.FLAKE
window_function = WindowFunction.Flattop | WindowFunction.Tukey; window_function = WindowFunction.Flattop | WindowFunction.Tukey;
order_method = OrderMethod.Akaike; order_method = OrderMethod.Akaike;
stereo_method = StereoMethod.Evaluate; stereo_method = StereoMethod.Evaluate;
window_method = WindowMethod.Evaluate;
block_size = 0; block_size = 0;
block_time_ms = 105; block_time_ms = 105;
prediction_type = PredictionType.Search; prediction_type = PredictionType.Search;
@@ -1882,7 +1912,8 @@ namespace CUETools.Codecs.FLAKE
window_function = WindowFunction.Bartlett; window_function = WindowFunction.Bartlett;
break; break;
case 5: case 5:
window_function = WindowFunction.Bartlett; stereo_method = StereoMethod.Estimate;
window_method = WindowMethod.Estimate;
break; break;
case 6: case 6:
stereo_method = StereoMethod.Estimate; stereo_method = StereoMethod.Estimate;