Fundamentals
Export Targets
Code Export
Patcher UI
Special Topics
RNBO Raspberry Pi OSCQuery Runner
Getting and Setting Parameters C++
A CoreObject
has multiple methods for working with parameters. For instance, you can use the getNumParameters
method to get a count of the parameters available in your exported RNBO patch. This could be useful when doing something like printing out each individul parameter's name and id. The parameter corresponds to a param object in your original RNBO patcher.
// Print the names of all the top-level parameters in the device.
#include <iostream>
#include "RNBO.h"
int main(int argc, const char * argv[]) {
RNBO::CoreObject rnboObject;
int n = rnboObject.getNumParameters();
for (int i = 0; i < n; i++) {
const char *id = rnboObject.getParameterId(i);
const char *name = rnboObject.getParameterName(i);
// This if statement filters out subpatcher parameters,
// only printing the name of top level parameters. This
// isn't necessary, so comment out this if statement if
// you want to print out all parameters.
if (strstr(id, "/") == nullptr) {
std::cout << i << ":\t" << name << "\n";
}
}
return 0;
}
Changing Parameter Values
RNBO::CoreObject
also exposes two functions called getParameterValue
and setParameterValue
, which can be used to get and set parameter values. These functions take a parameter index as their first argument, which you can retrieve using the getParameterIndexForID
function. An optional third argument to setParameterValue
lets you specify the time at which to update the parameter value, in case you want to schedule an update in the future. You can use RNBO::RNBOTimeNow
to update the parameter as soon as possible, or you can use the RNBO::CoreObject
function getCurrentTime
to retrieve the current time in milliseconds, and then pick a time relative to that.
// Move the pitch parameter up by 5
int parameterIndex = rnboObject.getParameterIndexForID("pitch");
double currentPitch = rnboObject.getParameterValue(parameterIndex);
// Schedule an update for one second from now
rnboObject.setParameterValue(parameterIndex, currentPitch + 5, rnboObject.getCurrentTime() + 1000);
Listening to Parameter Changes
To listen to parameter changes, one must write a concrete subclass of the EventHandler
virtual class. For parameters, the two important virtual methods of this class are eventsAvailable
and handleParameterEvent
. In a typical use case, the application will call process
on the RNBO core object from the audio thread. If a parameter is updated, it will generate a ParameterEvent, calling eventsAvailable
from the audio thread. At this point, the application should defer a call to drainEvents
to the main thread (or whatever thread is handling ParameterEvents through handleParameterEvent
). Finally, the simplest way to use the event handler is to pass an instance to the core object constructor. When we use this form of the core object constructor, we must also create an interface to the patcher using a factory function.
using namespace RNBO;
class CustomParameterHandler : EventHandler {
// This should be called from the main thread, or some other non-audio thread
void doDrainEvents() {
drainEvents();
}
void eventsAvailable() override {
// This function triggers some mechanism for calling doDrainEvents from the main thread
deferDrainEvents();
}
void handleParameterEvent(const ParameterEvent& event) override {
// Do something with the parameter events
}
};
PatcherFactoryFunctionPtr patcherFactoryFunc = GetPatcherFactoryFunction(Platform().get());
LoggingParameterHandler handler;
auto patcher = patcherFactoryFunc();
CoreObject rnboObject(UniquePtr<PatcherInterface>(patcher), (EventHandler *)&handler);
In a very simple test application, it might not be necessary to do any kind of threading. In this case we can explicitly set the type
of the ParameterInterface using the createParameterInterface
method of the RNBO core object. We can choose between the default ParameterEventInterface::MultiProducer
, where multiple threads can all set parameters, the optimized ParameterEventInterface::SingleProducer
which only allows one thread to set parameters, and ParameterEventInterface::NotThreadSafe
, which doesn't introduce any notion of threading. With this type, eventsAvailable
will never be called.
#include <iostream>
#include "RNBO.h"
#define __NOT_THREAD_SAFE
using namespace RNBO;
class LoggingParameterHandler : EventHandler {
void eventsAvailable() override {
#ifndef __NOT_THREAD_SAFE
drainEvents();
#endif
}
void handleParameterEvent(const ParameterEvent& event) override {
fprintf(
stdout,
"ParameterEvent: parameterIndex=%d time=%.3f value=%.4f source=%p\n",
event.getIndex(),
event.getTime(),
event.getValue(),
event.getSource()
);
}
};
int main(int argc, const char * argv[]) {
LoggingParameterHandler handler;
CoreObject rnboObject;
#ifndef __NOT_THREAD_SAFE
auto interface =
rnboObject.createParameterInterface(ParameterEventInterface::MultiProducer, (EventHandler *) &handler);
#else
auto interface =
rnboObject.createParameterInterface(ParameterEventInterface::NotThreadSafe, (EventHandler *) &handler);
#endif
rnboObject.prepareToProcess(44100, 64);
SampleValue** inputs = nullptr;
SampleValue** outputs = new SampleValue*[1];
outputs[0] = new double[64];
while (true) {
rnboObject.process(inputs, 0, outputs, 1, 64);
rnboObject.setParameterValue(0, 74);
}
delete [] outputs[0];
delete [] outputs;
return 0;
}
Parameter Scaling and Normalization
The RNBO core object has a getParameterValue
method for getting parameter values. In addition, it also has the methods getParameterNormalized
and setParameterValueNormalized
allowing you to get/set the parameter value using a range between 0
and 1
. Calling setParameterValueNormalized
with a value of 0
will set the parameter to its minimum value, and with 1
will set the parameter to its maximum value.
RNBO parameters may have a nonlinear scaling value applied to their normalization—either a simple exponent or else a custom normalization expression as defined in the original RNBO patcher. The parameter supplies functions that will take this custom scaling into account.