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); } } }