diff --git a/.gitignore b/.gitignore index 0790b55..83d09a0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ JuceLibraryCode/ Builds/ *bak +*jucer diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 7aecfac..79eab5b 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -1,7 +1,6 @@ #include "PluginProcessor.h" #include "PluginEditor.h" - LampshadeAudioProcessor::LampshadeAudioProcessor() #ifndef JucePlugin_PreferredChannelConfigurations : AudioProcessor (BusesProperties() @@ -69,6 +68,7 @@ void LampshadeAudioProcessor::changeProgramName (int index, const String& newNam void LampshadeAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) { + myYin = Yin(sampleRate, samplesPerBlock); } void LampshadeAudioProcessor::releaseResources() @@ -105,8 +105,12 @@ void LampshadeAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffe for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i) buffer.clear(i, 0, buffer.getNumSamples()); + float pitch = myYin.getPitch(buffer.getWritePointer (0)); // returns Pitch in Hertz + printf("pitch: %f", pitch); + for (int channel = 0; channel < totalNumInputChannels; ++channel) { //float* channelData = buffer.getWritePointer (channel); + } } diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 441be0f..bd2d1a0 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -1,7 +1,7 @@ #pragma once #include "../JuceLibraryCode/JuceHeader.h" - +#include "Yin.h" class LampshadeAudioProcessor : public AudioProcessor { @@ -38,4 +38,5 @@ public: private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LampshadeAudioProcessor) + Yin myYin; }; diff --git a/Source/Yin.cpp b/Source/Yin.cpp new file mode 100644 index 0000000..ef99681 --- /dev/null +++ b/Source/Yin.cpp @@ -0,0 +1,146 @@ +#include "Yin.h" +#include +//#include "WProgram.h" + +void Yin::initialize(float yinSampleRate,int yinBufferSize){ + bufferSize = yinBufferSize; + sampleRate = yinSampleRate; + halfBufferSize = bufferSize / 2; + threshold = 0.15; + probability = 0.0; + //initialize array and set it to zero + yinBuffer = (float *) malloc(sizeof(float)* halfBufferSize); + for(int i = 0; i < halfBufferSize; i++){ + yinBuffer[i] = 0; + } +} + +Yin::Yin(){ +} + +Yin::Yin(float yinSampleRate,int yinBufferSize){ + initialize(yinSampleRate,yinBufferSize); +} + +float Yin::getProbability(){ + return probability; +} + +float Yin::getPitch(float* buffer){ + int tauEstimate = -1; + float pitchInHertz = -1; + + //step 2 + difference(buffer); + + // step 3 + cumulativeMeanNormalizedDifference(); + + //step 4 + tauEstimate = absoluteThreshold(); + + //step 5 + if(tauEstimate != -1){ + + pitchInHertz = sampleRate / parabolicInterpolation(tauEstimate); + } + + return pitchInHertz; +} + +float Yin::parabolicInterpolation(int tauEstimate) { + float betterTau; + int x0; + int x2; + + if (tauEstimate < 1) { + x0 = tauEstimate; + } + else { + x0 = tauEstimate - 1; + } + if (tauEstimate + 1 < halfBufferSize) { + x2 = tauEstimate + 1; + } + else { + x2 = tauEstimate; + } + if (x0 == tauEstimate) { + if (yinBuffer[tauEstimate] <= yinBuffer[x2]) { + betterTau = tauEstimate; + } + else { + betterTau = x2; + } + } + else if (x2 == tauEstimate) { + if (yinBuffer[tauEstimate] <= yinBuffer[x0]) { + betterTau = tauEstimate; + } + else { + betterTau = x0; + } + } + else { + float s0, s1, s2; + s0 = yinBuffer[x0]; + s1 = yinBuffer[tauEstimate]; + s2 = yinBuffer[x2]; + // fixed AUBIO implementation, thanks to Karl Helgason: + // (2.0f * s1 - s2 - s0) was incorrectly multiplied with -1 + betterTau = tauEstimate + (s2 - s0) / (2 * (2 * s1 - s2 - s0)); + } + return betterTau; +} + +void Yin::cumulativeMeanNormalizedDifference(){ + int tau; + yinBuffer[0] = 1; + float runningSum = 0; + for (tau = 1; tau < halfBufferSize; tau++) { + runningSum += yinBuffer[tau]; + yinBuffer[tau] *= tau / runningSum; + } +} + +void Yin::difference(float* buffer){ + int index; + int tau; + float delta; + for(tau = 0 ; tau < halfBufferSize; tau++){ + for(index = 0; index < halfBufferSize; index++){ + delta= buffer[index] - buffer[index + tau]; + yinBuffer[tau] += delta * delta; + } + } +} + +int Yin::absoluteThreshold(){ + int tau; + // first two positions in yinBuffer are always 1 + // So start at the third (index 2) + for (tau = 2; tau < halfBufferSize ; tau++) { + if (yinBuffer[tau] < threshold) { + while (tau + 1 < halfBufferSize && yinBuffer[tau + 1] < yinBuffer[tau]) { + tau++; + } + // found tau, exit loop and return + // store the probability + // From the YIN paper: The threshold determines the list of + // candidates admitted to the set, and can be interpreted as the + // proportion of aperiodic power tolerated + // within a ëëperiodicíí signal. + // + // Since we want the periodicity and and not aperiodicity: + // periodicity = 1 - aperiodicity + probability = 1 - yinBuffer[tau]; + break; + } + } + // if no pitch found, tau => -1 + if (tau == halfBufferSize || yinBuffer[tau] >= threshold) { + tau = -1; + probability = 0; + } + return tau; +} diff --git a/Source/Yin.h b/Source/Yin.h new file mode 100644 index 0000000..dbeee98 --- /dev/null +++ b/Source/Yin.h @@ -0,0 +1,26 @@ +#pragma once + +//#include "WProgram.h" + +class Yin{ + +public: + Yin(); + Yin(float sampleRate,int bufferSize); + void initialize(float sampleRate,int bufferSize); + float getPitch(float* buffer); + float getProbability(); + +private: + float parabolicInterpolation(int tauEstimate); + int absoluteThreshold(); + void cumulativeMeanNormalizedDifference(); + void difference(float* buffer); + + double threshold; + int bufferSize; + int halfBufferSize; + float sampleRate; + float* yinBuffer; + float probability; +}; diff --git a/lampshade.jucer b/lampshade.jucer deleted file mode 100644 index c46c7d8..0000000 --- a/lampshade.jucer +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test Project/Ableton Project Info/Project8_1.cfg b/test Project/Ableton Project Info/Project8_1.cfg new file mode 100644 index 0000000..7c8c1d2 Binary files /dev/null and b/test Project/Ableton Project Info/Project8_1.cfg differ diff --git "a/test Project/Icon\r" "b/test Project/Icon\r" new file mode 100644 index 0000000..e69de29 diff --git a/test Project/test.als b/test Project/test.als new file mode 100644 index 0000000..e1a7137 Binary files /dev/null and b/test Project/test.als differ diff --git a/test.RPP b/test.RPP index 3ae1102..fc1dd24 100644 --- a/test.RPP +++ b/test.RPP @@ -1,105 +1,144 @@ - - - RENDER_FILE "" - RENDER_PATTERN "" - RENDER_FMT 0 2 0 - RENDER_1X 0 - RENDER_RANGE 1 0 0 18 1000 - RENDER_RESAMPLE 3 0 1 - RENDER_ADDTOPROJ 0 - RENDER_STEMS 0 - RENDER_DITHER 0 - TIMELOCKMODE 1 - TEMPOENVLOCKMODE 1 - ITEMMIX 0 - DEFPITCHMODE 589824 - TAKELANE 1 - SAMPLERATE 44100 0 0 - - LOCK 1 - - GLOBAL_AUTO -1 - TEMPO 120 4 4 - PLAYRATE 1 0 0.25 4 - SELECTION 0 0 - SELECTION2 0 0 - MASTERAUTOMODE 0 - MASTERTRACKHEIGHT 0 - MASTERPEAKCOL 16576 - MASTERMUTESOLO 0 - MASTERTRACKVIEW 0 0.6667 0.5 0.5 0 0 0 - MASTERHWOUT 0 0 1 0 0 0 0 -1 - MASTER_NCH 2 2 - MASTER_VOLUME 1 0 -1 -1 1 - MASTER_FX 1 - MASTER_SEL 0 - - FLOATPOS 0 0 0 0 - FXID {3568A34C-460C-D046-82F7-7D87378ABB20} - WAK 0 - > - - - -> + + + RENDER_FILE "" + RENDER_PATTERN "" + RENDER_FMT 0 2 0 + RENDER_1X 0 + RENDER_RANGE 1 0 0 18 1000 + RENDER_RESAMPLE 3 0 1 + RENDER_ADDTOPROJ 0 + RENDER_STEMS 0 + RENDER_DITHER 0 + TIMELOCKMODE 1 + TEMPOENVLOCKMODE 1 + ITEMMIX 0 + DEFPITCHMODE 589824 + TAKELANE 1 + SAMPLERATE 44100 0 0 + + LOCK 1 + + GLOBAL_AUTO -1 + TEMPO 120 4 4 + PLAYRATE 1 0 0.25 4 + SELECTION 0 0 + SELECTION2 0 0 + MASTERAUTOMODE 0 + MASTERTRACKHEIGHT 0 + MASTERPEAKCOL 16576 + MASTERMUTESOLO 0 + MASTERTRACKVIEW 0 0.6667 0.5 0.5 0 0 0 + MASTERHWOUT 0 0 1 0 0 0 0 -1 + MASTER_NCH 2 2 + MASTER_VOLUME 1 0 -1 -1 1 + MASTER_FX 1 + MASTER_SEL 0 + + FLOATPOS 0 0 0 0 + FXID {3568A34C-460C-D046-82F7-7D87378ABB20} + WAK 0 + > + + + + + FLOATPOS 0 0 0 0 + FXID {B7DD42FB-8D0E-C24C-924A-407EC4334EB7} + WAK 0 + > + > +>