diff --git a/RNBO_JuceAudioProcessor.cpp b/RNBO_JuceAudioProcessor.cpp index 0357fc4..7b62baf 100644 --- a/RNBO_JuceAudioProcessor.cpp +++ b/RNBO_JuceAudioProcessor.cpp @@ -11,6 +11,7 @@ #include "RNBO_JuceAudioProcessor.h" #include "RNBO_JuceAudioProcessorEditor.h" #include "RNBO_JuceAudioProcessorUtils.h" +#include "RNBO_Presets.h" #include #include #include @@ -110,9 +111,11 @@ JuceAudioProcessor::JuceAudioProcessor( #endif ) , Thread("fileLoadAndDealloc") - , _syncEventHandler(*this) - , _currentPresetIdx(-1) + , _currentPresetIdx(0) { + // XXX using the "NotThreadSafe" interface for parameters so that they get updated immediately after a setPresetSync + _parameterInterface = _rnboObject.createParameterInterface(ParameterEventInterface::NotThreadSafe, nullptr); + _dataRefCleanupQueue = make_unique>(static_cast(32)); _dataRefLoadQueue = make_unique, 32>>(static_cast(32)); @@ -137,7 +140,7 @@ JuceAudioProcessor::JuceAudioProcessor( int juceIndex = 0; for (ParameterIndex i = 0; i < _rnboObject.getNumParameters(); i++) { //create can return nullptr - juce::AudioProcessorParameter * p = paramFactory->create(_rnboObject, i); + juce::AudioProcessorParameter * p = paramFactory->create(_rnboObject, _parameterInterface.get(), i); if (p) { _rnboParamIndexToJuceParamIndex.insert({i, juceIndex++}); addParameter(p); @@ -162,7 +165,8 @@ JuceAudioProcessor::JuceAudioProcessor( } } - _syncParamInterface = _rnboObject.createParameterInterface(ParameterEventInterface::NotThreadSafe, &_syncEventHandler); + //save initial preset + _initialPreset = _rnboObject.getPresetSync(); //Read presets try { @@ -228,6 +232,11 @@ const juce::String JuceAudioProcessor::getName() const void JuceAudioProcessor::handleParameterEvent(const ParameterEvent& event) { + // filter out startup events + if (_isInStartup) { + return; + } + // Engine might have parameters than aren't exposed to JUCE // so we need to filter out any parameter events that are not in our _rnboParamIndexToJuceParamIndex auto it = _rnboParamIndexToJuceParamIndex.find(event.getIndex()); @@ -235,13 +244,16 @@ void JuceAudioProcessor::handleParameterEvent(const ParameterEvent& event) // we need to normalize the parameter value ParameterValue normalizedValue = _rnboObject.convertToNormalizedParameterValue(event.getIndex(), event.getValue()); const auto param = getParameters()[it->second]; - if (_isInStartup || _isSettingPresetAsync) { - param->setValue((float)normalizedValue); - } - else if (_notifyingParameters.count(event.getIndex()) != 0) { + + if (_isSettingPresetAsync || _notifyingParameters.count(event.getIndex()) != 0) { + //using "internal" method to simply notify listeners +#if RNBO_JUCE_PARAM_EVENT_NOTIFY_ONLY + param->sendValueChangedMessageToListeners((float)normalizedValue); +#else param->beginChangeGesture(); param->setValueNotifyingHost((float)normalizedValue); param->endChangeGesture(); +#endif } } } @@ -400,7 +412,7 @@ int JuceAudioProcessor::getNumPrograms() if (!_presetList) { return 1; } else { - return (int) _presetList->size(); + return (int) _presetList->size() + 1; //add "initial" } } @@ -413,19 +425,27 @@ void JuceAudioProcessor::setCurrentProgram (int index) { if (_presetList) { _currentPresetIdx = index; - if (index >= 0) { - UniquePresetPtr preset = _presetList->presetAtIndex(static_cast(index)); - _rnboObject.setPreset(std::move(preset)); - } + UniquePresetPtr preset; + if (index == 0 && _initialPreset) { + preset = make_unique(); + RNBO::copyPreset(*_initialPreset, *preset); + } else if (index > 0) { + preset = _presetList->presetAtIndex(static_cast(index - 1)); + } + if (preset) { + _rnboObject.setPreset(std::move(preset)); + } } } const juce::String JuceAudioProcessor::getProgramName (int index) { - if (!_presetList) { + if (!_presetList || index < 0) { return juce::String(); + } else if (index == 0) { + return juce::String("inital"); } else { - std::string name = _presetList->presetNameAtIndex((size_t)index); + std::string name = _presetList->presetNameAtIndex((size_t)index - 1); return juce::String(name); } } @@ -575,31 +595,23 @@ void JuceAudioProcessor::setStateInformation (const void* data, int sizeInBytes) String rnboPresetStr = String::createStringFromData (data, sizeInBytes); auto rnboPreset = RNBO::convertJSONToPreset(rnboPresetStr.toStdString()); _rnboObject.setPresetSync(std::move(rnboPreset)); -} -void JuceAudioProcessor::eventsAvailable() -{ - this->triggerAsyncUpdate(); -} - -void JuceAudioProcessor::SyncEventHandler::handleParameterEvent(const RNBO::ParameterEvent& event) -{ - if (_isSettingPresetSync) { - _owner.handleParameterEvent(event); + // notify changes + for (auto& kv: _rnboParamIndexToJuceParamIndex) { + auto index = kv.first; + auto param = getParameters()[kv.second]; + if (param) { + float value = static_cast(_parameterInterface->getParameterNormalized(index)); + param->sendValueChangedMessageToListeners(value); + } } } -void JuceAudioProcessor::SyncEventHandler::handlePresetEvent(const PresetEvent& event) +void JuceAudioProcessor::eventsAvailable() { - if (event.getType() == PresetEvent::SettingBegin) { - _isSettingPresetSync = true; - } - else if (event.getType() == PresetEvent::SettingEnd) { - _isSettingPresetSync = false; - } + this->triggerAsyncUpdate(); } - JuceAudioParameterFactory::JuceAudioParameterFactory( const nlohmann::json& patcherdesc ) @@ -625,7 +637,7 @@ JuceAudioParameterFactory::JuceAudioParameterFactory( } } -AudioProcessorParameter* JuceAudioParameterFactory::create(RNBO::CoreObject& rnboObject, ParameterIndex index) { +AudioProcessorParameter* JuceAudioParameterFactory::create(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index) { ParameterInfo info; rnboObject.getParameterInfo(index, &info); @@ -648,23 +660,23 @@ AudioProcessorParameter* JuceAudioParameterFactory::create(RNBO::CoreObject& rnb versionHint = meta[vkey].get(); } } - return create(rnboObject, index, info, versionHint, meta); + return create(rnboObject, parameterInterface, index, info, versionHint, meta); } -juce::AudioProcessorParameter* JuceAudioParameterFactory::create(RNBO::CoreObject& rnboObject, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta) { +juce::AudioProcessorParameter* JuceAudioParameterFactory::create(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta) { if (info.enumValues && info.steps > 0) { - return createEnum(rnboObject, index, info, versionHint, meta); + return createEnum(rnboObject, parameterInterface, index, info, versionHint, meta); } else { - return createFloat(rnboObject, index, info, versionHint, meta); + return createFloat(rnboObject, parameterInterface, index, info, versionHint, meta); } } -AudioProcessorParameter* JuceAudioParameterFactory::createEnum(RNBO::CoreObject& rnboObject, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta) { - return new EnumParameter(index, info, rnboObject, versionHint, automate(meta)); +AudioProcessorParameter* JuceAudioParameterFactory::createEnum(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta) { + return new EnumParameter(index, info, rnboObject, parameterInterface, versionHint, automate(meta)); } -AudioProcessorParameter* JuceAudioParameterFactory::createFloat(RNBO::CoreObject& rnboObject, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta) { - return new FloatParameter(index, info, rnboObject, versionHint, automate(meta)); +AudioProcessorParameter* JuceAudioParameterFactory::createFloat(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta) { + return new FloatParameter(index, info, rnboObject, parameterInterface, versionHint, automate(meta)); } bool JuceAudioParameterFactory::automate(const nlohmann::json& meta) { diff --git a/RNBO_JuceAudioProcessor.h b/RNBO_JuceAudioProcessor.h index ffdcc66..bd8ca8d 100644 --- a/RNBO_JuceAudioProcessor.h +++ b/RNBO_JuceAudioProcessor.h @@ -22,6 +22,9 @@ #include #include +// param events coming out of event handlers simply notify listeners, don't actually call setValue on param +#define RNBO_JUCE_PARAM_EVENT_NOTIFY_ONLY 1 + namespace moodycamel { template class ReaderWriterQueue; @@ -50,15 +53,15 @@ namespace RNBO { virtual ~JuceAudioParameterFactory() = default; //entrypoint, may return null - juce::AudioProcessorParameter* create(RNBO::CoreObject& rnboObject, ParameterIndex index); + juce::AudioProcessorParameter* create(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index); protected: //overrideable entrypoint - virtual juce::AudioProcessorParameter* create(RNBO::CoreObject& rnboObject, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta); + virtual juce::AudioProcessorParameter* create(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta); //called by create if appropriate - virtual juce::AudioProcessorParameter* createEnum(RNBO::CoreObject& rnboObject, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta); - virtual juce::AudioProcessorParameter* createFloat(RNBO::CoreObject& rnboObject, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta); + virtual juce::AudioProcessorParameter* createEnum(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta); + virtual juce::AudioProcessorParameter* createFloat(RNBO::CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, ParameterIndex index, const ParameterInfo& info, int versionHint, const nlohmann::json& meta); bool automate(const nlohmann::json& meta); @@ -146,31 +149,15 @@ namespace RNBO { TimeConverter preProcess(juce::MidiBuffer& midiMessages); void postProcess(TimeConverter& timeConverter, juce::MidiBuffer& midiMessages); - class SyncEventHandler : public RNBO::EventHandler - { - public: - SyncEventHandler(JuceAudioProcessor& owner) - : _owner(owner) - {} - - void eventsAvailable() override {} - - void handleParameterEvent(const RNBO::ParameterEvent& event) override; - void handlePresetEvent(const RNBO::PresetEvent& event) override; - - private: - bool _isSettingPresetSync = false; - JuceAudioProcessor& _owner; - }; - //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAudioProcessor) + RNBO::ParameterEventInterfaceUniquePtr _parameterInterface; + RNBO::MidiEventList _midiInput; RNBO::MidiEventList _midiOutput; std::unique_ptr _presetList; - SyncEventHandler _syncEventHandler; - RNBO::ParameterEventInterfaceUniquePtr _syncParamInterface; + RNBO::ConstPresetPtr _initialPreset; int _currentPresetIdx; bool _isInStartup = false; bool _isSettingPresetAsync = false; @@ -197,6 +184,7 @@ namespace RNBO { std::unique_ptr> _dataRefCleanupQueue; std::unique_ptr, 32>> _dataRefLoadQueue; + }; class DataRefUpdatedMessage : public juce::Message { @@ -215,14 +203,14 @@ namespace RNBO { using String = juce::String; public: - FloatParameter (ParameterIndex index, const ParameterInfo& info, CoreObject& rnboObject, int versionHint = 0, bool automatable = true) + FloatParameter (ParameterIndex index, const ParameterInfo& info, CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, int versionHint = 0, bool automatable = true) : juce::RangedAudioParameter( paramIdForRNBOParam(rnboObject, index, versionHint), String(rnboObject.getParameterName(index)) ) , _index(index) - , _rnboObject(rnboObject) + , _parameterInterface(parameterInterface) , _automatable(automatable) { @@ -232,10 +220,10 @@ namespace RNBO { _name = String(info.displayName); if (_name.isEmpty()) { - _name = String(_rnboObject.getParameterId(_index)); + _name = String(_parameterInterface->getParameterId(_index)); } - _defaultValue = static_cast(_rnboObject.convertToNormalizedParameterValue(_index, info.initialValue)); + _defaultValue = static_cast(_parameterInterface->convertToNormalizedParameterValue(_index, info.initialValue)); auto min = static_cast(info.min); auto max = static_cast(info.max); @@ -249,17 +237,23 @@ namespace RNBO { float getValue() const override { // getValue wants the value between 0 and 1 - float normalizedValue = (float)_rnboObject.getParameterNormalized(_index); + float normalizedValue = (float)_parameterInterface->getParameterNormalized(_index); + // std::cout << "getValue " << normalizedValue << std::endl; return normalizedValue; } void setValue (float newValue) override { jassert(newValue >= 0 && newValue <= 1.); // should be getting normalized values +#if RNBO_JUCE_PARAM_EVENT_NOTIFY_ONLY + //no need to check old value if we don't feed back + _parameterInterface->setParameterValueNormalized(_index, newValue); +#else float oldValue = getValue(); if (newValue != oldValue) { - _rnboObject.setParameterValueNormalized(_index, newValue); + _parameterInterface->setParameterValueNormalized(_index, newValue); } +#endif } float getDefaultValue() const override @@ -269,7 +263,7 @@ namespace RNBO { String getParameterID() const override { - return String(_rnboObject.getParameterId(_index)); + return String(_parameterInterface->getParameterId(_index)); } String getName (int maximumStringLength) const override @@ -294,7 +288,7 @@ namespace RNBO { String getText (float value, int maximumStringLength) const override { // we want to print the normalized value - float displayValue = (float)_rnboObject.convertFromNormalizedParameterValue(_index, value); + float displayValue = (float)_parameterInterface->convertFromNormalizedParameterValue(_index, value); return AudioProcessorParameter::getText(displayValue, maximumStringLength); } @@ -307,7 +301,7 @@ namespace RNBO { protected: ParameterIndex _index; - CoreObject& _rnboObject; + RNBO::ParameterInterface * _parameterInterface; String _unitName; String _name; float _defaultValue; @@ -320,8 +314,8 @@ namespace RNBO { using String = juce::String; public: - EnumParameter (ParameterIndex index, const ParameterInfo& info, CoreObject& rnboObject, int versionHint = 0, bool automatable = true) - : FloatParameter(index, info, rnboObject, versionHint, automatable) + EnumParameter (ParameterIndex index, const ParameterInfo& info, CoreObject& rnboObject, RNBO::ParameterInterface * parameterInterface, int versionHint = 0, bool automatable = true) + : FloatParameter(index, info, rnboObject, parameterInterface, versionHint, automatable) { for (Index i = 0; i < static_cast(info.steps); i++) { _enumValues.push_back(info.enumValues[i]); @@ -331,7 +325,7 @@ namespace RNBO { String getText (float value, int maximumStringLength) const override { // we want to print the normalized value - long displayValue = (long)_rnboObject.convertFromNormalizedParameterValue(_index, value); + long displayValue = (long)_parameterInterface->convertFromNormalizedParameterValue(_index, value); String v; if (displayValue >= 0 && static_cast(displayValue) < _enumValues.size()) { v = _enumValues[static_cast(displayValue)];