mirror of
https://github.com/Boof2015/prism.git
synced 2026-08-12 13:20:53 +02:00
63ef5ffa0f
Add cross platform VSTs
100 lines
3.5 KiB
C++
100 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include "ScopeEngine.h"
|
|
#include "oscilloscope.h" // reused, unmodified, from native/src
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
class OscilloscopeEngine : public ScopeEngine
|
|
{
|
|
public:
|
|
const char* scopeId() const override { return "oscilloscope"; }
|
|
juce::Identifier frameEventId() const override { return frameId; }
|
|
PreferredSize preferredSize() const override { return { 760, 300, 320, 160 }; }
|
|
|
|
void setSampleRate(double sampleRate) override
|
|
{
|
|
osc.setSampleRate((float) sampleRate);
|
|
osc.setDisplaySamples(normalizedDisplaySamples(sampleRate));
|
|
}
|
|
|
|
void configure(const juce::var& settings) override
|
|
{
|
|
pitchLock = (bool) settings.getProperty("pitchLock", true);
|
|
osc.setPitchLock(pitchLock);
|
|
}
|
|
|
|
void process(const float* left, const float* right, int numSamples) override
|
|
{
|
|
if (numSamples <= 0)
|
|
return;
|
|
if ((int) mono.size() < numSamples)
|
|
mono.resize((size_t) numSamples);
|
|
for (int i = 0; i < numSamples; ++i)
|
|
mono[(size_t) i] = 0.5f * (left[i] + right[i]);
|
|
osc.pushSamples(mono.data(), (size_t) numSamples);
|
|
samplesSeen += numSamples;
|
|
}
|
|
|
|
juce::var buildFrame(double sampleRate) override
|
|
{
|
|
auto* obj = new juce::DynamicObject();
|
|
obj->setProperty("sampleRate", sampleRate);
|
|
obj->setProperty("pitch", 0.0);
|
|
|
|
// Pitch lock needs samples buffered before trigger detection is meaningful.
|
|
if (pitchLock && samplesSeen < kWarmupSamples)
|
|
{
|
|
obj->setProperty("samples", juce::String());
|
|
return juce::var(obj);
|
|
}
|
|
|
|
const auto result = osc.process();
|
|
const int samplesToShow = result.samplesToShow;
|
|
if (samplesToShow <= 1)
|
|
{
|
|
obj->setProperty("samples", juce::String());
|
|
return juce::var(obj);
|
|
}
|
|
|
|
float triggerIndex = result.triggerIndex;
|
|
if (! pitchLock)
|
|
{
|
|
// Free-run: show the most recent window ending at the write head.
|
|
const size_t writePos = osc.getWritePos();
|
|
triggerIndex = (float) ((writePos + Visualizer::OSCILLOSCOPE_BUFFER_SIZE - (size_t) samplesToShow)
|
|
% Visualizer::OSCILLOSCOPE_BUFFER_SIZE);
|
|
}
|
|
|
|
if ((int) window.size() != samplesToShow)
|
|
window.resize((size_t) samplesToShow);
|
|
osc.getSamplesInterpolated(window.data(), triggerIndex, (size_t) samplesToShow);
|
|
|
|
obj->setProperty("pitch", result.detectedPitch);
|
|
obj->setProperty("samples", juce::Base64::toBase64(window.data(), window.size() * sizeof(float)));
|
|
return juce::var(obj);
|
|
}
|
|
|
|
private:
|
|
// Mirrors getNormalizedOscilloscopeDisplaySamples in the renderer.
|
|
static int normalizedDisplaySamples(double sampleRate)
|
|
{
|
|
const double base = 2048.0, rateMin = 44100.0, rateMax = 48000.0;
|
|
double samples = base;
|
|
if (sampleRate > 0.0)
|
|
{
|
|
if (sampleRate < rateMin) samples = std::round(base * (sampleRate / rateMin));
|
|
else if (sampleRate > rateMax) samples = std::round(base * (sampleRate / rateMax));
|
|
}
|
|
return (int) std::clamp(samples, 64.0, 32767.0);
|
|
}
|
|
|
|
static constexpr long long kWarmupSamples = 4096;
|
|
const juce::Identifier frameId { "oscilloscopeFrame" };
|
|
Visualizer::Oscilloscope osc;
|
|
std::vector<float> mono, window;
|
|
bool pitchLock = true;
|
|
long long samplesSeen = 0;
|
|
};
|