Smoother frequency map using cubics instead of linear segments.

This means the frequency map isn't *completely* linear around the peaks, but it's pretty close, and the smoother curve reduces pre-ringing around transients.
This commit is contained in:
Geraint 2022-12-01 00:02:42 +00:00
parent 85df203ba7
commit 72ea54e4a9

View File

@ -524,30 +524,28 @@ private:
}
return;
}
Sample linearZoneBins = peakWidthBins*Sample(0.5);
Sample bottomOffset = peaks[0].input - peaks[0].output;
for (int b = 0; b < std::min<int>(stft.bands(), peaks[0].output); ++b) {
for (int b = 0; b < std::min<int>(stft.bands(), std::ceil(peaks[0].output)); ++b) {
outputMap[b] = {b + bottomOffset, 1};
}
// Interpolate between points
for (size_t p = 1; p < peaks.size(); ++p) {
const Peak &prev = peaks[p - 1], &next = peaks[p];
Sample prevEnd = prev.output + linearZoneBins;
Sample nextStart = next.output - linearZoneBins;
if (nextStart < prevEnd) nextStart = prevEnd = (nextStart + prevEnd)*Sample(0.5);
signalsmith::curves::Linear<Sample> segment(prevEnd, nextStart, prev.input + linearZoneBins, next.input - linearZoneBins);
Sample segmentGrad = ((prev.input + linearZoneBins) - (next.input - linearZoneBins))/(prevEnd - nextStart + noiseFloor);
prevEnd = std::max<Sample>(0, std::min<Sample>(stft.bands(), prevEnd));
nextStart = std::max<Sample>(0, std::min<Sample>(stft.bands(), nextStart));
for (int b = std::max<int>(0, std::ceil(prev.output)); b < prevEnd; ++b) {
outputMap[b] = {b + prev.input - prev.output, 1};
}
for (int b = std::ceil(prevEnd); b < nextStart; ++b) {
outputMap[b] = {segment(b), segmentGrad};
}
for (int b = std::ceil(nextStart); b < std::min<int>(stft.bands(), std::ceil(next.output)); ++b) {
outputMap[b] = {b + next.input - next.output, 1};
Sample rangeScale = 1/(next.output - prev.output);
Sample outOffset = prev.input - prev.output;
Sample outScale = next.input - next.output - prev.input + prev.output;
Sample gradScale = outScale*rangeScale;
int startBin = std::max<int>(0, std::ceil(prev.output));
int endBin = std::min<int>(stft.bands(), std::ceil(next.output));
for (int b = startBin; b < endBin; ++b) {
Sample r = (b - prev.output)*rangeScale;
Sample h = r*r*(3 - 2*r);
Sample outB = b + outOffset + h*outScale;
Sample gradH = 6*r*(1 - r);
Sample gradB = 1 + gradH*gradScale;
outputMap[b] = {outB, gradB};
}
}
Sample topOffset = peaks.back().input - peaks.back().output;