sesh_sdk/scratch.rs
1use std::cell::UnsafeCell;
2
3/// Pre-allocated buffer pool for intermediate results during audio processing.
4///
5/// Const-constructed, zero-initialized in the data segment. Uses `UnsafeCell` for
6/// interior mutability — safe because WASM is single-threaded.
7///
8/// # Example
9///
10/// ```rust
11/// use sesh_sdk::Scratch;
12///
13/// static SCRATCH: Scratch = Scratch::new();
14///
15/// fn process(channels: &mut [&mut [f32]]) {
16/// let [mod_buf, tap_l, tap_r, out_l, out_r, ..] = SCRATCH.get();
17/// // use buffers...
18/// }
19/// ```
20pub struct ScratchPool<const N: usize, const FRAMES: usize> {
21 bufs: UnsafeCell<[[f32; FRAMES]; N]>,
22}
23
24// SAFETY: WASM is single-threaded. No concurrent access possible.
25unsafe impl<const N: usize, const FRAMES: usize> Sync for ScratchPool<N, FRAMES> {}
26
27impl<const N: usize, const FRAMES: usize> ScratchPool<N, FRAMES> {
28 pub const fn new() -> Self {
29 Self {
30 bufs: UnsafeCell::new([[0.0; FRAMES]; N]),
31 }
32 }
33
34 /// Get mutable access to all buffers. Destructure into individual `&mut [f32; FRAMES]`
35 /// references for non-overlapping borrows.
36 pub fn get(&self) -> &mut [[f32; FRAMES]; N] {
37 unsafe { &mut *self.bufs.get() }
38 }
39}
40
41/// Default scratch pool: 8 buffers of 2048 frames each (64KB).
42pub type Scratch = ScratchPool<8, 2048>;