waw-rs helps you create Web Audio Worklets using Rust, without crying.
See WebAssembly/Rust Tutorial: Pitch-perfect Audio Processing
This is all very experimental.
Add waw-rs to your Cargo.toml:
waw = { git = "https://github.com/Marcel-G/waw-rs" }Implement the Processor trait and register your audio node:
use wasm_bindgen::prelude::*;
use waw::{create_node, register, ParameterValues, Processor};
#[derive(Clone)]
pub struct MyData {
pub frequency: f32,
}
pub struct MyProcessor {
phase: f32,
frequency: f32,
}
impl Processor for MyProcessor {
type Data = MyData;
fn new(data: Self::Data) -> Self {
Self { phase: 0.0, frequency: data.frequency }
}
fn process(
&mut self,
_inputs: &[&[f32]],
outputs: &mut [&mut [f32]],
sample_rate: f32,
params: &ParameterValues,
) {
// ... your audio processing logic
}
}
#[wasm_bindgen]
pub struct MyNode {
node: web_sys::AudioWorkletNode,
}
#[wasm_bindgen]
impl MyNode {
#[wasm_bindgen(constructor)]
pub fn new(ctx: &web_sys::AudioContext, frequency: f32) -> Result<MyNode, JsValue> {
let data = MyData { frequency };
let node = MyProcessor::create_node(ctx, data)?;
Ok(MyNode { node })
}
#[wasm_bindgen(getter)]
pub fn node(&self) -> web_sys::AudioWorkletNode {
self.node.clone()
}
}
register!(MyProcessor, "my-processor");Build with wasm-pack:
wasm-pack build --target webUse in JavaScript:
import init, { MyNode, registerContext } from './pkg/your_project';
const main = async () => {
await init();
const context = await registerContext();
const node = new MyNode(context, 440.0);
node.node.connect(context.destination);
document.addEventListener('click', () => context.resume(), { once: true });
};
main();See the demo for a complete example.