use firewheel::{
clock::ClockSeconds, collector::ArcGc, node::StreamStatus, processor::FirewheelProcessor,
};
use js_sys::{Array, Float32Array};
use std::sync::atomic::AtomicBool;
use wasm_bindgen::{JsCast, prelude::wasm_bindgen};
#[wasm_bindgen]
pub(crate) struct ProcessorHost {
pub(crate) processor: Option<FirewheelProcessor>,
pub(crate) receiver: std::sync::mpsc::Receiver<FirewheelProcessor>,
pub(crate) alive: ArcGc<AtomicBool>,
pub(crate) inputs: usize,
pub(crate) outputs: usize,
pub(crate) input_buffers: &'static mut [f32],
pub(crate) output_buffers: &'static mut [f32],
}
impl ProcessorHost {
fn process_fallible(
&mut self,
inputs: js_sys::Array,
outputs: js_sys::Array,
current_time: f64,
) -> Result<bool, wasm_bindgen::JsValue> {
if !self.alive.load(std::sync::atomic::Ordering::Relaxed) {
return Ok(false);
}
if let Ok(processor) = self.receiver.try_recv() {
self.processor = Some(processor);
}
let mut temp_buffer = [0f32; crate::BLOCK_FRAMES];
for i in 0..self.inputs {
let Ok(inputs) = inputs.get(0).dyn_into::<Array>() else {
continue;
};
let Ok(channel_array) = inputs.get(i as u32).dyn_into::<Float32Array>() else {
continue;
};
if channel_array.is_undefined() {
return Err(wasm_bindgen::JsValue::undefined());
}
channel_array.copy_to(&mut temp_buffer);
for (j, input) in temp_buffer.iter().enumerate() {
let buffer_index = i + j * self.inputs;
self.input_buffers[buffer_index] = *input;
}
}
if let Some(processor) = &mut self.processor {
processor.process_interleaved(
self.input_buffers,
self.output_buffers,
self.inputs,
self.outputs,
crate::BLOCK_FRAMES,
ClockSeconds(current_time),
StreamStatus::empty(),
);
}
for i in 0..self.outputs {
let Ok(outputs) = outputs.get(0).dyn_into::<Array>() else {
continue;
};
let Ok(channel_array) = outputs.get(i as u32).dyn_into::<Float32Array>() else {
continue;
};
if channel_array.is_undefined() {
return Err(wasm_bindgen::JsValue::undefined());
}
for (j, output) in temp_buffer.iter_mut().enumerate() {
let buffer_index = i + j * self.outputs;
*output = self.output_buffers[buffer_index];
}
channel_array.copy_from(&temp_buffer);
}
Ok(true)
}
}
#[wasm_bindgen]
#[allow(dead_code)]
impl ProcessorHost {
pub fn pack(self) -> usize {
Box::into_raw(Box::new(self)) as usize
}
pub unsafe fn unpack(ptr: usize) -> Self {
unsafe { *Box::from_raw(ptr as *mut Self) }
}
pub fn process(
&mut self,
inputs: js_sys::Array,
outputs: js_sys::Array,
current_time: f64,
) -> bool {
self.process_fallible(inputs, outputs, current_time)
.unwrap_or(true)
}
}