sm-26/Source/PluginProcessor.cpp

163 lines
5.2 KiB
C++
Raw Normal View History

#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "BuildInfo_generated.h"
SM26AudioProcessor::SM26AudioProcessor()
: AudioProcessor (BusesProperties().withOutput ("Output", juce::AudioChannelSet::stereo(), true)),
apvts (*this, nullptr, "SM26State", {
std::make_unique<juce::AudioParameterFloat> ("k1", "Knob 1", juce::NormalisableRange<float>(0.f,1.f,0.001f), 0.5f),
std::make_unique<juce::AudioParameterFloat> ("k2", "Knob 2", juce::NormalisableRange<float>(0.f,1.f,0.001f), 0.5f),
std::make_unique<juce::AudioParameterFloat> ("k3", "Knob 3", juce::NormalisableRange<float>(0.f,1.f,0.001f), 0.5f),
std::make_unique<juce::AudioParameterFloat> ("k4", "Knob 4", juce::NormalisableRange<float>(0.f,1.f,0.001f), 0.5f),
std::make_unique<juce::AudioParameterInt> ("preset", "Preset",
0, sm26::PresetStore::count() - 1, 0)
})
{
engine.setPresetIndex (0);
apvts.addParameterListener ("k1", this);
apvts.addParameterListener ("k2", this);
apvts.addParameterListener ("k3", this);
apvts.addParameterListener ("k4", this);
apvts.addParameterListener ("preset", this);
paramsReady.store (true);
}
SM26AudioProcessor::~SM26AudioProcessor()
{
apvts.removeParameterListener ("k1", this);
apvts.removeParameterListener ("k2", this);
apvts.removeParameterListener ("k3", this);
apvts.removeParameterListener ("k4", this);
apvts.removeParameterListener ("preset", this);
}
void SM26AudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
engine.prepare (sampleRate, samplesPerBlock);
}
void SM26AudioProcessor::releaseResources() {}
void SM26AudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midi)
{
juce::ScopedNoDenormals noDenormals;
const int n = buffer.getNumSamples();
double bpm = 120.0;
bool playing = false;
if (auto* ph = getPlayHead())
{
auto pos = ph->getPosition();
if (pos.hasValue())
{
if (pos->getBpm().hasValue())
bpm = *pos->getBpm();
playing = pos->getIsPlaying();
}
}
for (int ch = 0; ch < buffer.getNumChannels(); ++ch)
buffer.clear (ch, 0, n);
engine.process (buffer, midi, n, bpm, playing);
}
juce::AudioProcessorEditor* SM26AudioProcessor::createEditor()
{
return new SM26AudioProcessorEditor (*this);
}
void SM26AudioProcessor::getStateInformation (juce::MemoryBlock& destData)
{
auto xmlStr = apvts.copyState().createXml()->toString();
destData.replaceAll (xmlStr.toRawUTF8(), (size_t) xmlStr.length());
}
void SM26AudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
auto xml = juce::XmlDocument::parse (juce::String::fromUTF8 ((const char*) data, sizeInBytes));
if (xml != nullptr)
{
auto tree = juce::ValueTree::fromXml (*xml);
if (tree.isValid())
{
paramsReady.store (false);
apvts.replaceState (tree);
paramsReady.store (true);
int idx = (int) *apvts.getRawParameterValue ("preset");
engine.setPresetIndex (idx);
applyPresetKnobs();
}
}
}
void SM26AudioProcessor::setKnob (int knob, float value01)
{
if (knob < 0 || knob >= 4) return;
auto* p = apvts.getParameter (juce::String ("k") + juce::String (knob + 1));
if (p != nullptr)
p->setValueNotifyingHost (p->convertTo0to1 (value01));
}
void SM26AudioProcessor::adjustParam (int paramId, float delta01)
{
float cur = engine.getParam (paramId);
engine.setParam (paramId, sm26::clamp01 (cur + delta01));
for (int k = 0; k < 4; ++k)
{
auto kv = engine.knobView (k);
if (kv.param == paramId)
{
float pval = engine.getParam (paramId);
float knobVal = sm26::clamp01 ((pval - kv.lo) / (kv.hi - kv.lo + 1e-9f));
setKnob (k, knobVal);
}
}
}
void SM26AudioProcessor::setPresetByIndex (int i)
{
auto* p = apvts.getParameter ("preset");
if (p != nullptr)
p->setValueNotifyingHost (p->convertTo0to1 ((float) i));
}
void SM26AudioProcessor::parameterChanged (const juce::String& parameterID, float newValue)
{
if (! paramsReady.load()) return;
if (parameterID == "preset")
{
int idx = (int) std::round (newValue * (float) (sm26::PresetStore::count() - 1));
idx = juce::jlimit (0, sm26::PresetStore::count() - 1, idx);
engine.setPresetIndex (idx);
applyPresetKnobs();
}
else if (parameterID == "k1" || parameterID == "k2" || parameterID == "k3" || parameterID == "k4")
{
int k = parameterID.getIntValue() - 1;
auto kv = engine.knobView (k);
float paramVal = sm26::clamp01 (kv.lo + newValue * (kv.hi - kv.lo));
engine.setParam (kv.param, paramVal);
}
}
void SM26AudioProcessor::applyPresetKnobs()
{
for (int k = 0; k < 4; ++k)
{
auto kv = engine.knobView (k);
float paramVal = engine.getParam (kv.param);
float knobVal = sm26::clamp01 ((paramVal - kv.lo) / (kv.hi - kv.lo + 1e-9f));
setKnob (k, knobVal);
}
}
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new SM26AudioProcessor();
}