/// <summary> /// Calculate autocorrelation data and reflection coefficients. /// Can be used to incrementaly compute coefficients for higher orders, /// because it caches them. /// </summary> /// <param name="order">Maximum order</param> /// <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 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; } for (int section = 0; section < lpc.MAX_LPC_SECTIONS; section++) { if (sections[section].m_type == LpcWindowSection.SectionType.Zero) { continue; } 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]) { 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; } for (int i = autocorr_order; i <= order; i++) { autoc[i] += subframe.autocorr_section_values[sections[section].m_id, i]; } } else { sections[section].compute_autocorr(samples, window, autocorr_order, order, blocksize, autoc); } } lpc.compute_schur_reflection(autoc, (uint)order, reff, err); autocorr_order = order + 1; } }
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; } } } if (boundaries.Count >= lpc.MAX_LPC_SECTIONS * 2) { throw new IndexOutOfRangeException(); } 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.Data : bps * 2 + BitReader.log2i(sz) >= 61 ? LpcWindowSection.SectionType.OneLarge : LpcWindowSection.SectionType.One; } bool isBoundary = false; for (int i = 0; i < _windowcount; i++) { isBoundary |= boundaries.Count == 0 || types[i, boundaries.Count - 1] != types[i, boundaries.Count]; } 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 secs = new int[_windowcount]; // Reconstruct segments list. for (int j = 0; j < boundaries.Count - 1; j++) { for (int i = 0; i < _windowcount; i++) { LpcWindowSection *window_sections = sections + i * lpc.MAX_LPC_SECTIONS; // leave room for glue if (secs[i] >= lpc.MAX_LPC_SECTIONS - 1) { throw new IndexOutOfRangeException(); //window_sections[secs[i] - 1].m_type = LpcWindowSection.SectionType.Data; //window_sections[secs[i] - 1].m_end = boundaries[j + 1]; //continue; } 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 (section_id >= lpc.MAX_LPC_SECTIONS) { throw new IndexOutOfRangeException(); } 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? nontrivial, must be sure next sections are the same size 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++) { for (int s = 0; s < secs[i]; s++) { LpcWindowSection *window_sections = sections + i * lpc.MAX_LPC_SECTIONS; if (window_sections[s].m_type == SectionType.Glue || window_sections[s].m_type == SectionType.OneGlue) { window_sections[s].m_end = window_sections[s + 1].m_end; } } while (secs[i] < lpc.MAX_LPC_SECTIONS) { LpcWindowSection *window_sections = sections + i * lpc.MAX_LPC_SECTIONS; window_sections[secs[i]++].setZero(sz, sz); } } }