unsafe void encode_residual(FlacFrame frame, int ch, PredictionType predict, OrderMethod omethod, int pass, int best_window)
{
int* smp = frame.subframes[ch].samples;
int i, n = frame.blocksize;
// save best.window, because we can overwrite it later with fixed frame
// CONSTANT
for (i = 1; i < n; i++)
{
if (smp[i] != smp[0]) break;
}
if (i == n)
{
frame.subframes[ch].best.type = SubframeType.Constant;
frame.subframes[ch].best.residual[0] = smp[0];
frame.subframes[ch].best.size = (uint)frame.subframes[ch].obits;
return;
}
// VERBATIM
frame.current.type = SubframeType.Verbatim;
frame.current.size = (uint)(frame.subframes[ch].obits * frame.blocksize);
frame.ChooseBestSubframe(ch);
if (n < 5 || predict == PredictionType.None)
return;
// FIXED
if (predict == PredictionType.Fixed ||
(predict == PredictionType.Search && pass != 1) ||
//predict == PredictionType.Search ||
//(pass == 2 && frame.subframes[ch].best.type == SubframeType.Fixed) ||
n <= eparams.max_prediction_order)
{
int max_fixed_order = Math.Min(eparams.max_fixed_order, 4);
int min_fixed_order = Math.Min(eparams.min_fixed_order, max_fixed_order);
for (i = min_fixed_order; i <= max_fixed_order; i++)
encode_residual_fixed_sub(frame, i, ch);
}
// LPC
if (n > eparams.max_prediction_order &&
(predict == PredictionType.Levinson ||
predict == PredictionType.Search)
//predict == PredictionType.Search ||
//(pass == 2 && frame.subframes[ch].best.type == SubframeType.LPC))
)
{
float* lpcs = stackalloc float[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER];
int min_order = eparams.min_prediction_order;
int max_order = eparams.max_prediction_order;
for (int iWindow = 0; iWindow < _windowcount; iWindow++)
{
if (best_window != -1 && iWindow != best_window)
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);
lpc_ctx.ComputeLPC(lpcs);
//int frameSize = n;
//float* F = stackalloc float[frameSize];
//float* B = stackalloc float[frameSize];
//float* PE = stackalloc float[max_order + 1];
//float* arp = stackalloc float[max_order];
//float* rc = stackalloc float[max_order];
//for (int j = 0; j < frameSize; j++)
// F[j] = B[j] = smp[j];
//for (int K = 1; K <= max_order; K++)
//{
// // BURG:
// float denominator = 0.0f;
// //float denominator = F[K - 1] * F[K - 1] + B[frameSize - K] * B[frameSize - K];
// for (int j = 0; j < frameSize - K; j++)
// denominator += F[j + K] * F[j + K] + B[j] * B[j];
// denominator /= 2;
// // Estimate error
// PE[K - 1] = denominator / (frameSize - K);
// float reflectionCoeff = 0.0f;
// for (int j = 0; j < frameSize - K; j++)
// reflectionCoeff += F[j + K] * B[j];
// reflectionCoeff /= denominator;
// rc[K - 1] = arp[K - 1] = reflectionCoeff;
// // Levinson-Durbin
// for (int j = 0; j < (K - 1) >> 1; j++)
// {
// float arptmp = arp[j];
// arp[j] -= reflectionCoeff * arp[K - 2 - j];
// arp[K - 2 - j] -= reflectionCoeff * arptmp;
// }
// if (((K - 1) & 1) != 0)
// arp[(K - 1) >> 1] -= reflectionCoeff * arp[(K - 1) >> 1];
// for (int j = 0; j < frameSize - K; j++)
// {
// float f = F[j + K];
// float b = B[j];
// F[j + K] = f - reflectionCoeff * b;
// B[j] = b - reflectionCoeff * f;
// }
// for (int j = 0; j < K; j++)
// lpcs[(K - 1) * lpc.MAX_LPC_ORDER + j] = (float)arp[j];
//}
switch (omethod)
{
case OrderMethod.Akaike:
//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;
default:
throw new Exception("unknown order method");
}
for (i = 0; i < eparams.estimation_depth && i < max_order; i++)
encode_residual_lpc_sub(frame, lpcs, iWindow, lpc_ctx.best_orders[i], ch);
}
}
}