Taking equal-sized chunks from multiple audio streams in Rust in parallel

337 views Asked by At

I'm trying to write elegant audio processing code in Rust that can consume chunks of audio from N channels (mono, stereo or surround, known at compile-time) in lock-step, reduce them and send the reduced value (or flat-mapped value) off to another stream for processing.

In Clojure, the sequence abstractions and higher-order transducers make it easy to bite chunks off a stream and post a processed result to another core.async channel, but I'm struggling to get this working in Rust, especially since Rust complains about generic iterators not being sized at compile time.

Specifically, how do I consume equal-sized chunks of audio from multiple channels in lock-step, to e.g. calculate the summed square of all values, and then do something with that value? I'm aware of crossbeam.

Here is the pseudo-code I'm reaching for:

type AudioSample = f64;
struct Signal<S, const N: usize> {
    sample_rate: f64,
    channels: [Iterator<S>; N], // I know this won't compile
}

fn process_signal(signal: Signal<AudioSample, 5>) -> f64 {
    let mut sum_squared = 0.0;
    let chunk_size = 0.1 * signal.sample_rate; // 100ms of audio from each channel
    for channel in signal.channels {  // how to parallelize this blocking call?
        let chunk = channel.take(chunk_size); // assuming this blocks until 100ms of signal is available
        sum_squared += chunk.fold(|0., sample| sample * sample);
    }

    sum_squared
}

Bonus points if you can show a pragmatic way to make the process_signal() function "incremental", i.e. asynchronous and parallelizable for N-channels.

1

There are 1 answers

0
Danny Meyer On

Perhaps you can have another thread responsible for processing, rather than try to synchronize buffer reads? This seems like a nice opportunity to use a mpsc channel.

Since you'll likely only be able to react to the callback from the audio scheduler being called, it's worry you'll spend a lot of time waiting/blocking for buffers to be ready if you try to for processing to happen in unison.