From 0bfa94a76a4fe78c027eac271e6700a1035fb541 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Fri, 10 Jun 2022 13:09:48 +0100 Subject: [PATCH] Restore MovingMedian to the simpler single filter and provide ..Stack separately. Seems little point in coalescing memory there, now we have separate ring buffers anyway --- src/common/MovingMedian.h | 169 ++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 91 deletions(-) diff --git a/src/common/MovingMedian.h b/src/common/MovingMedian.h index bdd743c..ce81380 100644 --- a/src/common/MovingMedian.h +++ b/src/common/MovingMedian.h @@ -38,74 +38,96 @@ namespace RubberBand { template -class MovingMedianStack +class MovingMedian : public SampleFilter { public: - MovingMedianStack(int nfilters, int filterLength, float percentile = 50.f) : - m_buffers(nfilters, filterLength), - m_sortspace(nfilters * filterLength, {}), - m_length(filterLength) + MovingMedian(int filterLength, float percentile = 50.f) : + m_buffer(filterLength), + m_sortspace(filterLength, {}) { setPercentile(percentile); } - ~MovingMedianStack() { + ~MovingMedian() { } - int getNFilters() const { - return m_buffers.size(); - } - + MovingMedian(const MovingMedian &) =default; + MovingMedian &operator=(const MovingMedian &) =default; + int getSize() const { - return m_length; + return m_buffer.getSize(); } void setPercentile(float p) { - m_index = int((m_length * p) / 100.f); - if (m_index >= m_length) m_index = m_length-1; + int length = getSize(); + m_index = int((length * p) / 100.f); + if (m_index >= length) m_index = length-1; if (m_index < 0) m_index = 0; } - void push(int filter, T value) { + void push(T value) { if (value != value) { std::cerr << "WARNING: MovingMedian: NaN encountered" << std::endl; value = T(); } - auto &buf = m_buffers[filter]; - if (buf.getWriteSpace() == 0) { - T toDrop = buf.readOne(); - dropAndPut(filter, toDrop, value); - buf.writeOne(value); + if (m_buffer.getWriteSpace() == 0) { + T toDrop = m_buffer.readOne(); + dropAndPut(toDrop, value); + m_buffer.writeOne(value); } else { - put(filter, value); - buf.writeOne(value); + put(value); + m_buffer.writeOne(value); } } - T get(int filter) const { - const T *sorted = sortedFor(filter); - return sorted[m_index]; + T get() const { + return m_sortspace[m_index]; } void reset() { - for (auto &buf : m_buffers) buf.reset(); + m_buffer.reset(); v_zero(m_sortspace.data(), m_sortspace.size()); } + + // Convenience function that applies a given filter to an array + // in-place. Array has length n. Modifies both the filter and the + // array. + // + static void filter(MovingMedian &mm, T *v, int n) { + int fn = mm.getSize(); + int lag = fn / 2; + mm.reset(); + int i = 0; + for (; i < lag; ++i) { + if (i < n) mm.push(v[i]); + } + for (; i < n; ++i) { + mm.push(v[i]); + v[i-lag] = mm.get(); + } + for (; i < lag; ++i) { + // just for the unusual case where lag > n + mm.push(T()); + (void)mm.get(); + } + for (; i < n + lag; ++i) { + mm.push(T()); + v[i-lag] = mm.get(); + } + } + + // As above but with a vector argument + // + static void filter(MovingMedian &mm, std::vector &v) { + filter(mm, v.data(), v.size()); + } private: - FixedVector> m_buffers; - FixedVector m_sortspace; - int m_length; + SingleThreadRingBuffer m_buffer; + std::vector m_sortspace; int m_index; - const T *sortedFor(int filter) const { - return m_sortspace.data() + filter * m_length; - } - T *sortedFor(int filter) { - return m_sortspace.data() + filter * m_length; - } - - void dropAndPut(int filter, const T &toDrop, const T &toPut) { + void dropAndPut(const T &toDrop, const T &toPut) { // precondition: sorted contains m_length values, one of which is toDrop // postcondition: sorted contains m_length values, one of which is toPut // (and one instance of toDrop has been removed) @@ -114,8 +136,8 @@ private: // longer than maybe 16 items). Two binary searches plus a // memmove should be faster for longer ones. - const int n = m_length; - T *sorted = sortedFor(filter); + const int n = getSize(); + T *sorted = m_sortspace.data(); int dropIx; if (toDrop <= *sorted) { // this is quite a common short-circuit in situations @@ -175,12 +197,12 @@ private: #endif } - void put(int filter, const T &toPut) { + void put(const T &toPut) { // precondition: sorted contains fewer than m_length values, // packed at the start // postcondition: sorted contains up to m_length values, // packed at the start, one of which is toPut - const int n = m_buffers[filter].getReadSpace(); // items in sorted + const int n = m_buffer.getReadSpace(); // items in sorted #ifdef DEBUG_MM if (n >= m_length) { @@ -188,7 +210,7 @@ private: } #endif - T *sorted = sortedFor(filter); + T *sorted = m_sortspace.data(); int putIx = std::lower_bound(sorted, sorted + n, toPut) - sorted; #ifdef DEBUG_MM @@ -220,81 +242,46 @@ private: } #endif } - - MovingMedianStack(const MovingMedianStack &) =delete; - MovingMedianStack &operator=(const MovingMedianStack &) =delete; }; template -class MovingMedian : public SampleFilter +class MovingMedianStack { public: - MovingMedian(int size, float percentile = 50.f) : - m_mm(1, size, percentile) + MovingMedianStack(int nfilters, int size, float percentile = 50.f) : + m_stack(nfilters, { size, percentile }) { } - ~MovingMedian() { + ~MovingMedianStack() { } int getSize() const { - return m_mm.getSize(); + return m_stack[0].getSize(); } void setPercentile(float p) { - m_mm.setPercentile(p); + for (auto &f: m_stack) { + f.setPercentile(p); + } } - void push(T value) { - m_mm.push(0, value); + void push(int filter, T value) { + m_stack[filter].push(value); } - T get() const { - return m_mm.get(0); + T get(int filter) const { + return m_stack[filter].get(); } void reset() { - m_mm.reset(); - } - - // Convenience function that applies a given filter to an array - // in-place. Array has length n. Modifies both the filter and the - // array. - // - static void filter(MovingMedian &mm, T *v, int n) { - int fn = mm.getSize(); - int lag = fn / 2; - mm.reset(); - int i = 0; - for (; i < lag; ++i) { - if (i < n) mm.push(v[i]); + for (auto &f: m_stack) { + f.reset(); } - for (; i < n; ++i) { - mm.push(v[i]); - v[i-lag] = mm.get(); - } - for (; i < lag; ++i) { - // just for the unusual case where lag > n - mm.push(T()); - (void)mm.get(); - } - for (; i < n + lag; ++i) { - mm.push(T()); - v[i-lag] = mm.get(); - } - } - - // As above but with a vector argument - // - static void filter(MovingMedian &mm, std::vector &v) { - filter(mm, v.data(), v.size()); } private: - MovingMedianStack m_mm; - - MovingMedian(const MovingMedian &) =delete; - MovingMedian &operator=(const MovingMedian &) =delete; + std::vector> m_stack; }; }