diff --git a/src/yaw-totune/CMakeLists.txt b/src/yaw-totune/CMakeLists.txt index e29e0d1..109ca7e 100644 --- a/src/yaw-totune/CMakeLists.txt +++ b/src/yaw-totune/CMakeLists.txt @@ -3,5 +3,7 @@ dpf_add_plugin(yaw-totune FILES_DSP dsp.cpp) + target_include_directories(yaw-totune PUBLIC - ".") \ No newline at end of file + "." + "../../lib") \ No newline at end of file diff --git a/src/yaw-totune/Resampler.hpp b/src/yaw-totune/Resampler.hpp index f76be76..27bcf5e 100644 --- a/src/yaw-totune/Resampler.hpp +++ b/src/yaw-totune/Resampler.hpp @@ -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 frequencies; - std::vector 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 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(readIdx)]; - ++output; - - if ((readIdx + rate > writeIdx)) - readIdx -= period; + // TODO: add interpolation filter. Linear for now. + uint idx = static_cast(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) diff --git a/src/yaw-totune/dsp.cpp b/src/yaw-totune/dsp.cpp index 3c57733..e99db59 100644 --- a/src/yaw-totune/dsp.cpp +++ b/src/yaw-totune/dsp.cpp @@ -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, 2> resamplers; std::array, 2> detectors;