beamgrid/Source/PluginProcessor.cpp
Armin aeb4b83281 Add BOOST, 3D depth, and gradient-angle knobs
- BOOST: global display level multiplier (0.75 - 2.5, 1.0 default)
- 3D: pseudo-3D bevel/shading on bars, LEDs, peaks and curve (0 = flat)
- G-ANG: 3D gradient angle (-180 - 180, 0 = top-lit)
- Apply CURVING rounded corners to bars and peaks in BAR mode
2026-08-14 03:38:09 +02:00

192 lines
7.5 KiB
C++

#include "PluginProcessor.h"
#include "PluginEditor.h"
BeamgridAudioProcessor::BeamgridAudioProcessor()
: AudioProcessor (BusesProperties()
.withInput ("Input", juce::AudioChannelSet::stereo(), true)
.withOutput ("Output", juce::AudioChannelSet::stereo(), true)),
params (*this, nullptr, "Parameters", createParameterLayout())
{
}
BeamgridAudioProcessor::~BeamgridAudioProcessor() = default;
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new BeamgridAudioProcessor();
}
juce::AudioProcessorValueTreeState::ParameterLayout
BeamgridAudioProcessor::createParameterLayout()
{
std::vector<std::unique_ptr<juce::RangedAudioParameter>> params;
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"grace", "Peak Grace (ms)",
juce::NormalisableRange<float> (0.0f, 2000.0f, 1.0f), 800.0f,
juce::AudioParameterFloatAttributes().withLabel ("ms")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"falloff", "Peak Falloff",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.4f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"barfalloff", "Bar Falloff",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.5f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"hue", "Hue",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.5f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"smooth", "Smoothing",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.35f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"grid", "Grid Visibility",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.32f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"gridzoom", "Grid Zoom",
juce::NormalisableRange<float> (0.98f, 1.02f, 0.001f), 1.0f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"gridfade", "Grid Fade",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.0f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"curving", "Curving",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.0f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"tilt", "Tilt",
juce::NormalisableRange<float> (-1.0f, 1.0f, 0.001f), 0.0f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"boost", "Boost",
juce::NormalisableRange<float> (0.75f, 2.5f, 0.001f), 1.0f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"depth3d", "3D",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f), 0.0f,
juce::AudioParameterFloatAttributes().withLabel ("")));
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"gradangle", "Gradient Angle",
juce::NormalisableRange<float> (-180.0f, 180.0f, 0.5f), 0.0f,
juce::AudioParameterFloatAttributes().withLabel ("")));
juce::NormalisableRange<float> barsRange (8.0f, 128.0f,
[] (float start, float end, float v) { return start + v * (end - start); }, // convertFrom0To1
[] (float start, float end, float v) { return (v - start) / (end - start); }, // convertTo0To1
[] (float, float, float v) // snapToLegalValue
{
const float steps[] = { 8.0f, 16.0f, 24.0f, 32.0f, 40.0f, 48.0f, 56.0f, 64.0f,
72.0f, 80.0f, 88.0f, 96.0f, 104.0f, 112.0f, 120.0f, 128.0f };
float best = steps[0];
float bestDist = std::abs (v - best);
for (float s : steps)
{
const float dist = std::abs (v - s);
if (dist < bestDist)
{
bestDist = dist;
best = s;
}
}
return best;
});
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"bars", "Bars", barsRange, 64.0f));
params.push_back (std::make_unique<juce::AudioParameterInt>(
"mode", "Mode", 1, 3, 1));
juce::NormalisableRange<float> ledsRange (4.0f, 48.0f,
[] (float start, float end, float v) { return start + v * (end - start); }, // convertFrom0To1
[] (float start, float end, float v) { return (v - start) / (end - start); }, // convertTo0To1
[] (float, float, float v) // snapToLegalValue
{
const float steps[] = { 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f,
28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f };
float best = steps[0];
float bestDist = std::abs (v - best);
for (float s : steps)
{
const float dist = std::abs (v - s);
if (dist < bestDist)
{
bestDist = dist;
best = s;
}
}
return best;
});
params.push_back (std::make_unique<juce::AudioParameterFloat>(
"leds", "LEDs/Bar", ledsRange, 16.0f));
return { params.begin(), params.end() };
}
void BeamgridAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
analyser.prepare (sampleRate, samplesPerBlock);
}
void BeamgridAudioProcessor::releaseResources() {}
bool BeamgridAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
if (layouts.getMainInputChannels() == 0 ||
layouts.getMainOutputChannels() == 0)
return false;
if (layouts.getMainInputChannels() != layouts.getMainOutputChannels())
return false;
return true;
}
void BeamgridAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer,
juce::MidiBuffer& /*midi*/)
{
juce::ScopedNoDenormals noDenormals;
analyser.setTilt (*params.getRawParameterValue ("tilt"));
analyser.setBoost (*params.getRawParameterValue ("boost"));
// Analyse the first channel; pass the audio through unchanged.
if (buffer.getNumChannels() > 0)
analyser.push (buffer.getReadPointer (0), buffer.getNumSamples());
}
juce::AudioProcessorEditor* BeamgridAudioProcessor::createEditor()
{
return new BeamgridAudioProcessorEditor (*this);
}
void BeamgridAudioProcessor::getStateInformation (juce::MemoryBlock& dest)
{
auto state = params.copyState();
std::unique_ptr<juce::XmlElement> xml (state.createXml());
copyXmlToBinary (*xml, dest);
}
void BeamgridAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
std::unique_ptr<juce::XmlElement> xml (getXmlFromBinary (data, sizeInBytes));
if (xml && xml->hasTagName (params.state.getType()))
params.replaceState (juce::ValueTree::fromXml (*xml));
}