Fundamentals
Export Targets
Code Export
Patcher UI
Special Topics
RNBO Raspberry Pi OSCQuery Runner
RNBO Helper Types
Before working with RNBO, there's a handful of helper types that deserve special mention. Having some familiarity with these types will make working with RNBO much easier.
UniquePtr
The notion of a unique pointer is borrowed heavily from the c++11
std::unique_ptr structure. The core concept is essentially the same: UniquePtr
is a smart pointer that manages another object. When the UniquePtr
goes out of scope, the object itself is destroyed. UniquePtr
comes with a convenience function make_unique
, a templated function that constructs a new object and a UniquePtr
to manage that object at the same time.
using namespace RNBO;
std::cout << "Starting the program\n";
CoreObject rnboObject;
if (true) {
ConstPresetPtr newPreset = rnboObject.getPresetSync();
// This creates a new Preset, as well as a UniquePtr to manage that preset
UniquePtr<Preset> uniquePreset = make_unique<Preset>();
copyPreset(*newPreset, *uniquePreset);
// No need to worry about deleting the Preset. As soon as the uniquePreset pointer
// goes out of scope, it will delete the managed Preset object as well.
// Or, we could call std::move on the uniquePreset, handing off management of the
// pointer to another part of the program
rnboObject.setPreset(std::move(uniquePreset));
}
// In any case, uniquePreset is no longer memory that this part of the program
// needs to manage
One important thing to keep in mind is that because a UniquePtr
deletes its managed object as soon as the UniquePtr
goes out of scope, any function that returns a UniquePtr
will delete its return value immediately if the return value is unused. Occasionally this can cause some slightly surprising results. Consider the case where the user calls createParameterInterface
to attach an EventHandler
to a RNBO core object.
ConcreteEventHandler handler;
if (true) {
// interface is a UniquePtr. When it goes out of scope, the managed
// ParameterInterface object will be deleted.
auto interface = rnboObject.createParameterInterface(
ParameterEventInterface::MultiProducer,
(EventHandler *) &handler
);
}
// Now that UniquePtr is out of scope, the ParameterInterface has been deleted.
// The EventHandler will no longer receive events.
Even if the returned interface
value is unused, it must be assigned to a variable or kept in scope for the EventHandler
to receive events. It's a subtle point, but helpful to keep in mind, in case you're not receiving events when you expect to.
There are some key differences between std::unique_ptr
and UniquePtr
. There's no copy constructor or assignment operator for UniquePtr
, which makes UniquePtr
a more limited, but also much simpler alternative. In most cases, it's enough to understand what a UniquePtr
is trying to achieve, and to know how to interface with RNBO API functions that require a UniquePtr
instead of an unmanaged pointer (RNBO::CoreObject::setPreset
is a perfect example).
RNBO::list
Similar to Max, RNBO has a notion of a list. Lists in RNBO consist of numbers only, but it's possible to treat them somewhat similar to a std::vector
in the C++ standard library. You can create, iterate, and modify a RNBO::list
as you'd expect.
RNBO::list mylist;
mylist.push(1);
mylist.push(2);
mylist.push(3);
for (int i = 0; i < mylist.length; i++) {
if (i != 0) std::cout << ", ";
std::cout << mylist[i];
}
std::cout << "\n";
// Prints 1, 2, 3
mylist[0] = 4;
mylist = mylist.reverse();
for (int i = 0; i < mylist.length; i++) {
if (i != 0) std::cout << ", ";
std::cout << mylist[i];
}
std::cout << "\n";
// Prints 3, 2, 4
Probably the most common way to use lists is to send messages to a RNBO inport or in object. In this case, the list must be wrapped in a UniquePtr
and then handed off to the RNBO core object using std::move
.
using namespace RNBO;
auto mylist = make_unique<list>();
(*mylist).push(1);
(*mylist).push(2);
(*mylist).push(3);
rnboObject.sendMessage(TAG("in1"), std::move(mylist), TAG(""));