use std::ops::Range;
use dspk_core::{DspResult, MemoryOrder, RecordingSource};
use std::cell::RefCell;
use crate::envelope::fold::Block;
thread_local! {
static BLOCKS: RefCell<[Vec<f32>; 2]> = const { RefCell::new([Vec::new(), Vec::new()]) };
}
pub(crate) fn read_channel_blocks(
source: &dyn RecordingSource,
channels: &[usize],
ranges: &[Range<u64>],
mut fold: impl FnMut(&Block) + Send,
) -> DspResult<()> {
let Some(first) = ranges.first() else { return Ok(()) };
let rows = channels.len();
let read = |r: &Range<u64>, buf: &mut Vec<f32>| -> DspResult<()> {
buf.resize(rows * (r.end - r.start) as usize, 0.0);
source.read(channels, r.clone(), buf)
};
BLOCKS.with_borrow_mut(|[current, next]| {
read(first, current)?;
for (i, range) in ranges.iter().enumerate() {
let block = Block { data: current, order: MemoryOrder::ChannelMajor, channels: rows, samples: (range.end - range.start) as usize, first: range.start };
match ranges.get(i + 1) {
Some(r) => {
let (read_next, ()) = rayon::join(|| read(r, next), || fold(&block));
read_next?;
}
None => fold(&block),
}
std::mem::swap(current, next);
}
Ok(())
})
}
pub(crate) fn read_pipelined(
source: &dyn RecordingSource,
ranges: impl IntoIterator<Item = Range<u64>>,
stop: impl Fn() -> bool + Sync,
mut fold: impl FnMut(&Block) + Send,
) -> DspResult<bool> {
let channels = source.info().channel_count();
let read = |r: Range<u64>| -> DspResult<(Vec<f32>, MemoryOrder, Range<u64>)> {
let mut data = vec![0.0f32; channels * (r.end - r.start) as usize];
let order = source.read_native(r.clone(), &mut data)?;
Ok((data, order, r))
};
let mut ranges = ranges.into_iter();
let Some(first) = ranges.next() else { return Ok(true) };
if stop() {
return Ok(false);
}
let mut current = read(first)?;
loop {
let (data, order, range) = ¤t;
let block = Block { data, order: *order, channels, samples: (range.end - range.start) as usize, first: range.start };
let next = match ranges.next() {
Some(r) if !stop() => {
let (next, ()) = rayon::join(|| read(r), || fold(&block));
next?
}
Some(_) => {
fold(&block);
return Ok(false);
}
None => {
fold(&block);
return Ok(true);
}
};
current = next;
}
}