vectorscope VST

This commit is contained in:
Boof2015
2026-05-27 19:22:22 -04:00
parent 434b65605a
commit 7da5f62c5e
9 changed files with 381 additions and 2 deletions
+3
View File
@@ -59,6 +59,8 @@ function(add_prism_scope TARGET PRODUCT PLUGIN_CODE SCOPE_DEFINE)
${PRISM_NATIVE_DIR}/oscilloscope.cpp
${PRISM_NATIVE_DIR}/vumeter.cpp
${PRISM_NATIVE_DIR}/lufsmeter.cpp
${PRISM_NATIVE_DIR}/vectorscope.cpp
${PRISM_NATIVE_DIR}/multiband.cpp
${PRISM_NATIVE_DIR}/dsp_utils.cpp)
target_include_directories(${TARGET} PRIVATE Source ${PRISM_NATIVE_DIR})
@@ -98,3 +100,4 @@ add_prism_scope(PrismSpectrum "Prism Spectrum" Pspc "")
add_prism_scope(PrismOscilloscope "Prism Oscilloscope" Posc "PRISM_SCOPE_OSCILLOSCOPE=1")
add_prism_scope(PrismVUMeter "Prism VU Meter" Pvum "PRISM_SCOPE_VUMETER=1")
add_prism_scope(PrismLUFSMeter "Prism Loudness Meter" Pluf "PRISM_SCOPE_LUFSMETER=1")
add_prism_scope(PrismVectorscope "Prism Vectorscope" Pvct "PRISM_SCOPE_VECTORSCOPE=1")
+4 -1
View File
@@ -3,6 +3,7 @@
#include "OscilloscopeEngine.h"
#include "VUMeterEngine.h"
#include "LUFSMeterEngine.h"
#include "VectorscopeEngine.h"
#include <cstring>
#if ! PRISM_USE_DEV_SERVER
@@ -20,7 +21,9 @@ namespace
std::unique_ptr<ScopeEngine> makeEngine()
{
#if defined(PRISM_SCOPE_LUFSMETER) && PRISM_SCOPE_LUFSMETER
#if defined(PRISM_SCOPE_VECTORSCOPE) && PRISM_SCOPE_VECTORSCOPE
return std::make_unique<VectorscopeEngine>();
#elif defined(PRISM_SCOPE_LUFSMETER) && PRISM_SCOPE_LUFSMETER
return std::make_unique<LUFSMeterEngine>();
#elif defined(PRISM_SCOPE_VUMETER) && PRISM_SCOPE_VUMETER
return std::make_unique<VUMeterEngine>();
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include "ScopeEngine.h"
#include "vectorscope.h" // reused, unmodified, from native/src
#include <vector>
/**
* Vectorscope engine. Pushes stereo audio into the reused `Visualizer::Vectorscope`
* (lowpass-filtered L/R + a 3-band split, both in circular buffers) and emits the
* most recent display points each frame. Two layouts share the buffers: the standard
* X/Y point cloud and the multiband (low/mid/high) cloud. Both buffers are kept warm
* so toggling is instant; the active layout (from the `multiband` setting) is flagged
* in the frame so the webview reads the right payload.
*/
class VectorscopeEngine : public ScopeEngine
{
public:
const char* scopeId() const override { return "vectorscope"; }
juce::Identifier frameEventId() const override { return frameId; }
void setSampleRate(double sampleRate) override
{
vec.setSampleRate((float) sampleRate);
}
void configure(const juce::var& settings) override
{
multiband = (bool) settings.getProperty("multiband", false);
}
void process(const float* left, const float* right, int numSamples) override
{
if (numSamples <= 0)
return;
vec.pushSamples(left, right, (size_t) numSamples);
vec.pushMultibandSamples(left, right, (size_t) numSamples);
}
juce::var buildFrame(double sampleRate) override
{
auto* obj = new juce::DynamicObject();
obj->setProperty("sampleRate", sampleRate);
obj->setProperty("multiband", multiband);
if (multiband)
{
constexpr size_t stride = Visualizer::MULTIBAND_POINT_STRIDE;
if (mbData.size() < (size_t) kDisplayPoints * stride)
mbData.resize((size_t) kDisplayPoints * stride);
const size_t count = vec.getMultibandPoints(mbData.data(), (size_t) kDisplayPoints);
obj->setProperty("count", (int) count);
obj->setProperty("data", juce::Base64::toBase64(mbData.data(), count * stride * sizeof(float)));
}
else
{
if (pointX.size() < (size_t) kDisplayPoints)
{
pointX.resize((size_t) kDisplayPoints);
pointY.resize((size_t) kDisplayPoints);
}
const size_t count = vec.getPoints(pointX.data(), pointY.data(), (size_t) kDisplayPoints);
obj->setProperty("count", (int) count);
obj->setProperty("x", juce::Base64::toBase64(pointX.data(), count * sizeof(float)));
obj->setProperty("y", juce::Base64::toBase64(pointY.data(), count * sizeof(float)));
}
return juce::var(obj);
}
private:
static constexpr int kDisplayPoints = 4096; // matches Vectorscope.ts default
const juce::Identifier frameId { "vectorscopeFrame" };
Visualizer::Vectorscope vec;
std::vector<float> pointX, pointY, mbData;
bool multiband = false;
};