From e9264ae90996488ecb4818d73d80ee524e83076f Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Thu, 19 May 2022 13:13:47 +0100 Subject: [PATCH] Add peak finder --- src/R3StretcherImpl.h | 2 + src/dsp/Peak.h | 127 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/dsp/Peak.h diff --git a/src/R3StretcherImpl.h b/src/R3StretcherImpl.h index 420a03f..075808c 100644 --- a/src/R3StretcherImpl.h +++ b/src/R3StretcherImpl.h @@ -31,6 +31,8 @@ #include "dsp/FFT.h" #include "system/Allocators.h" +#include "dsp/Peak.h" + namespace RubberBand { diff --git a/src/dsp/Peak.h b/src/dsp/Peak.h new file mode 100644 index 0000000..f73ab71 --- /dev/null +++ b/src/dsp/Peak.h @@ -0,0 +1,127 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band Library + An audio time-stretching and pitch-shifting library. + Copyright 2007-2022 Particular Programs Ltd. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. + + Alternatively, if you have a valid commercial licence for the + Rubber Band Library obtained by agreement with the copyright + holders, you may redistribute and/or modify it under the terms + described in that licence. + + If you wish to distribute code using the Rubber Band Library + under terms other than those of the GNU General Public License, + you must obtain a valid commercial licence before doing so. +*/ + +#ifndef RUBBERBAND_PEAK_H +#define RUBBERBAND_PEAK_H + +#include + +namespace RubberBand +{ + +template +class Peak +{ +public: + Peak(int n) : + m_n(n), + m_locations(n, 0) { } + + // Find the nearest peak to each bin, and optionally the next + // highest peak above each bin, within an array v, where a peak is + // a value greater than the p nearest neighbours on each side. The + // array must have length n where n is the size passed the the + // constructor. + void findNearestAndNextPeaks(const T *const v, + int p, + int *nearest, + int *next = nullptr) + { + findNearestAndNextPeaks(v, 0, m_n, p, nearest, next); + } + + // As above but consider only the range of size rangeCount from + // index rangeStart. Write rangeCount results into nearest and + // optionally next, starting to write at index rangeStart - so + // these arrays must have the full length even if rangeCount is + // shorter. Leave the rest of nearest and/or next unmodified. + void findNearestAndNextPeaks(const T *const v, + int rangeStart, + int rangeCount, + int p, + int *nearest, + int *next = nullptr) + { + int nPeaks = 0; + int n = rangeStart + rangeCount; + + for (int i = rangeStart; i < n; ++i) { + T x = v[i]; + bool good = true; + for (int k = i - p; k <= i + p; ++k) { + if (k < rangeStart || k == i) continue; + if (k >= n) break; + if (k < i && x <= v[k]) { + good = false; + break; + } + if (k > i && x < v[k]) { + good = false; + break; + } + } + if (good) { + m_locations[nPeaks++] = i; + } + } + + int pp = rangeStart - 1; + for (int i = rangeStart, j = 0; i < n; ++i) { + int np = i; + if (j < nPeaks) { + np = m_locations[j]; + } + if (next) { + if (pp == i) { + next[i] = i; + } else { + next[i] = np; + } + } + if (nearest) { + if (j == 0) { + nearest[i] = np; + } else { + if (np - i < i - pp) { + nearest[i] = np; + } else { + nearest[i] = pp; + } + } + } + while (j < nPeaks && m_locations[j] <= i) { + pp = np; + ++j; + } + } + } + +protected: + int m_n; + std::vector m_locations; +}; + + +} + +#endif