Fixed resampling bugs, pitch detection still pilked
This commit is contained in:
parent
645ce2e092
commit
f4eb2bdfaf
|
@ -3,5 +3,7 @@ dpf_add_plugin(yaw-totune
|
|||
FILES_DSP
|
||||
dsp.cpp)
|
||||
|
||||
|
||||
target_include_directories(yaw-totune PUBLIC
|
||||
".")
|
||||
"."
|
||||
"../../lib")
|
|
@ -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 ¬e : 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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue