2022-05-19 13:13:47 +01:00
|
|
|
/* -*- 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.
|
2024-03-07 15:19:37 +00:00
|
|
|
Copyright 2007-2024 Particular Programs Ltd.
|
2022-05-19 13:13:47 +01:00
|
|
|
|
|
|
|
|
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 <vector>
|
|
|
|
|
|
|
|
|
|
namespace RubberBand
|
|
|
|
|
{
|
|
|
|
|
|
2022-05-19 15:25:33 +01:00
|
|
|
template <typename T, typename GreaterThan = std::greater<T>>
|
2022-05-19 13:13:47 +01:00
|
|
|
class Peak
|
|
|
|
|
{
|
|
|
|
|
public:
|
2022-05-20 15:29:52 +01:00
|
|
|
/** Peak picker for array of length n. This allocates on
|
|
|
|
|
construction an internal buffer for temporary values, to be
|
|
|
|
|
used within the peak-picking functions, so that it does not
|
|
|
|
|
have to allocate when used. It does not have persistent state.
|
|
|
|
|
*/
|
2022-05-19 13:13:47 +01:00
|
|
|
Peak(int n) :
|
|
|
|
|
m_n(n),
|
|
|
|
|
m_locations(n, 0) { }
|
|
|
|
|
|
2022-05-20 15:29:52 +01:00
|
|
|
/** 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.
|
|
|
|
|
*/
|
2022-05-19 16:31:21 +01:00
|
|
|
void findNearestAndNextPeaks(const T *v,
|
2022-05-19 13:13:47 +01:00
|
|
|
int p,
|
|
|
|
|
int *nearest,
|
|
|
|
|
int *next = nullptr)
|
|
|
|
|
{
|
|
|
|
|
findNearestAndNextPeaks(v, 0, m_n, p, nearest, next);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-20 15:29:52 +01:00
|
|
|
/** 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.
|
|
|
|
|
*/
|
2022-05-19 16:31:21 +01:00
|
|
|
void findNearestAndNextPeaks(const T *v,
|
2022-05-19 13:13:47 +01:00
|
|
|
int rangeStart,
|
|
|
|
|
int rangeCount,
|
|
|
|
|
int p,
|
|
|
|
|
int *nearest,
|
|
|
|
|
int *next = nullptr)
|
|
|
|
|
{
|
|
|
|
|
int nPeaks = 0;
|
|
|
|
|
int n = rangeStart + rangeCount;
|
2022-05-19 15:25:33 +01:00
|
|
|
GreaterThan greater;
|
2022-05-19 13:13:47 +01:00
|
|
|
|
|
|
|
|
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;
|
2022-05-19 15:25:33 +01:00
|
|
|
if (k < i && !greater(x, v[k])) {
|
2022-05-19 13:13:47 +01:00
|
|
|
good = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-05-19 15:25:33 +01:00
|
|
|
if (k > i && greater(v[k], x)) {
|
2022-05-19 13:13:47 +01:00
|
|
|
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];
|
2022-06-09 09:03:20 +01:00
|
|
|
} else if (nPeaks > 0) {
|
|
|
|
|
np = m_locations[nPeaks-1];
|
2022-05-19 13:13:47 +01:00
|
|
|
}
|
|
|
|
|
if (next) {
|
2022-06-09 09:03:20 +01:00
|
|
|
if (pp == i || j >= nPeaks) {
|
2022-05-19 13:13:47 +01:00
|
|
|
next[i] = i;
|
|
|
|
|
} else {
|
|
|
|
|
next[i] = np;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nearest) {
|
|
|
|
|
if (j == 0) {
|
|
|
|
|
nearest[i] = np;
|
|
|
|
|
} else {
|
2022-05-24 15:21:13 +01:00
|
|
|
if (np - i <= i - pp) {
|
2022-05-19 13:13:47 +01:00
|
|
|
nearest[i] = np;
|
|
|
|
|
} else {
|
|
|
|
|
nearest[i] = pp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (j < nPeaks && m_locations[j] <= i) {
|
|
|
|
|
pp = np;
|
|
|
|
|
++j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
int m_n;
|
|
|
|
|
std::vector<int> m_locations;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|