mirror of
https://github.com/Boof2015/prism.git
synced 2026-08-12 05:10:51 +02:00
waveform VST
This commit is contained in:
@@ -62,6 +62,7 @@ function(add_prism_scope TARGET PRODUCT PLUGIN_CODE SCOPE_DEFINE)
|
||||
${PRISM_NATIVE_DIR}/vectorscope.cpp
|
||||
${PRISM_NATIVE_DIR}/multiband.cpp
|
||||
${PRISM_NATIVE_DIR}/spectrogram.cpp
|
||||
${PRISM_NATIVE_DIR}/waveform.cpp
|
||||
${PRISM_NATIVE_DIR}/dsp_utils.cpp)
|
||||
|
||||
target_include_directories(${TARGET} PRIVATE Source ${PRISM_NATIVE_DIR})
|
||||
@@ -103,3 +104,4 @@ add_prism_scope(PrismVUMeter "Prism VU Meter" Pvum "PRISM_SCOPE_VUMETER
|
||||
add_prism_scope(PrismLUFSMeter "Prism Loudness Meter" Pluf "PRISM_SCOPE_LUFSMETER=1")
|
||||
add_prism_scope(PrismVectorscope "Prism Vectorscope" Pvct "PRISM_SCOPE_VECTORSCOPE=1")
|
||||
add_prism_scope(PrismSpectrogram "Prism Spectrogram" Pspg "PRISM_SCOPE_SPECTROGRAM=1")
|
||||
add_prism_scope(PrismWaveform "Prism Waveform" Pwav "PRISM_SCOPE_WAVEFORM=1")
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "LUFSMeterEngine.h"
|
||||
#include "VectorscopeEngine.h"
|
||||
#include "SpectrogramEngine.h"
|
||||
#include "WaveformEngine.h"
|
||||
#include <cstring>
|
||||
|
||||
#if ! PRISM_USE_DEV_SERVER
|
||||
@@ -22,7 +23,9 @@ namespace
|
||||
|
||||
std::unique_ptr<ScopeEngine> makeEngine()
|
||||
{
|
||||
#if defined(PRISM_SCOPE_SPECTROGRAM) && PRISM_SCOPE_SPECTROGRAM
|
||||
#if defined(PRISM_SCOPE_WAVEFORM) && PRISM_SCOPE_WAVEFORM
|
||||
return std::make_unique<WaveformEngine>();
|
||||
#elif defined(PRISM_SCOPE_SPECTROGRAM) && PRISM_SCOPE_SPECTROGRAM
|
||||
return std::make_unique<SpectrogramEngine>();
|
||||
#elif defined(PRISM_SCOPE_VECTORSCOPE) && PRISM_SCOPE_VECTORSCOPE
|
||||
return std::make_unique<VectorscopeEngine>();
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include "ScopeEngine.h"
|
||||
#include "waveform.h" // reused, unmodified, from native/src
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* Waveform engine. Runs the reused Visualizer::WaveformMultibandAnalyzer, which
|
||||
* summarizes audio into per-column min/max + 3-band RMS. Unlike the spectrogram, the
|
||||
* column width (samplesPerColumn) is a pure function of sampleRate and scrollSpeed —
|
||||
* sampleRate / (128 * scrollSpeed), the same formula the renderer uses — so the engine
|
||||
* derives it itself; no canvas round-trip. mode ('stereo' vs 'mono') selects
|
||||
* processStereo (stride 10) vs processMono (stride 5), flagged in the frame. multiband
|
||||
* is render-only (the analyzer always emits the band RMS columns use for coloring).
|
||||
*/
|
||||
class WaveformEngine : public ScopeEngine
|
||||
{
|
||||
public:
|
||||
WaveformEngine() { reconfigure(); }
|
||||
|
||||
const char* scopeId() const override { return "waveform"; }
|
||||
juce::Identifier frameEventId() const override { return frameId; }
|
||||
|
||||
void setSampleRate(double sr) override
|
||||
{
|
||||
if (sr > 0.0 && (float) sr != sampleRate)
|
||||
{
|
||||
sampleRate = (float) sr;
|
||||
reconfigure();
|
||||
}
|
||||
}
|
||||
|
||||
void configure(const juce::var& settings) override
|
||||
{
|
||||
stereo = settings.getProperty("mode", "mono").toString() == "stereo";
|
||||
const auto speed = (float) settings.getProperty("scrollSpeed", (double) scrollSpeed);
|
||||
if (speed > 0.0f)
|
||||
scrollSpeed = speed;
|
||||
reconfigure();
|
||||
}
|
||||
|
||||
void process(const float* left, const float* right, int numSamples) override
|
||||
{
|
||||
if (numSamples <= 0)
|
||||
return;
|
||||
|
||||
if (stereo)
|
||||
{
|
||||
const auto& cols = wave.processStereo(left, right, (size_t) numSamples);
|
||||
pending.insert(pending.end(), cols.begin(), cols.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
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]);
|
||||
const auto& cols = wave.processMono(mono.data(), (size_t) numSamples);
|
||||
pending.insert(pending.end(), cols.begin(), cols.end());
|
||||
}
|
||||
}
|
||||
|
||||
juce::var buildFrame(double sr) override
|
||||
{
|
||||
const size_t stride = stereo ? Visualizer::WAVEFORM_STEREO_SUMMARY_STRIDE
|
||||
: Visualizer::WAVEFORM_MONO_SUMMARY_STRIDE;
|
||||
auto* obj = new juce::DynamicObject();
|
||||
obj->setProperty("sampleRate", sr);
|
||||
obj->setProperty("stereo", stereo);
|
||||
obj->setProperty("columnCount", (int) (pending.size() / stride));
|
||||
if (! pending.empty())
|
||||
obj->setProperty("summaries", juce::Base64::toBase64(pending.data(), pending.size() * sizeof(float)));
|
||||
else
|
||||
obj->setProperty("summaries", juce::String());
|
||||
pending.clear();
|
||||
return juce::var(obj);
|
||||
}
|
||||
|
||||
private:
|
||||
void reconfigure()
|
||||
{
|
||||
const float pps = 128.0f * std::max(0.01f, scrollSpeed);
|
||||
samplesPerColumn = (size_t) std::max(1L, std::lround(sampleRate / pps));
|
||||
wave.configure(sampleRate, samplesPerColumn);
|
||||
pending.clear();
|
||||
}
|
||||
|
||||
const juce::Identifier frameId { "waveformFrame" };
|
||||
Visualizer::WaveformMultibandAnalyzer wave;
|
||||
std::vector<float> mono, pending;
|
||||
float sampleRate = 48000.0f;
|
||||
float scrollSpeed = 1.0f;
|
||||
size_t samplesPerColumn = 1;
|
||||
bool stereo = false;
|
||||
};
|
||||
Reference in New Issue
Block a user