dspk_core/recording/
source.rs1use std::ops::Range;
2
3use super::format::SampleFormat;
4use super::info::RecordingInfo;
5use crate::buffer::{MemoryOrder, SignalChunk};
6use crate::error::{DspError, DspResult};
7use crate::time::RationalTime;
8
9pub trait RecordingSource: Send + Sync {
14 fn info(&self) -> &RecordingInfo;
15
16 fn read(&self, channels: &[usize], samples: Range<u64>, out: &mut [f32]) -> DspResult<()>;
20
21 fn read_stored(&self, channels: &[usize], samples: Range<u64>, out: &mut [u8]) -> DspResult<()> {
30 let info = self.info();
31 let identity = channels.iter().all(|&c| info.channels.get(c).is_some_and(|ch| ch.gain == 1.0 && ch.offset == 0.0));
32 if info.format != SampleFormat::F32 || !identity {
33 return Err(DspError::UnsupportedFormat(format!("{}: stored {} reads", info.name, info.format.name())));
34 }
35 let n = check_read_stored(info, channels, &samples, out.len())?;
36 let mut values = vec![0.0f32; channels.len() * n];
37 self.read(channels, samples, &mut values)?;
38 for (dst, v) in out.chunks_exact_mut(4).zip(values) {
39 dst.copy_from_slice(&v.to_le_bytes());
40 }
41 Ok(())
42 }
43
44 fn read_native(&self, samples: Range<u64>, out: &mut [f32]) -> DspResult<MemoryOrder> {
51 let all: Vec<usize> = (0..self.info().channel_count()).collect();
52 self.read(&all, samples, out)?;
53 Ok(MemoryOrder::ChannelMajor)
54 }
55
56 fn chunk_samples(&self) -> Option<u64> {
60 None
61 }
62
63 fn read_channel(&self, channel: usize, samples: Range<u64>, out: &mut [f32]) -> DspResult<()> {
64 self.read(&[channel], samples, out)
65 }
66
67 fn read_chunk(&self, channels: &[usize], samples: Range<u64>) -> DspResult<SignalChunk> {
69 let n = (samples.end.saturating_sub(samples.start)) as usize;
70 let mut data = vec![0.0f32; channels.len() * n];
71 self.read(channels, samples.clone(), &mut data)?;
72 let info = self.info();
73 let start = RationalTime::from_samples(samples.start, info.sample_rate)?;
74 SignalChunk::new(channels.len(), n, info.sample_rate, start, MemoryOrder::ChannelMajor, data)
75 }
76}
77
78pub fn check_read_stored(info: &RecordingInfo, channels: &[usize], samples: &Range<u64>, out_len: usize) -> DspResult<usize> {
81 let bytes = info.format.bytes();
82 if out_len % bytes != 0 {
83 return Err(DspError::ShapeMismatch { expected: vec![channels.len(), bytes], actual: vec![out_len] });
84 }
85 check_read(info, channels, samples, out_len / bytes)
86}
87
88pub fn check_read(info: &RecordingInfo, channels: &[usize], samples: &Range<u64>, out_len: usize) -> DspResult<usize> {
90 if samples.start > samples.end || samples.end > info.samples {
91 return Err(DspError::SampleRange { start: samples.start, end: samples.end, total: info.samples });
92 }
93 let total = info.channels.len();
94 if let Some(&channel) = channels.iter().find(|&&c| c >= total) {
95 return Err(DspError::InvalidChannel { channel, total });
96 }
97 let n = (samples.end - samples.start) as usize;
98 if out_len != channels.len() * n {
99 return Err(DspError::ShapeMismatch { expected: vec![channels.len(), n], actual: vec![out_len] });
100 }
101 Ok(n)
102}