Fixed resampling bugs, pitch detection still pilked

This commit is contained in:
yaw-man 2022-09-19 17:31:20 -04:00
parent 645ce2e092
commit f4eb2bdfaf
3 changed files with 49 additions and 77 deletions

View File

@ -3,5 +3,7 @@ dpf_add_plugin(yaw-totune
FILES_DSP FILES_DSP
dsp.cpp) dsp.cpp)
target_include_directories(yaw-totune PUBLIC target_include_directories(yaw-totune PUBLIC
".") "."
"../../lib")

View File

@ -8,53 +8,6 @@ private: \
ClassName& operator=(ClassName&) = delete; \ ClassName& operator=(ClassName&) = delete; \
ClassName& operator=(const ClassName&) = delete; ClassName& operator=(const ClassName&) = delete;
static constexpr double BIG_DOUBLE = 10000.0;
class Scale
{
double sampleRate = 48000.0;
// freqs in hz, periods in samples
std::vector<double> frequencies;
std::vector<double> periods;
public:
void newSampleRate(double rate)
{
double ratio = rate / sampleRate;
sampleRate = rate;
for (double &note : periods)
note *= ratio;
};
// Default ctor: 12TET @ 48kHz
Scale(double hz = 440.0)
{
hz /= 32.0;
for (int i = 0; i < 12 * 8; ++i)
{
frequencies.push_back(hz);
periods.push_back(sampleRate / hz);
hz *= exp2(1.0 / 12.0);
}
}
double getNearestPeriod(double period)
{
for (auto note : periods)
{
if (period > note)
return note;
}
// This should NOT happen.
return 0;
}
// TODO: parse scala files. new ctor that parses arbitrary scales
};
// x that minimizes the quadratic function determined by the three points // x that minimizes the quadratic function determined by the three points
static double secondOrderMinimum(float x0, float y0, float x1, float y1, float x2, float y2) static double secondOrderMinimum(float x0, float y0, float x1, float y1, float x2, float y2)
{ {
@ -77,6 +30,10 @@ static constexpr uint dFactor = 1 << dLogFactor;
static constexpr size_t dBufferSize = 1 << (pSize - dLogFactor); static constexpr size_t dBufferSize = 1 << (pSize - dLogFactor);
static constexpr size_t dBufferMask = dBufferSize - 1; static constexpr size_t dBufferMask = dBufferSize - 1;
static constexpr double BIG_DOUBLE = 10000.0;
template <typename T> template <typename T>
class Resampler class Resampler
{ {
@ -93,7 +50,6 @@ private:
// Pointer for pitch detection. // Pointer for pitch detection.
uint writeIdx = 0; uint writeIdx = 0;
// Calculate autocorrelation from scratch for given period // Calculate autocorrelation from scratch for given period
inline double ac(const uint per) inline double ac(const uint per)
{ {
@ -119,7 +75,7 @@ public:
{ {
double minAC = BIG_DOUBLE; double minAC = BIG_DOUBLE;
double period = nearPeriod; double period = nearPeriod;
for (uint per = nearPeriod - dFactor; per < nearPeriod + dFactor; ++per) for (uint per = nearPeriod - dFactor / 2; per < nearPeriod + dFactor / 2; ++per)
{ {
double curAC = ac(per); double curAC = ac(per);
if (curAC < minAC) if (curAC < minAC)
@ -147,20 +103,33 @@ public:
inline void resample(T *output, uint32_t frames, const double rate, const double period) inline void resample(T *output, uint32_t frames, const double rate, const double period)
{ {
//Bounds of read index.
double end = writeIdx;
while ( readIdx > end ) { end += resamplerBufferSize; };
double start = end - period;
for (uint32_t i = 0; i < frames; ++i) for (uint32_t i = 0; i < frames; ++i)
{ {
// TODO: add interpolation filter. // TODO: add interpolation filter. Linear for now.
*output = array[static_cast<uint>(readIdx)]; uint idx = static_cast<uint>(readIdx);
++output; float frac = readIdx - idx;
*output = (1.f - frac) * array[(idx - 1) & resamplerMask] + frac * array[idx & resamplerMask];
if ((readIdx + rate > writeIdx))
readIdx -= period;
readIdx += rate; readIdx += rate;
if (readIdx >= resamplerBufferSize) while ( readIdx < start )
readIdx -= resamplerBufferSize; {
if (readIdx < 0) readIdx += period;
readIdx = 0; }
while ( readIdx > end )
{
readIdx -= period;
}
++output;
}; };
} }
@ -191,7 +160,8 @@ public:
for (uint32_t i = 0; i < inputFrames; for (uint32_t i = 0; i < inputFrames;
i += dFactor, writeIdx = (writeIdx + 1) & dBufferMask) i += dFactor, writeIdx = (writeIdx + 1) & dBufferMask)
{ {
array[writeIdx] = input[i]; uint32_t j = (i > 3) ? i - 4 : 0;
array[writeIdx] = 0.5f * (input[i] + input[j]); //Lousy lowpass filter just for now.
}; };
} }
@ -200,17 +170,18 @@ public:
{ {
frames /= dFactor; frames /= dFactor;
uint idx = writeIdx - frames; uint idx = writeIdx - frames;
bool a = false;
while (frames) while (frames)
{ {
for (uint per = 1; per < squares.size(); ++per)
// TODO: start at 1 rather than 0
for (int per = 0; per < squares.size(); ++per)
{ {
T x = array[idx & dBufferMask]; T x = array[idx & dBufferMask];
T y = array[(idx - per) & dBufferMask]; T y = array[(idx - per) & dBufferMask];
T z = array[(idx - 2 * per) & dBufferMask]; T z = array[(idx - 2 * per) & dBufferMask];
squares[per] += x * x - z * z; squares[per] += x * x - z * z;
crosses[per] += x * y - y * z; crosses[per] += x * y - y * z;
if(squares[per] - 2.0 * crosses[per] < -0.1)
break;
} }
--frames; --frames;
++idx; ++idx;
@ -218,7 +189,7 @@ public:
double least = BIG_DOUBLE; double least = BIG_DOUBLE;
uint per = 0; uint per = 0;
for (uint i = 0; i < squares.size(); ++i) for (uint i = 1; i < squares.size(); ++i)
{ {
double uac = squares[i] - 2 * crosses[i]; double uac = squares[i] - 2 * crosses[i];
if (uac < least) if (uac < least)

View File

@ -1,5 +1,6 @@
#include "DistrhoPlugin.hpp" #include "DistrhoPlugin.hpp"
#include "Resampler.hpp" #include "Resampler.hpp"
#include "scale/scale.h"
START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO
@ -7,7 +8,7 @@ class PitchCorrector : public Plugin
{ {
public: public:
PitchCorrector() PitchCorrector()
: Plugin(0, 0, 0), : Plugin(1, 0, 0),
resamplers{}, resamplers{},
detectors{} detectors{}
{ {
@ -27,7 +28,7 @@ protected:
parameter.hints = kParameterIsAutomable; parameter.hints = kParameterIsAutomable;
parameter.ranges.def = 0.0f; parameter.ranges.def = 0.0f;
parameter.ranges.min = 0.0f; parameter.ranges.min = 0.0f;
parameter.ranges.max = 1.0f; parameter.ranges.max = 1000.0f;
parameter.name = "param"; parameter.name = "param";
parameter.symbol = "param"; parameter.symbol = "param";
} }
@ -39,7 +40,7 @@ protected:
float getParameterValue(uint32_t index) const override float getParameterValue(uint32_t index) const override
{ {
return 0; return curPitch;
} }
void setParameterValue(uint32_t idx, float val) override void setParameterValue(uint32_t idx, float val) override
@ -53,24 +54,22 @@ protected:
resamplers[chn].write(inputs[chn], frames); resamplers[chn].write(inputs[chn], frames);
detectors[chn].downsample(inputs[chn], frames); detectors[chn].downsample(inputs[chn], frames);
uint dpitch = detectors[chn].detectPitch(frames); uint dpitch = detectors[chn].detectPitch(frames);
double taux; curPitch = dpitch;
double period; double taux = 1.0;
double period = 1.0;
if (dpitch) if (dpitch)
{ {
period = resamplers[chn].detectPeriodNear(dpitch); period = resamplers[chn].detectPeriodNear(dpitch);
double correctPeriod = scale.getNearestPeriod(period); double correctPeriod = scale.getNearestPeriod(period);
taux = period / correctPeriod; if( correctPeriod > 1.0 ) taux = period / correctPeriod;
} }
else //resamplers[chn].resample(outputs[chn], frames, taux, period);
{ resamplers[chn].resample(outputs[chn], frames, 1.3, period);
taux = 1.0;
period = 1.0;
}
resamplers[chn].resample(outputs[chn], frames, taux, period);
} }
} }
private: private:
uint curPitch = 0;
double hzNyq; double hzNyq;
std::array<Resampler<float>, 2> resamplers; std::array<Resampler<float>, 2> resamplers;
std::array<Detector<float>, 2> detectors; std::array<Detector<float>, 2> detectors;