1use crate::common::{ChannelCount, SampleRate};
14use crate::source::SeekError;
15use crate::{Sample, Source};
16use std::sync::Arc;
17use std::time::Duration;
18
19#[derive(Debug, Clone)]
21pub struct SamplesBuffer {
22 data: Arc<[Sample]>,
23 pos: usize,
24 channels: ChannelCount,
25 sample_rate: SampleRate,
26 duration: Duration,
27}
28
29impl SamplesBuffer {
30 pub fn new<D>(channels: ChannelCount, sample_rate: SampleRate, data: D) -> SamplesBuffer
40 where
41 D: Into<Vec<Sample>>,
42 {
43 assert!(channels >= 1);
44 assert!(sample_rate >= 1);
45
46 let data: Arc<[f32]> = data.into().into();
47 let duration_ns = 1_000_000_000u64.checked_mul(data.len() as u64).unwrap()
48 / sample_rate as u64
49 / channels as u64;
50 let duration = Duration::new(
51 duration_ns / 1_000_000_000,
52 (duration_ns % 1_000_000_000) as u32,
53 );
54
55 SamplesBuffer {
56 data,
57 pos: 0,
58 channels,
59 sample_rate,
60 duration,
61 }
62 }
63}
64
65impl Source for SamplesBuffer {
66 #[inline]
67 fn current_span_len(&self) -> Option<usize> {
68 None
69 }
70
71 #[inline]
72 fn channels(&self) -> ChannelCount {
73 self.channels
74 }
75
76 #[inline]
77 fn sample_rate(&self) -> SampleRate {
78 self.sample_rate
79 }
80
81 #[inline]
82 fn total_duration(&self) -> Option<Duration> {
83 Some(self.duration)
84 }
85
86 #[inline]
88 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
89 let curr_channel = self.pos % self.channels() as usize;
94 let new_pos = pos.as_secs_f32() * self.sample_rate() as f32 * self.channels() as f32;
95 let new_pos = new_pos as usize;
97 let new_pos = new_pos.min(self.data.len());
98
99 let new_pos = new_pos.next_multiple_of(self.channels() as usize);
101 let new_pos = new_pos - curr_channel;
102
103 self.pos = new_pos;
104 Ok(())
105 }
106}
107
108impl Iterator for SamplesBuffer {
109 type Item = Sample;
110
111 #[inline]
112 fn next(&mut self) -> Option<Self::Item> {
113 let sample = self.data.get(self.pos)?;
114 self.pos += 1;
115 Some(*sample)
116 }
117
118 #[inline]
119 fn size_hint(&self) -> (usize, Option<usize>) {
120 (self.data.len(), Some(self.data.len()))
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use crate::buffer::SamplesBuffer;
127 use crate::source::Source;
128
129 #[test]
130 fn basic() {
131 let _ = SamplesBuffer::new(1, 44100, vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
132 }
133
134 #[test]
135 #[should_panic]
136 fn panic_if_zero_channels() {
137 SamplesBuffer::new(0, 44100, vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
138 }
139
140 #[test]
141 #[should_panic]
142 fn panic_if_zero_sample_rate() {
143 SamplesBuffer::new(1, 0, vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
144 }
145
146 #[test]
147 fn duration_basic() {
148 let buf = SamplesBuffer::new(2, 2, vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
149 let dur = buf.total_duration().unwrap();
150 assert_eq!(dur.as_secs(), 1);
151 assert_eq!(dur.subsec_nanos(), 500_000_000);
152 }
153
154 #[test]
155 fn iteration() {
156 let mut buf = SamplesBuffer::new(1, 44100, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
157 assert_eq!(buf.next(), Some(1.0));
158 assert_eq!(buf.next(), Some(2.0));
159 assert_eq!(buf.next(), Some(3.0));
160 assert_eq!(buf.next(), Some(4.0));
161 assert_eq!(buf.next(), Some(5.0));
162 assert_eq!(buf.next(), Some(6.0));
163 assert_eq!(buf.next(), None);
164 }
165
166 #[cfg(test)]
167 mod try_seek {
168 use super::*;
169 use crate::common::{ChannelCount, SampleRate};
170 use crate::Sample;
171 use std::time::Duration;
172
173 #[test]
174 fn channel_order_stays_correct() {
175 const SAMPLE_RATE: SampleRate = 100;
176 const CHANNELS: ChannelCount = 2;
177 let mut buf = SamplesBuffer::new(
178 CHANNELS,
179 SAMPLE_RATE,
180 (0..2000i16).map(|s| s as Sample).collect::<Vec<_>>(),
181 );
182 buf.try_seek(Duration::from_secs(5)).unwrap();
183 assert_eq!(buf.next(), Some(5.0 * SAMPLE_RATE as f32 * CHANNELS as f32));
184
185 assert!(buf.next().is_some_and(|s| s.trunc() as i32 % 2 == 1));
186 assert!(buf.next().is_some_and(|s| s.trunc() as i32 % 2 == 0));
187
188 buf.try_seek(Duration::from_secs(6)).unwrap();
189 assert!(buf.next().is_some_and(|s| s.trunc() as i32 % 2 == 1),);
190 }
191 }
192}