Fixed a couple pitch corrector bugs. Many remain, however.
This commit is contained in:
parent
ef0c96f72a
commit
bfe17282d1
|
@ -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)
|
||||
};
|
|
@ -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 ¶meter) 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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue