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); } } }
unsafe void encode_residual_lpc_sub(FlacFrame frame, float* lpcs, int iWindow, int order, int ch) { // select LPC precision based on block size uint lpc_precision; if (frame.blocksize <= 192) lpc_precision = 7U; else if (frame.blocksize <= 384) lpc_precision = 8U; else if (frame.blocksize <= 576) lpc_precision = 9U; else if (frame.blocksize <= 1152) lpc_precision = 10U; else if (frame.blocksize <= 2304) lpc_precision = 11U; else if (frame.blocksize <= 4608) lpc_precision = 12U; else if (frame.blocksize <= 8192) lpc_precision = 13U; else if (frame.blocksize <= 16384) lpc_precision = 14U; else lpc_precision = 15; for (int i_precision = eparams.lpc_min_precision_search; i_precision <= eparams.lpc_max_precision_search && lpc_precision + i_precision < 16; i_precision++) // check if we already calculated with this order, window and precision if ((frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[i_precision] & (1U << (order - 1))) == 0) { frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[i_precision] |= (1U << (order - 1)); uint cbits = lpc_precision + (uint)i_precision; frame.current.type = SubframeType.LPC; frame.current.order = order; frame.current.window = iWindow; fixed (int* coefs = frame.current.coefs) { lpc.quantize_lpc_coefs(lpcs + (frame.current.order - 1) * lpc.MAX_LPC_ORDER, frame.current.order, cbits, coefs, out frame.current.shift, 15, 0); if (frame.current.shift < 0 || frame.current.shift > 15) throw new Exception("negative shift"); ulong csum = 0; for (int i = frame.current.order; i > 0; i--) csum += (ulong)Math.Abs(coefs[i - 1]); if ((csum << frame.subframes[ch].obits) >= 1UL << 32) lpc.encode_residual_long(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift); else lpc.encode_residual(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift); } int pmax = get_max_p_order(eparams.max_partition_order, frame.blocksize, frame.current.order); int pmin = Math.Min(eparams.min_partition_order, pmax); uint best_size = calc_rice_params(frame.current.rc, pmin, pmax, frame.current.residual, (uint)frame.blocksize, (uint)frame.current.order, PCM.BitsPerSample); // not working //for (int o = 1; o <= frame.current.order; o++) //{ // if (frame.current.coefs[o - 1] > -(1 << frame.current.shift)) // { // for (int i = o; i < frame.blocksize; i++) // frame.current.residual[i] += frame.subframes[ch].samples[i - o] >> frame.current.shift; // frame.current.coefs[o - 1]--; // uint new_size = calc_rice_params(ref frame.current.rc, pmin, pmax, frame.current.residual, (uint)frame.blocksize, (uint)frame.current.order); // if (new_size > best_size) // { // for (int i = o; i < frame.blocksize; i++) // frame.current.residual[i] -= frame.subframes[ch].samples[i - o] >> frame.current.shift; // frame.current.coefs[o - 1]++; // } // } //} frame.current.size = (uint)(frame.current.order * frame.subframes[ch].obits + 4 + 5 + frame.current.order * (int)cbits + 6 + (int)best_size); frame.ChooseBestSubframe(ch); } }
unsafe void encode_residual_fixed_sub(FlacFrame frame, int order, int ch) { if ((frame.subframes[ch].done_fixed & (1U << order)) != 0) return; // already calculated; frame.current.order = order; frame.current.type = SubframeType.Fixed; encode_residual_fixed(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order); int pmax = get_max_p_order(eparams.max_partition_order, frame.blocksize, frame.current.order); int pmin = Math.Min(eparams.min_partition_order, pmax); frame.current.size = (uint)(frame.current.order * frame.subframes[ch].obits) + 6 + calc_rice_params(frame.current.rc, pmin, pmax, frame.current.residual, (uint)frame.blocksize, (uint)frame.current.order, PCM.BitsPerSample); frame.subframes[ch].done_fixed |= (1U << order); frame.ChooseBestSubframe(ch); }
unsafe void postprocess_coefs(FlacFrame frame, FlacSubframe sf, int ch) { if (eparams.development_mode < 0) return; if (sf.type != SubframeType.LPC || sf.order > 30) return; int orig_window = sf.window; int orig_order = sf.order; int orig_shift = sf.shift; int orig_cbits = sf.cbits; uint orig_size = sf.size; var orig_coefs = stackalloc int[orig_order]; for (int i = 0; i < orig_order; i++) orig_coefs[i] = sf.coefs[i]; int orig_xx = -1; int orig_seq = 0; int maxxx = Math.Min(good_x[orig_order].Length, eparams.development_mode); var pmax = get_max_p_order(eparams.max_partition_order, frame.blocksize, orig_order); var pmin = Math.Min(eparams.min_partition_order, pmax); ulong* sums = stackalloc ulong[(pmax + 1) * Flake.MAX_PARTITIONS]; while (true) { var best_coefs = stackalloc int[orig_order]; int best_shift = orig_shift; int best_cbits = orig_cbits; uint best_size = orig_size; int best_xx = -1; for (int xx = -1; xx < maxxx; xx++) { int x = xx; if (xx < 0) { if (orig_xx < 0 || maxxx < 1/*3*/)// || (orig_xx >> orig_order) != 0) continue; x = orig_xx; orig_seq++; } else { orig_seq = 0; if (orig_order < good_x.Length && good_x[orig_order] != null) x = good_x[orig_order][xx]; } frame.current.type = SubframeType.LPC; frame.current.order = orig_order; frame.current.window = orig_window; frame.current.shift = orig_shift; frame.current.cbits = orig_cbits; if (((x >> orig_order) & 1) != 0) { frame.current.shift--; frame.current.cbits--; if (frame.current.shift < 0 || frame.current.cbits < 2) continue; } ulong csum = 0; int qmax = (1 << (frame.current.cbits - 1)) - 1; for (int i = 0; i < frame.current.order; i++) { int shift = (x >> orig_order) & 1; int increment = (x == 1 << orig_order) ? 0 : (((x >> i) & 1) << 1) - 1; frame.current.coefs[i] = (orig_coefs[i] + (increment << orig_seq)) >> shift; if (frame.current.coefs[i] < -(qmax + 1)) frame.current.coefs[i] = -(qmax + 1); if (frame.current.coefs[i] > qmax) frame.current.coefs[i] = qmax; csum += (ulong)Math.Abs(frame.current.coefs[i]); } fixed (int* coefs = frame.current.coefs) { if ((csum << frame.subframes[ch].obits) >= 1UL << 32) lpc.encode_residual_long(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift); else lpc.encode_residual(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift); } var cur_size = calc_rice_params(frame.current.rc, pmin, pmax, frame.current.residual, (uint)frame.blocksize, (uint)frame.current.order, Settings.PCM.BitsPerSample); frame.current.size = (uint)(frame.current.order * frame.subframes[ch].obits + 4 + 5 + frame.current.order * frame.current.cbits + 6 + (int)cur_size); if (frame.current.size < best_size) { //var dif = best_size - frame.current.size; for (int i = 0; i < frame.current.order; i++) best_coefs[i] = frame.current.coefs[i]; best_shift = frame.current.shift; best_cbits = frame.current.cbits; best_size = frame.current.size; best_xx = x; frame.ChooseBestSubframe(ch); //if (dif > orig_order * 5) // break; } if (xx < 0 && best_size < orig_size) break; } if (best_size < orig_size) { //if (best_xx >= 0) best_x[order, best_xx]++; //if (orig_size != 0x7FFFFFFF) // System.Console.Write(string.Format(" {0}[{1:x}]", orig_size - best_size, best_xx)); for (int i = 0; i < orig_order; i++) orig_coefs[i] = best_coefs[i]; orig_shift = best_shift; orig_cbits = best_cbits; orig_size = best_size; orig_xx = best_xx; } else { break; } } //if (orig_size != 0x7FFFFFFF) // System.Console.WriteLine(); //if (frame_count % 0x400 == 0) //{ // for (int o = 0; o < best_x.GetLength(0); o++) // { // //for (int x = 0; x <= (1 << o); x++) // // if (best_x[o, x] != 0) // // System.Console.WriteLine(string.Format("{0:x2}\t{1:x4}\t{2}", o, x, best_x[o, x])); // var s = new List<KeyValuePair<int, int>>(); // for (int x = 0; x < (1 << o); x++) // if (best_x[o, x] != 0) // s.Add(new KeyValuePair<int, int>(x, best_x[o, x])); // s.Sort((x, y) => y.Value.CompareTo(x.Value)); // foreach (var x in s) // System.Console.WriteLine(string.Format("{0:x2}\t{1:x4}\t{2}", o, x.Key, x.Value)); // int i = 0; // foreach (var x in s) // { // System.Console.Write(string.Format(o <= 8 ? "0x{0:x2}," : "0x{0:x3},", x.Key)); // if ((++i) % 16 == 0) // System.Console.WriteLine(); // } // System.Console.WriteLine(); // } //} }