kopia lustrzana https://github.com/jameshball/osci-render
310 wiersze
10 KiB
C++
310 wiersze
10 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file contains the basic framework code for a JUCE plugin processor.
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
#include "SosciPluginProcessor.h"
|
|
#include "SosciPluginEditor.h"
|
|
#include "audio/EffectParameter.h"
|
|
|
|
//==============================================================================
|
|
SosciAudioProcessor::SosciAudioProcessor()
|
|
#ifndef JucePlugin_PreferredChannelConfigurations
|
|
: AudioProcessor (BusesProperties().withInput("Input", juce::AudioChannelSet::stereo(), true)
|
|
.withInput("Brightness", juce::AudioChannelSet::mono(), true)
|
|
.withOutput("Output", juce::AudioChannelSet::stereo(), true))
|
|
#endif
|
|
{
|
|
// locking isn't necessary here because we are in the constructor
|
|
|
|
allEffects.push_back(parameters.brightnessEffect);
|
|
allEffects.push_back(parameters.intensityEffect);
|
|
allEffects.push_back(parameters.persistenceEffect);
|
|
allEffects.push_back(parameters.hueEffect);
|
|
allEffects.push_back(parameters.saturationEffect);
|
|
|
|
for (auto effect : allEffects) {
|
|
for (auto effectParameter : effect->parameters) {
|
|
auto parameters = effectParameter->getParameters();
|
|
for (auto parameter : parameters) {
|
|
addParameter(parameter);
|
|
}
|
|
}
|
|
}
|
|
|
|
booleanParameters.push_back(parameters.graticuleEnabled);
|
|
booleanParameters.push_back(parameters.smudgesEnabled);
|
|
booleanParameters.push_back(parameters.upsamplingEnabled);
|
|
booleanParameters.push_back(parameters.legacyVisualiserEnabled);
|
|
booleanParameters.push_back(parameters.visualiserFullScreen);
|
|
|
|
for (auto parameter : booleanParameters) {
|
|
addParameter(parameter);
|
|
}
|
|
|
|
for (auto parameter : floatParameters) {
|
|
addParameter(parameter);
|
|
}
|
|
|
|
for (auto parameter : intParameters) {
|
|
addParameter(parameter);
|
|
}
|
|
}
|
|
|
|
SosciAudioProcessor::~SosciAudioProcessor() {}
|
|
|
|
const juce::String SosciAudioProcessor::getName() const {
|
|
return JucePlugin_Name;
|
|
}
|
|
|
|
bool SosciAudioProcessor::acceptsMidi() const {
|
|
#if JucePlugin_WantsMidiInput
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool SosciAudioProcessor::producesMidi() const {
|
|
#if JucePlugin_ProducesMidiOutput
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool SosciAudioProcessor::isMidiEffect() const {
|
|
#if JucePlugin_IsMidiEffect
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
double SosciAudioProcessor::getTailLengthSeconds() const {
|
|
return 0.0;
|
|
}
|
|
|
|
int SosciAudioProcessor::getNumPrograms() {
|
|
return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
|
|
// so this should be at least 1, even if you're not really implementing programs.
|
|
}
|
|
|
|
int SosciAudioProcessor::getCurrentProgram() {
|
|
return 0;
|
|
}
|
|
|
|
void SosciAudioProcessor::setCurrentProgram(int index) {
|
|
}
|
|
|
|
const juce::String SosciAudioProcessor::getProgramName(int index) {
|
|
return {};
|
|
}
|
|
|
|
void SosciAudioProcessor::changeProgramName(int index, const juce::String& newName) {}
|
|
|
|
void SosciAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) {
|
|
currentSampleRate = sampleRate;
|
|
|
|
for (auto& effect : allEffects) {
|
|
effect->updateSampleRate(currentSampleRate);
|
|
}
|
|
}
|
|
|
|
void SosciAudioProcessor::releaseResources() {
|
|
// When playback stops, you can use this as an opportunity to free up any
|
|
// spare memory, etc.
|
|
}
|
|
|
|
bool SosciAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const {
|
|
auto numIns = layouts.getMainInputChannels();
|
|
auto numOuts = layouts.getMainOutputChannels();
|
|
|
|
return numIns >= 2 && numOuts >= 2;
|
|
}
|
|
|
|
// effectsLock should be held when calling this
|
|
std::shared_ptr<Effect> SosciAudioProcessor::getEffect(juce::String id) {
|
|
for (auto& effect : allEffects) {
|
|
if (effect->getId() == id) {
|
|
return effect;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// effectsLock should be held when calling this
|
|
BooleanParameter* SosciAudioProcessor::getBooleanParameter(juce::String id) {
|
|
for (auto& parameter : booleanParameters) {
|
|
if (parameter->paramID == id) {
|
|
return parameter;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// effectsLock should be held when calling this
|
|
FloatParameter* SosciAudioProcessor::getFloatParameter(juce::String id) {
|
|
for (auto& parameter : floatParameters) {
|
|
if (parameter->paramID == id) {
|
|
return parameter;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// effectsLock should be held when calling this
|
|
IntParameter* SosciAudioProcessor::getIntParameter(juce::String id) {
|
|
for (auto& parameter : intParameters) {
|
|
if (parameter->paramID == id) {
|
|
return parameter;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void SosciAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) {
|
|
juce::ScopedNoDenormals noDenormals;
|
|
|
|
auto input = getBusBuffer(buffer, true, 0);
|
|
auto brightness = getBusBuffer(buffer, true, 1);
|
|
|
|
midiMessages.clear();
|
|
|
|
auto inputArray = input.getArrayOfWritePointers();
|
|
auto brightnessArray = brightness.getArrayOfWritePointers();
|
|
|
|
for (int sample = 0; sample < input.getNumSamples(); ++sample) {
|
|
juce::SpinLock::ScopedLockType scope(consumerLock);
|
|
|
|
float x = input.getNumChannels() > 0 ? inputArray[0][sample] : 0.0f;
|
|
float y = input.getNumChannels() > 1 ? inputArray[1][sample] : 0.0f;
|
|
float z = brightness.getNumChannels() > 0 ? brightnessArray[0][sample] : 1.0f;
|
|
|
|
Point point = { x, y, z };
|
|
|
|
for (auto& effect : allEffects) {
|
|
point = effect->apply(sample, point);
|
|
}
|
|
|
|
for (auto consumer : consumers) {
|
|
consumer->write(point);
|
|
consumer->notifyIfFull();
|
|
}
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
bool SosciAudioProcessor::hasEditor() const {
|
|
return true; // (change this to false if you choose to not supply an editor)
|
|
}
|
|
|
|
juce::AudioProcessorEditor* SosciAudioProcessor::createEditor() {
|
|
auto editor = new SosciPluginEditor(*this);
|
|
return editor;
|
|
}
|
|
|
|
//==============================================================================
|
|
void SosciAudioProcessor::getStateInformation(juce::MemoryBlock& destData) {
|
|
juce::SpinLock::ScopedLockType lock2(effectsLock);
|
|
|
|
std::unique_ptr<juce::XmlElement> xml = std::make_unique<juce::XmlElement>("project");
|
|
xml->setAttribute("version", ProjectInfo::versionString);
|
|
auto effectsXml = xml->createNewChildElement("effects");
|
|
for (auto effect : allEffects) {
|
|
effect->save(effectsXml->createNewChildElement("effect"));
|
|
}
|
|
|
|
auto booleanParametersXml = xml->createNewChildElement("booleanParameters");
|
|
for (auto parameter : booleanParameters) {
|
|
auto parameterXml = booleanParametersXml->createNewChildElement("parameter");
|
|
parameter->save(parameterXml);
|
|
}
|
|
|
|
auto floatParametersXml = xml->createNewChildElement("floatParameters");
|
|
for (auto parameter : floatParameters) {
|
|
auto parameterXml = floatParametersXml->createNewChildElement("parameter");
|
|
parameter->save(parameterXml);
|
|
}
|
|
|
|
auto intParametersXml = xml->createNewChildElement("intParameters");
|
|
for (auto parameter : intParameters) {
|
|
auto parameterXml = intParametersXml->createNewChildElement("parameter");
|
|
parameter->save(parameterXml);
|
|
}
|
|
|
|
copyXmlToBinary(*xml, destData);
|
|
}
|
|
|
|
void SosciAudioProcessor::setStateInformation(const void* data, int sizeInBytes) {
|
|
std::unique_ptr<juce::XmlElement> xml;
|
|
|
|
const uint32_t magicXmlNumber = 0x21324356;
|
|
if (sizeInBytes > 8 && juce::ByteOrder::littleEndianInt(data) == magicXmlNumber) {
|
|
// this is a binary xml format
|
|
xml = getXmlFromBinary(data, sizeInBytes);
|
|
} else {
|
|
// this is a text xml format
|
|
xml = juce::XmlDocument::parse(juce::String((const char*)data, sizeInBytes));
|
|
}
|
|
|
|
if (xml.get() != nullptr && xml->hasTagName("project")) {
|
|
juce::SpinLock::ScopedLockType lock2(effectsLock);
|
|
|
|
auto effectsXml = xml->getChildByName("effects");
|
|
if (effectsXml != nullptr) {
|
|
for (auto effectXml : effectsXml->getChildIterator()) {
|
|
auto effect = getEffect(effectXml->getStringAttribute("id"));
|
|
if (effect != nullptr) {
|
|
effect->load(effectXml);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto booleanParametersXml = xml->getChildByName("booleanParameters");
|
|
if (booleanParametersXml != nullptr) {
|
|
for (auto parameterXml : booleanParametersXml->getChildIterator()) {
|
|
auto parameter = getBooleanParameter(parameterXml->getStringAttribute("id"));
|
|
if (parameter != nullptr) {
|
|
parameter->load(parameterXml);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto floatParametersXml = xml->getChildByName("floatParameters");
|
|
if (floatParametersXml != nullptr) {
|
|
for (auto parameterXml : floatParametersXml->getChildIterator()) {
|
|
auto parameter = getFloatParameter(parameterXml->getStringAttribute("id"));
|
|
if (parameter != nullptr) {
|
|
parameter->load(parameterXml);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto intParametersXml = xml->getChildByName("intParameters");
|
|
if (intParametersXml != nullptr) {
|
|
for (auto parameterXml : intParametersXml->getChildIterator()) {
|
|
auto parameter = getIntParameter(parameterXml->getStringAttribute("id"));
|
|
if (parameter != nullptr) {
|
|
parameter->load(parameterXml);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
double SosciAudioProcessor::getSampleRate() {
|
|
return currentSampleRate;
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// This creates new instances of the plugin..
|
|
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
|
{
|
|
return new SosciAudioProcessor();
|
|
}
|