mirror of
https://codeberg.org/armin/horizont.git
synced 2026-09-01 04:10:46 +02:00
update
This commit is contained in:
parent
ed28db30a3
commit
6c0d072465
19 changed files with 2212 additions and 0 deletions
314
Source/PluginProcessor.cpp
Normal file
314
Source/PluginProcessor.cpp
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
#include "PluginProcessor.h"
|
||||
|
||||
#include "PluginEditor.h"
|
||||
|
||||
HorizontAudioProcessor::HorizontAudioProcessor()
|
||||
: AudioProcessor (BusesProperties()
|
||||
.withInput ("Input", juce::AudioChannelSet::stereo(), true)
|
||||
.withOutput ("Output", juce::AudioChannelSet::stereo(), true)),
|
||||
apvts (*this, nullptr, "Parameters", createParameterLayout()),
|
||||
presets (getPresets())
|
||||
{
|
||||
lowCutParam = apvts.getRawParameterValue ("lowCut");
|
||||
highCutParam = apvts.getRawParameterValue ("highCut");
|
||||
decayParam = apvts.getRawParameterValue ("decay");
|
||||
sizeParam = apvts.getRawParameterValue ("size");
|
||||
diffusionParam = apvts.getRawParameterValue ("diffusion");
|
||||
brightnessParam = apvts.getRawParameterValue ("brightness");
|
||||
feedbackParam = apvts.getRawParameterValue ("feedback");
|
||||
pitchParam = apvts.getRawParameterValue ("pitch");
|
||||
dryWetParam = apvts.getRawParameterValue ("dryWet");
|
||||
}
|
||||
|
||||
HorizontAudioProcessor::~HorizontAudioProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
juce::AudioProcessorValueTreeState::ParameterLayout HorizontAudioProcessor::createParameterLayout()
|
||||
{
|
||||
juce::AudioProcessorValueTreeState::ParameterLayout layout;
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("lowCut", "Low Cut",
|
||||
juce::NormalisableRange<float> (20.0f, 500.0f, 0.0f, 0.35f), 40.0f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("highCut", "High Cut",
|
||||
juce::NormalisableRange<float> (800.0f, 20000.0f, 0.0f, 0.25f), 14000.0f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("decay", "Decay",
|
||||
juce::NormalisableRange<float> (0.2f, 10.0f, 0.0f, 0.5f), 3.5f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("size", "Size",
|
||||
juce::NormalisableRange<float> (0.4f, 2.0f, 0.0f, 0.5f), 1.0f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("diffusion", "Diffusion",
|
||||
juce::NormalisableRange<float> (0.0f, 1.0f, 0.0f), 0.6f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("brightness", "Brightness",
|
||||
juce::NormalisableRange<float> (0.0f, 1.0f, 0.0f), 0.75f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("feedback", "Feedback",
|
||||
juce::NormalisableRange<float> (0.0f, 1.0f, 0.0f), 0.6f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("pitch", "Pitch",
|
||||
juce::NormalisableRange<float> (-12.0f, 12.0f, 0.0f), 0.0f));
|
||||
|
||||
layout.add (std::make_unique<juce::AudioParameterFloat> ("dryWet", "Dry/Wet",
|
||||
juce::NormalisableRange<float> (0.0f, 1.0f, 0.0f), 0.35f));
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
|
||||
{
|
||||
wetScratch.resize ((size_t) juce::jmax (samplesPerBlock, 1));
|
||||
dryScratch.resize ((size_t) juce::jmax (samplesPerBlock, 1));
|
||||
wetFifo.reset();
|
||||
engine.prepare (sampleRate);
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::releaseResources()
|
||||
{
|
||||
engine.reset();
|
||||
}
|
||||
|
||||
bool HorizontAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
|
||||
{
|
||||
if (layouts.getMainOutputChannelSet().isDisabled())
|
||||
return false;
|
||||
|
||||
const int outCh = layouts.getMainOutputChannelSet().size();
|
||||
const int inCh = layouts.getMainInputChannelSet().size();
|
||||
|
||||
if (inCh == 0)
|
||||
return outCh <= 2;
|
||||
|
||||
return inCh <= 2 && outCh <= 2;
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::updateParameters()
|
||||
{
|
||||
engine.setLowCut (lowCutParam->load());
|
||||
engine.setHighCut (highCutParam->load());
|
||||
engine.setDecay (decayParam->load());
|
||||
engine.setSize (sizeParam->load());
|
||||
engine.setDiffusion (diffusionParam->load());
|
||||
engine.setBrightness (brightnessParam->load());
|
||||
engine.setFeedback (feedbackParam->load());
|
||||
engine.setPitch (pitchParam->load());
|
||||
engine.setDryWet (dryWetParam->load());
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer&)
|
||||
{
|
||||
juce::ScopedNoDenormals noDenormals;
|
||||
|
||||
const int numSamples = buffer.getNumSamples();
|
||||
if (numSamples == 0)
|
||||
return;
|
||||
|
||||
const int numOut = juce::jmin (buffer.getNumChannels(), 2);
|
||||
if (numOut == 0)
|
||||
return;
|
||||
|
||||
for (int ch = numOut; ch < buffer.getNumChannels(); ++ch)
|
||||
buffer.clear (ch, 0, numSamples);
|
||||
|
||||
updateParameters();
|
||||
|
||||
const int inputChannels = getChannelCountOfBus (true, 0);
|
||||
const bool haveLeft = buffer.getNumChannels() > 0 && inputChannels > 0;
|
||||
const bool haveRight = buffer.getNumChannels() > 1 && inputChannels > 1;
|
||||
const bool canCaptureWet = wetScratch.size() >= (size_t) numSamples;
|
||||
|
||||
for (int s = 0; s < numSamples; ++s)
|
||||
{
|
||||
const float inL = haveLeft ? buffer.getSample (0, s) : 0.0f;
|
||||
const float inR = haveRight ? buffer.getSample (1, s) : inL;
|
||||
|
||||
float outL = 0.0f;
|
||||
float outR = 0.0f;
|
||||
engine.processSample (inL, inR, outL, outR);
|
||||
|
||||
buffer.setSample (0, s, outL);
|
||||
if (numOut > 1)
|
||||
buffer.setSample (1, s, outR);
|
||||
|
||||
if (canCaptureWet)
|
||||
{
|
||||
wetScratch[(size_t) s] = engine.getLastWetL();
|
||||
dryScratch[(size_t) s] = inL;
|
||||
}
|
||||
}
|
||||
|
||||
if (canCaptureWet)
|
||||
{
|
||||
pushWetSamples (wetScratch.data(), numSamples);
|
||||
appendDrySamples (dryScratch.data(), numSamples);
|
||||
}
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::pushWetSamples (const float* src, int numToWrite)
|
||||
{
|
||||
if (numToWrite <= 0)
|
||||
return;
|
||||
|
||||
numToWrite = juce::jmin (numToWrite, wetFifo.getFreeSpace());
|
||||
if (numToWrite <= 0)
|
||||
return;
|
||||
|
||||
int i = 0;
|
||||
auto handle = wetFifo.write (numToWrite);
|
||||
handle.forEach ([&] (int idx) { wetRing.setSample (0, idx, src[i++]); });
|
||||
}
|
||||
|
||||
int HorizontAudioProcessor::readWetSamples (float* dest, int numToRead)
|
||||
{
|
||||
const int avail = wetFifo.getNumReady();
|
||||
if (avail <= 0)
|
||||
return 0;
|
||||
|
||||
numToRead = juce::jmin (numToRead, avail);
|
||||
|
||||
int i = 0;
|
||||
auto handle = wetFifo.read (numToRead);
|
||||
handle.forEach ([&] (int idx) { dest[i++] = wetRing.getSample (0, idx); });
|
||||
|
||||
return numToRead;
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::appendDrySamples (const float* src, int numToWrite)
|
||||
{
|
||||
if (numToWrite <= 0)
|
||||
return;
|
||||
|
||||
size_t w = dryWritePos.load (std::memory_order_relaxed);
|
||||
for (int i = 0; i < numToWrite; ++i)
|
||||
{
|
||||
dryRingLive[w] = src[i];
|
||||
w = (w + 1) % (size_t) dryRingSize;
|
||||
}
|
||||
dryWritePos.store (w, std::memory_order_release);
|
||||
dryTotalWritten.fetch_add ((size_t) numToWrite, std::memory_order_release);
|
||||
}
|
||||
|
||||
int HorizontAudioProcessor::copyRecentDrySamples (float* dest, int numToRead)
|
||||
{
|
||||
numToRead = juce::jmin (numToRead, dryRingSize);
|
||||
|
||||
const size_t written = dryTotalWritten.load (std::memory_order_acquire);
|
||||
const size_t wp = dryWritePos.load (std::memory_order_acquire);
|
||||
|
||||
if (written < (size_t) numToRead)
|
||||
{
|
||||
const int avail = (int) written;
|
||||
const int lead = numToRead - avail;
|
||||
std::fill (dest, dest + lead, 0.0f);
|
||||
for (int i = 0; i < avail; ++i)
|
||||
{
|
||||
const size_t idx = (wp + (size_t) dryRingSize - (size_t) avail + (size_t) i) % (size_t) dryRingSize;
|
||||
dest[lead + i] = dryRingLive[idx];
|
||||
}
|
||||
return numToRead;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numToRead; ++i)
|
||||
{
|
||||
const size_t idx = (wp + (size_t) dryRingSize - (size_t) numToRead + (size_t) i) % (size_t) dryRingSize;
|
||||
dest[i] = dryRingLive[idx];
|
||||
}
|
||||
|
||||
return numToRead;
|
||||
}
|
||||
|
||||
juce::AudioProcessorEditor* HorizontAudioProcessor::createEditor()
|
||||
{
|
||||
return new HorizontAudioProcessorEditor (*this, apvts);
|
||||
}
|
||||
|
||||
bool HorizontAudioProcessor::hasEditor() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const juce::String HorizontAudioProcessor::getName() const
|
||||
{
|
||||
return "Horizont";
|
||||
}
|
||||
|
||||
bool HorizontAudioProcessor::acceptsMidi() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HorizontAudioProcessor::producesMidi() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
double HorizontAudioProcessor::getTailLengthSeconds() const
|
||||
{
|
||||
return 10.0;
|
||||
}
|
||||
|
||||
int HorizontAudioProcessor::getNumPrograms()
|
||||
{
|
||||
return (int) presets.size();
|
||||
}
|
||||
|
||||
int HorizontAudioProcessor::getCurrentProgram()
|
||||
{
|
||||
return currentProgram;
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::setCurrentProgram (int index)
|
||||
{
|
||||
if (index >= 0 && index < (int) presets.size())
|
||||
{
|
||||
currentProgram = index;
|
||||
applyPreset (presets[(size_t) index]);
|
||||
}
|
||||
}
|
||||
|
||||
const juce::String HorizontAudioProcessor::getProgramName (int index)
|
||||
{
|
||||
if (index >= 0 && index < (int) presets.size())
|
||||
return presets[(size_t) index].name;
|
||||
|
||||
return "Default";
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::changeProgramName (int, const juce::String&)
|
||||
{
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::applyPreset (const Preset& preset)
|
||||
{
|
||||
for (const auto& v : preset.values)
|
||||
{
|
||||
if (auto* param = apvts.getParameter (v.id))
|
||||
param->setValueNotifyingHost (param->convertTo0to1 (v.value));
|
||||
}
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
|
||||
{
|
||||
auto state = apvts.copyState();
|
||||
std::unique_ptr<juce::XmlElement> xml (state.createXml());
|
||||
copyXmlToBinary (*xml, destData);
|
||||
}
|
||||
|
||||
void HorizontAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
|
||||
{
|
||||
std::unique_ptr<juce::XmlElement> xml (getXmlFromBinary (data, sizeInBytes));
|
||||
|
||||
if (xml != nullptr)
|
||||
apvts.replaceState (juce::ValueTree::fromXml (*xml));
|
||||
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
||||
{
|
||||
return new HorizontAudioProcessor();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue