Fundamentals
Export Targets
Code Export
Patcher UI
Special Topics
RNBO Raspberry Pi OSCQuery Runner
Buffers and File Dependencies
A RNBO patch can declare and reference buffers that can be filled with binary data at runtime.
A RNBO patch can declare and reference buffers that can be filled with binary data at runtime. Usually this means creating a buffer~ object in your RNBO patch, and then filling it with the contents of an audio file while it's running in the browser.
DataBuffer Description
Each buffer within a RNBO device is associated with a unique id. If the buffer came from a buffer~ object in a RNBO patcher, then the unique id will be the name of the buffer~. Depending on how the buffer~ was defined, there may be other information associated with the buffer in addition to its id. To retrieve a list of buffer descriptions, you can utilize the following code:
// descriptions is of type ExternalDataInfo[]
const descriptions = device.dataBufferDescriptions;
// Each description will have a unique id, as well as a "file" or "url" key, depending on whether
// the buffer references a local file or a remote URL
descriptions.forEach(desc => {
if (!!desc.file) {
console.log(`Buffer with id ${desc.id} references file ${desc.file}`);
} else {
console.log(`Buffer with id ${desc.id} references remote URL ${desc.url}`);
}
});
You can read more about this dataBufferDescriptions
property in the JS API Reference document for the BaseDevice class.
Setting DataBuffers
To set the referenced data for a buffer in a RNBO device, we use the unique id associated with that buffer, calling setDataBuffer with the data to set. Be aware that the buffer will make a copy of the data when calling setDataBuffer. This is to ensure that the given data is in the correct format, safely transfers to the audio worklet (if applicable), and avoids altering the source data unexpectedly. The API also supports multiple signatures, allowing you to set the contents of a buffer by:
- providing an AudioBuffer
- providing an ArrayBuffer alongside a channel count and sample rate
- providing a Float32Array alongside a channel count and sample rate
In the case of an AudioBuffer, the necessary information (channel count, sample rate) is gathered from the AudioBuffer directly. In the case of an ArrayBuffer or Float32Array, the channel count and sample rate need to be provided separately in order to tell the device how to interpret the data. Additionally, all raw input data is considered to be in an interleaved data format.
Releasing DataBuffers
When you want to reset a buffer after a call to setDataBuffer, you can call releaseDataBuffer to release the data and reset the buffer. The latest state of the data will be returned as an instance of a DataBuffer, and the contents of the data within the patch will be reset. This can be used to free up resources after filling a buffer with a large sample.
Usage Example
The following shows the typical use case for fetching a .wav
audio file using a HTTP request, decoding it using the WebAudio API, and setting it as the contents of a DataBuffer on a device:
const { createDevice } = require("@rnbo/js");
const audioContext = new AudioContext();
const bufferId = "my_sample"; // let's assume we have a [buffer~ my_sample] object in our patch
const start = async () => {
const patcherRequest = new Request("patch.json");
const patcherResponse = await fetch(patcherRequest);
const patcher = await patcherResponse.json();
// Create the device
const device = await createDevice({ context: audioContext, patcher: patcher });
// Load our sample as an ArrayBuffer;
const fileResponse = await fetch("sample.wav");
const arrayBuf = await fileResponse.arrayBuffer();
// Decode the received Data as an AudioBuffer
const audioBuf = await audioContext.decodeAudioData(arrayBuf);
// Set the DataBuffer on the device
await device.setDataBuffer(bufferId, audioBuf);
// Connect the device to the audio out
device.node.connect(audioContext.destination);
};
Exported Dependencies and dependencies.json
If your patcher has file
or url
dependencies defined in its buffer~ objects, then it can generate a dependencies.json
file in addition to other files during export. This human-readable JSON file defines a mapping between each buffer ID and its content's corresponding file/URL. The RNBO device provides a convenience function loadDataBufferDependencies
that works with data loaded from the dependencies.json
file.
// Load the exported dependencies.json file
let dependencies = await fetch("dependencies.json");
dependencies = await dependencies.json();
// Load the dependencies into the device
const results = await device.loadDataBufferDependencies(dependencies);
results.forEach(result => {
if (result.type === "success") {
console.log(`Successfully loaded buffer with id ${result.id}`);
} else {
console.log(`Failed to load buffer with id ${result.id}, ${result.error}`);
}
});
This can streamline device loading and setup, especially if you're working with a very large number of samples.