Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xnor/more notification #6

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 54 additions & 42 deletions RNBO_JuceAudioProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "RNBO_JuceAudioProcessor.h"
#include "RNBO_JuceAudioProcessorEditor.h"
#include "RNBO_JuceAudioProcessorUtils.h"
#include "RNBO_Presets.h"
#include <readerwriterqueue/readerwriterqueue.h>
#include <iostream>
#include <sstream>
Expand Down Expand Up @@ -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<moodycamel::ReaderWriterQueue<char *, 32>>(static_cast<size_t>(32));
_dataRefLoadQueue = make_unique<moodycamel::ReaderWriterQueue<std::pair<juce::String, juce::File>, 32>>(static_cast<size_t>(32));

Expand All @@ -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);
Expand All @@ -162,7 +165,8 @@ JuceAudioProcessor::JuceAudioProcessor(
}
}

_syncParamInterface = _rnboObject.createParameterInterface(ParameterEventInterface::NotThreadSafe, &_syncEventHandler);
//save initial preset
_initialPreset = _rnboObject.getPresetSync();

//Read presets
try {
Expand Down Expand Up @@ -228,20 +232,28 @@ 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());
if (it != _rnboParamIndexToJuceParamIndex.end()) {
// 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
}
}
}
Expand Down Expand Up @@ -400,7 +412,7 @@ int JuceAudioProcessor::getNumPrograms()
if (!_presetList) {
return 1;
} else {
return (int) _presetList->size();
return (int) _presetList->size() + 1; //add "initial"
}
}

Expand All @@ -413,19 +425,27 @@ void JuceAudioProcessor::setCurrentProgram (int index)
{
if (_presetList) {
_currentPresetIdx = index;
if (index >= 0) {
UniquePresetPtr preset = _presetList->presetAtIndex(static_cast<size_t>(index));
_rnboObject.setPreset(std::move(preset));
}
UniquePresetPtr preset;
if (index == 0 && _initialPreset) {
preset = make_unique<RNBO::Preset>();
RNBO::copyPreset(*_initialPreset, *preset);
} else if (index > 0) {
preset = _presetList->presetAtIndex(static_cast<size_t>(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);
}
}
Expand Down Expand Up @@ -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<float>(_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
)
Expand All @@ -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);

Expand All @@ -648,23 +660,23 @@ AudioProcessorParameter* JuceAudioParameterFactory::create(RNBO::CoreObject& rnb
versionHint = meta[vkey].get<int>();
}
}
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) {
Expand Down
64 changes: 29 additions & 35 deletions RNBO_JuceAudioProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_audio_formats/juce_audio_formats.h>

// 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<typename T, size_t MAX_BLOCK_SIZE>
class ReaderWriterQueue;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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<RNBO::PresetList> _presetList;
SyncEventHandler _syncEventHandler;
RNBO::ParameterEventInterfaceUniquePtr _syncParamInterface;
RNBO::ConstPresetPtr _initialPreset;
int _currentPresetIdx;
bool _isInStartup = false;
bool _isSettingPresetAsync = false;
Expand All @@ -197,6 +184,7 @@ namespace RNBO {

std::unique_ptr<moodycamel::ReaderWriterQueue<char *, 32>> _dataRefCleanupQueue;
std::unique_ptr<moodycamel::ReaderWriterQueue<std::pair<juce::String, juce::File>, 32>> _dataRefLoadQueue;

};

class DataRefUpdatedMessage : public juce::Message {
Expand All @@ -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)
{

Expand All @@ -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<float>(_rnboObject.convertToNormalizedParameterValue(_index, info.initialValue));
_defaultValue = static_cast<float>(_parameterInterface->convertToNormalizedParameterValue(_index, info.initialValue));

auto min = static_cast<float>(info.min);
auto max = static_cast<float>(info.max);
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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);
}

Expand All @@ -307,7 +301,7 @@ namespace RNBO {

protected:
ParameterIndex _index;
CoreObject& _rnboObject;
RNBO::ParameterInterface * _parameterInterface;
String _unitName;
String _name;
float _defaultValue;
Expand All @@ -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<Index>(info.steps); i++) {
_enumValues.push_back(info.enumValues[i]);
Expand All @@ -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<Index>(displayValue) < _enumValues.size()) {
v = _enumValues[static_cast<Index>(displayValue)];
Expand Down