2023-07-09 20:30:33 +00:00
|
|
|
#include "PitchDetector.h"
|
2023-09-01 22:42:17 +00:00
|
|
|
#include "../PluginProcessor.h"
|
2023-07-09 20:30:33 +00:00
|
|
|
|
2023-09-01 22:42:17 +00:00
|
|
|
PitchDetector::PitchDetector(OscirenderAudioProcessor& audioProcessor) : juce::Thread("PitchDetector"), audioProcessor(audioProcessor) {
|
2023-07-10 12:17:04 +00:00
|
|
|
startThread();
|
|
|
|
}
|
2023-07-09 20:30:33 +00:00
|
|
|
|
|
|
|
PitchDetector::~PitchDetector() {
|
2023-09-05 19:46:05 +00:00
|
|
|
audioProcessor.consumerStop(consumer);
|
2023-07-09 20:30:33 +00:00
|
|
|
stopThread(1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PitchDetector::run() {
|
|
|
|
while (!threadShouldExit()) {
|
2023-09-05 19:46:05 +00:00
|
|
|
consumer = audioProcessor.consumerRegister(buffer);
|
|
|
|
audioProcessor.consumerRead(consumer);
|
2023-07-09 20:30:33 +00:00
|
|
|
|
|
|
|
// buffer is for 2 channels, so we need to only use one
|
|
|
|
for (int i = 0; i < fftSize; i++) {
|
2023-09-01 22:42:17 +00:00
|
|
|
fftData[i] = buffer[2 * i];
|
2023-07-09 20:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
forwardFFT.performFrequencyOnlyForwardTransform(fftData.data());
|
|
|
|
|
|
|
|
// get frequency of the peak
|
|
|
|
int maxIndex = 0;
|
|
|
|
for (int i = 0; i < fftSize / 2; ++i) {
|
|
|
|
if (frequencyFromIndex(i) < 20 || frequencyFromIndex(i) > 20000) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto current = fftData[i];
|
|
|
|
if (current > fftData[maxIndex]) {
|
|
|
|
maxIndex = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
frequency = frequencyFromIndex(maxIndex);
|
|
|
|
triggerAsyncUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PitchDetector::handleAsyncUpdate() {
|
2023-07-13 19:11:24 +00:00
|
|
|
juce::SpinLock::ScopedLockType scope(lock);
|
|
|
|
for (auto& callback : callbacks) {
|
|
|
|
callback(frequency);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int PitchDetector::addCallback(std::function<void(float)> callback) {
|
|
|
|
juce::SpinLock::ScopedLockType scope(lock);
|
|
|
|
callbacks.push_back(callback);
|
|
|
|
return callbacks.size() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PitchDetector::removeCallback(int index) {
|
|
|
|
juce::SpinLock::ScopedLockType scope(lock);
|
|
|
|
callbacks.erase(callbacks.begin() + index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PitchDetector::setSampleRate(float sampleRate) {
|
|
|
|
this->sampleRate = sampleRate;
|
2023-07-09 20:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float PitchDetector::frequencyFromIndex(int index) {
|
2023-07-13 19:11:24 +00:00
|
|
|
auto binWidth = sampleRate / fftSize;
|
2023-07-09 20:30:33 +00:00
|
|
|
return index * binWidth;
|
|
|
|
}
|