🔊 Integrating p5.js with RNBO for Web-Based Audiovisual Experiences
🧑💻️ Andrei Antonescu / superblob.studio
Here’s what we’re going to build today - “Mouse Theremin”
Workshop Plan
Overview
Overview
Intro to Max
Create object (N)
Lock/Unlock (Cmd-E)
Signal vs. Value
Debug / Bangs
Help menu
Simple example to get us started with
Two base frequencies and multiple sets of sine oscillators
Overtones based on frequency divisions
Download (1-Max.maxpat)
Intro to Max
Intro to p5.js
Base website structure (2-starterWeb)
Serving on local server
Setup & Draw
Connecting to HTML
Mouse Moved
Intro to p5.js - index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.js"></script>
<script src="sketch.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
<button onClick="doSomething()">Click Me!</button>
</main>
</body>
</html>
Add p5.js library to index.html
Button that calls doSomething() function
Our javascript sketch
Intro to p5.js - sketch.js
function setup() {
createCanvas(windowWidth, windowHeight)
background(200)
fill('green')
ellipse(200, 200, 250)
}
function draw() {
ellipse(random(windowWidth), random(windowHeight), 50)
}
function mouseMoved() {
console.log(mouseX, mouseY)
}
function doSomething() {
console.log("I was clicked")
}
Called once
Called every frame (60fps)
Called when mouse is moved
Our function for interacting with the HTML button
RNBO
Installing RNBO
Creating RNBO patch
Porting from Max
Params and Outputs
Exporting to web
Download (3-RNBO-conv)
RNBO - converting Max patch
RNBO - Params
Params (IN)
Outputs (OUT)
RNBO - Exporting
Web Export
Dependencies needed if using samples
Integrating RNBO and p5.js
Export structure
Adding RNBO to the web
Signal Flow/Devices
Starting Audio on the web
Get/Set Params
Combining with graphics
Download (4-RNBO-Web)
Exported params from patcher
Integrating - Adding RNBO to the web
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.js"></script>
<script type="text/javascript" src="https://cdn.cycling74.com/rnbo/latest/rnbo.min.js"></script>
<script src="sketch.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
<button onClick="doSomething()">Click Me!</button>
</main>
</body>
</html>
Add RNBO library to index.html
Integrating - Devices & Signal Flow
async function setupRNBO() {
const WAContext = window.AudioContext || window.webkitAudioContext
context = new WAContext()
const outputNode = context.createGain()
outputNode.connect(context.destination)
let response = await fetch("export/sketch.export.json")
const myPatcher = await response.json()
const myDevice = await RNBO.createDevice({ context, patcher: myPatcher })
// Connect the devices in series
myDevice.node.connect(outputNode)
Continues…
Get audio context and output
Get patcher and connect to output
Integrating - Devices & Signal Flow
…Continued
// get parameters
freqOne = myDevice.parametersById.get("freqOne")
freqOne.value = 350.0
freqTwo = myDevice.parametersById.get("freqTwo")
freqTwo.value = 500.0
gain = myDevice.parametersById.get("gain")
gain.value = 85.0
context.suspend()
}
Get and set params from patcher
Audio context needs to be resumed after user interaction
Integrating - Starting Audio on the web
function setup() {
createCanvas(innerWidth, innerHeight)
background(200)
setupRNBO()
}
function doSomething() {
context.resume()
console.log("Start Audio")
}
Setup RNBO during setup()
Resume audio context after user interaction
Integrating - Playing with params and graphics
Multiple Devices / Effects
Download RNBO Guitar Pedals pack
Multiple Devices / Effects
Launch and select an effect, like the ShimmeRev
Select RNBO patch from example and export
Multiple Devices - Creating New & Add to Signal Flow
async function setupRNBO() {
const WAContext = window.AudioContext || window.webkitAudioContext
context = new WAContext()
const outputNode = context.createGain()
outputNode.connect(context.destination)
let response = await fetch("export/Example.export.json")
const myPatcher = await response.json()
const myDevice = await RNBO.createDevice({ context, patcher: myPatcher })
let responseTwo = await fetch("export/Reverb/rnbo.shimmerev.json")
const myPatcherTwo = await responseTwo.json()
const myDeviceTwo = await RNBO.createDevice({ context, patcher: myPatcherTwo })
// Change the signal flow
myDevice.node.connect(myDeviceTwo.node)
myDeviceTwo.node.connect(outputNode)
Continues...
Final touches
Extra - MIDI/Polyphony/Dependencies
Extra - MIDI/Polyphony/Dependencies
Extra - Connecting to p5.Sound / other Web Audio contexts
Instead of creating the audio context, you can grab it from another place/library (Tone JS / p5.Sound / etc.)
For example, p5.js has a function for getting the audio context
context = getAudioContext() // get p5 audio context
See an example here (towards the end).
Resources
Thank you!
🧑💻️ Andrei Antonescu / superblob.studio