Learn Buffers and File Dependencies

Getting Started

Welcome to RNBO

Quickstart

RNBO Basics

Key Differences

Why We Made RNBO

Fundamentals

Audio IO

Messages to rnbo~

Using Parameters

MIDI in RNBO

Messages and Ports

Polyphony and Voice Control

Audio Files in RNBO

Using Buffers

Using the FFT

Export Targets

Export Targets Overview

VST/AudioUnit
Max External Target
Raspberry Pi Target
The Web Export Target
The C++ Source Code Target

Code Export

Working with JavaScript
Working with C++

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:

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.