Fixed a couple pitch corrector bugs. Many remain, however.

This commit is contained in:
yaw-man 2022-09-16 11:41:33 -04:00
parent ef0c96f72a
commit bfe17282d1
2 changed files with 56 additions and 26 deletions

View File

@ -1,6 +1,13 @@
#include <array>
#include <vector>
# define DISTRHO_DECLARE_NON_COPYABLE(ClassName) \
private: \
ClassName(ClassName&) = delete; \
ClassName(const ClassName&) = delete; \
ClassName& operator=(ClassName&) = delete; \
ClassName& operator=(const ClassName&) = delete;
static constexpr double BIG_DOUBLE = 10000.0;
class Scale
@ -75,6 +82,8 @@ class Resampler
{
private:
// Ring buffer.
//TODO: refactor into its own class and look up operator[] semantics.
std::array<T, resamplerBufferSize> array = {};
@ -103,6 +112,8 @@ private:
public:
Resampler(){};
// Detect accurate period from scratch near a target period.
inline double detectPeriodNear(const uint nearPeriod)
{
@ -136,23 +147,24 @@ public:
inline void resample(T *output, uint32_t frames, const double rate, const double period)
{
for (; frames; --frames)
for (uint32_t i = 0; i < frames; ++i)
{
// TODO: add interpolation filter.
*output = array[static_cast<uint>(readIdx)];
++output;
if ((readIdx < writeIdx) &&
(readIdx > writeIdx - rate))
if ((readIdx + rate > writeIdx))
readIdx -= period;
readIdx += rate;
if (readIdx > resamplerBufferSize)
if (readIdx >= resamplerBufferSize)
readIdx -= resamplerBufferSize;
if (readIdx < 0)
readIdx = 0;
};
}
DISTRHO_DECLARE_NON_COPYABLE(Resampler)
};
template <typename T>
@ -169,6 +181,9 @@ class Detector
static constexpr uint maxPeriod = dBufferSize / 2;
public:
Detector(){};
// Read inputFrames from input buffer, downsample by factor and write to our ring buffer
// TODO: implement downsampling filter. This will probably have way too much antialiasing!
inline void downsample(const T* const input, const uint32_t inputFrames)
@ -183,6 +198,7 @@ public:
// Incrementally detect all possible pitches. Return coarse pitch match.
inline uint detectPitch(uint32_t frames)
{
frames /= dFactor;
uint idx = writeIdx - frames;
while (frames)
{
@ -213,4 +229,6 @@ public:
}
return per * dFactor;
}
DISTRHO_DECLARE_NON_COPYABLE(Detector)
};

View File

@ -7,21 +7,22 @@ class PitchCorrector : public Plugin
{
public:
PitchCorrector()
: Plugin(0, 0, 0)
: Plugin(0, 0, 0),
resamplers{},
detectors{}
{
}
protected:
const char* getLabel() const override { return "yaw-totune"; }
const char* getDescription() const override { return "Pitch corrector"; }
const char* getMaker() const override { return "yaw-audio"; }
const char* getHomePage() const override { return "https://yaw.man/plugins/yaw-totune"; }
const char* getLicense() const override { return "Fuck you pay me"; }
uint32_t getVersion() const override { return d_version(1, 0, 0); }
int64_t getUniqueId() const override { return d_cconst('y', 't', 't', 'n'); }
const char *getLabel() const override { return "yaw-totune"; }
const char *getDescription() const override { return "Pitch corrector"; }
const char *getMaker() const override { return "yaw-audio"; }
const char *getHomePage() const override { return "https://yaw.man/plugins/yaw-totune"; }
const char *getLicense() const override { return "Fuck you pay me"; }
uint32_t getVersion() const override { return d_version(1, 0, 0); }
int64_t getUniqueId() const override { return d_cconst('y', 't', 't', 'n'); }
void initParameter(uint32_t index, Parameter& parameter) override
void initParameter(uint32_t index, Parameter &parameter) override
{
parameter.hints = kParameterIsAutomable;
parameter.ranges.def = 0.0f;
@ -43,30 +44,41 @@ protected:
void setParameterValue(uint32_t idx, float val) override
{
}
void run(const float** inputs, float** outputs, uint32_t frames) override
void run(const float **inputs, float **outputs, uint32_t frames) override
{
for(int chn = 0; chn < 2; ++chn){
resamplers[chn].write(inputs[chn], frames);
for (int chn = 0; chn < 2; ++chn)
{
resamplers[chn].write(inputs[chn], frames);
detectors[chn].downsample(inputs[chn], frames);
double period = resamplers[chn].detectPeriodNear(detectors[chn].detectPitch(frames));
double correctPeriod = scale.getNearestPeriod(period);
double taux = period / correctPeriod;
resamplers[chn].resample(outputs[chn], frames, taux, period);
}
uint dpitch = detectors[chn].detectPitch(frames);
double taux;
double period;
if (dpitch)
{
period = resamplers[chn].detectPeriodNear(dpitch);
double correctPeriod = scale.getNearestPeriod(period);
taux = period / correctPeriod;
}
else
{
taux = 1.0;
period = 1.0;
}
resamplers[chn].resample(outputs[chn], frames, taux, period);
}
}
private:
double hzNyq;
std::array<Resampler<float>, 2> resamplers;
std::array<Resampler<float>, 2> resamplers;
std::array<Detector<float>, 2> detectors;
Scale scale{440.0};
Scale scale{440.0};
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PitchCorrector)
};
Plugin* createPlugin()
Plugin *createPlugin()
{
return new PitchCorrector();
}