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
dsp.cpp)
target_include_directories(yaw-totune PUBLIC
".")
"."
"../../lib")

View File

@ -8,53 +8,6 @@ private: \
ClassName& operator=(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
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 dBufferMask = dBufferSize - 1;
static constexpr double BIG_DOUBLE = 10000.0;
template <typename T>
class Resampler
{
@ -93,7 +50,6 @@ private:
// Pointer for pitch detection.
uint writeIdx = 0;
// Calculate autocorrelation from scratch for given period
inline double ac(const uint per)
{
@ -119,7 +75,7 @@ public:
{
double minAC = BIG_DOUBLE;
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);
if (curAC < minAC)
@ -147,20 +103,33 @@ public:
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)
{
// TODO: add interpolation filter.
*output = array[static_cast<uint>(readIdx)];
++output;
if ((readIdx + rate > writeIdx))
readIdx -= period;
// TODO: add interpolation filter. Linear for now.
uint idx = static_cast<uint>(readIdx);
float frac = readIdx - idx;
*output = (1.f - frac) * array[(idx - 1) & resamplerMask] + frac * array[idx & resamplerMask];
readIdx += rate;
if (readIdx >= resamplerBufferSize)
readIdx -= resamplerBufferSize;
if (readIdx < 0)
readIdx = 0;
while ( readIdx < start )
{
readIdx += period;
}
while ( readIdx > end )
{
readIdx -= period;
}
++output;
};
}
@ -191,7 +160,8 @@ public:
for (uint32_t i = 0; i < inputFrames;
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;
uint idx = writeIdx - frames;
bool a = false;
while (frames)
{
// TODO: start at 1 rather than 0
for (int per = 0; per < squares.size(); ++per)
for (uint per = 1; per < squares.size(); ++per)
{
T x = array[idx & dBufferMask];
T y = array[(idx - per) & dBufferMask];
T z = array[(idx - 2 * per) & dBufferMask];
squares[per] += x * x - z * z;
crosses[per] += x * y - y * z;
if(squares[per] - 2.0 * crosses[per] < -0.1)
break;
}
--frames;
++idx;
@ -218,7 +189,7 @@ public:
double least = BIG_DOUBLE;
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];
if (uac < least)

View File

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