Help with web_sys and Web Audio API

Hi there!

I'm a JavaScript developer trying to learn Rust, so I'm having a go porting some old JS of mine to rust using web_sys. I've used the wasm_bindgen book article on Web Audio as the basis for getting things running.

As far as I can tell, I've got all the parts wired up correctly but for the life of me I can't get the app to make any noise! Here is my rust code:

use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{AudioContext, AudioProcessingEvent};
use rand::prelude::*;

#[wasm_bindgen]
pub struct PinkNoise {
    ctx: AudioContext,        
    buffer_size: u32,
    node: web_sys::ScriptProcessorNode
}

impl Drop for PinkNoise {
    fn drop(&mut self) {
        let _ = self.ctx.close();
    }
}

#[wasm_bindgen]
impl PinkNoise {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Result<PinkNoise, JsValue> {

        let ctx = AudioContext::new()?;

        let buffer_size = 4096;

        let node = ctx.create_script_processor_with_buffer_size_and_number_of_input_channels_and_number_of_output_channels(
            buffer_size, 1, 1
        )?;

        let cb: Closure<dyn Fn(&AudioProcessingEvent)> = Closure::wrap(Box::new(move |event: &AudioProcessingEvent| {
            audio_process_callback(&event);
        }));

        let callback: Option<&js_sys::Function> = Some(cb.as_ref().unchecked_ref());

        node.set_onaudioprocess(callback);
        node.connect_with_audio_node(&ctx.destination())?;

        cb.forget();

        fn audio_process_callback(event: &AudioProcessingEvent) {

            let buffer = event.event_phase();

            let mut b_0: f32 = 0.0;
            let mut b_1: f32 = 0.0;
            let mut b_2: f32 = 0.0;
            let mut b_3: f32 = 0.0;
            let mut b_4: f32 = 0.0;
            let mut b_5: f32 = 0.0;

            let mut output = event.output_buffer().unwrap().get_channel_data(0).unwrap();
            let mut rng = thread_rng();
            let white: f32 = rng.gen::<f32>() * 2.0 - 1.0;            

            for n in 0..4096 {
                b_0 = 0.99886 * b_0 + white * 0.0555179;
                b_1 = 0.99332 * b_1 + white * 0.0750759;
                b_2 = 0.96900 * b_2 + white * 0.1538520;
                b_3 = 0.86650 * b_3 + white * 0.3104856;
                b_4 = 0.55000 * b_4 + white * 0.5329522;
                b_5 = -0.7616 * b_5 + white * 0.0168980;
                
                output[n] = b_1 + b_2 + b_2 + b_3 + b_4 + b_5 + white * 0.5362;
                output[n] *= 0.11;
            }
        }

        Ok(PinkNoise {
            ctx,
            buffer_size,
            node
        })
    }
}

If I stick a console log in the callback I can see that the callback is firing, just no noise.

For comparison, here is a pen of the Javascript. I'm using wasm-pack to handle all the building and glue etc. and it works fine for the wasm_bindgen example from the book.

Any help would be greatly appreciated! (I've been going around in circles with this for a while!).

Thanks in advance

1 Like