waw-rs
should help you create Web Audio Worklets using Rust, without crying.
See WebAssembly/Rust Tutorial: Pitch-perfect Audio Processing
This is all very experimental.
To use waw-rs in your project, add it as a dependency in your Cargo.toml:
waw = { git = "https://github.com/Marcel-G/waw-rs" }
You will need to setup an xtask to build the project, see xtask-waw.
Then, in your Rust code, simply implement the AudioModule
trait and call the waw::main!
macro on your struct:
src/lib.rs
use waw::{
worklet::{ AudioModule, Emitter },
buffer::{ AudioBuffer, ParamBuffer }
};
struct MyWorklet;
impl AudioModule for MyWorklet {
fn create(
_initial_state: Option<Self::InitialState>,
_emitter: Emitter<Self::Event>
) -> Self { MyWorklet }
fn process(&mut self, audio: &mut AudioBuffer, params: &ParamBuffer<Self::Param>) {
// Implement process
}
}
waw::main!(MyWorklet);
Run the build using the xtask command
cargo xtask dist
They can then be used from JavaScript:
import init, { init_worklet, MyWorklet } from "./pkg/waw-demo";
import worklet_url from "./pkg/waw-demo.worklet.js?url&worker";
// Note: waw-demo.worklet.js must be loaded as a URL - bundlers may need different config for this
const main = async () => {
// Init WASM on the main thread
await init();
// Create an audio context
const context = new AudioContext();
// Init WASM on the audio worklet thread
await init_worklet(context, worklet_url);
// Call create on the generated worklet node
const worklet = await MyWorklet.create(context);
// Connect the audio node to WebAudio graph
worklet.node().connect(context.destination);
// Wait for some interaction on the page before starting the audio
const handle_interaction = () => {
void context?.resume();
};
document.addEventListener("click", handle_interaction, { once: true });
};
main();
See the demo project for a full example.