rill_core_dsp/generators/
sample_player.rs1use crate::generators::{Generator, InterpolatedReader};
8use rill_core::traits::algorithm::{Algorithm, AlgorithmCategory, AlgorithmMetadata};
9use rill_core::traits::ProcessResult;
10use rill_core::Transcendental;
11
12#[derive(Debug, Clone, Copy, PartialEq)]
14pub enum LoopMode {
15 OneShot,
17 Forward,
19 PingPong,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq)]
25pub enum PlayState {
26 Stopped,
28 Playing,
30}
31
32pub struct SamplePlayer<T: Transcendental> {
47 reader: InterpolatedReader<T>,
48 loop_mode: LoopMode,
49 loop_start: f64,
50 loop_end: f64,
51 state: PlayState,
52 gate: bool,
53 amplitude: T,
54 sample_rate: f32,
55}
56
57impl<T: Transcendental> SamplePlayer<T> {
58 pub fn new(buffer: Vec<T>) -> Self {
60 let len = buffer.len() as f64;
61 Self {
62 reader: InterpolatedReader::new(buffer),
63 loop_mode: LoopMode::OneShot,
64 loop_start: 0.0,
65 loop_end: len,
66 state: PlayState::Stopped,
67 gate: false,
68 amplitude: T::from_f32(1.0),
69 sample_rate: 44100.0,
70 }
71 }
72
73 pub fn from_boxed(buffer: Box<[T]>) -> Self {
75 let len = buffer.len() as f64;
76 Self {
77 reader: InterpolatedReader::from_boxed(buffer),
78 loop_mode: LoopMode::OneShot,
79 loop_start: 0.0,
80 loop_end: len,
81 state: PlayState::Stopped,
82 gate: false,
83 amplitude: T::from_f32(1.0),
84 sample_rate: 44100.0,
85 }
86 }
87
88 pub fn len(&self) -> usize {
90 self.reader.len()
91 }
92
93 pub fn is_empty(&self) -> bool {
95 self.reader.is_empty()
96 }
97
98 pub fn loop_mode(&self) -> LoopMode {
100 self.loop_mode
101 }
102
103 pub fn set_loop_mode(&mut self, mode: LoopMode) {
105 self.loop_mode = mode;
106 }
107
108 pub fn loop_start(&self) -> f64 {
110 self.loop_start
111 }
112
113 pub fn set_loop_start(&mut self, start: f64) {
115 self.loop_start = start.clamp(0.0, self.reader.len() as f64);
116 }
117
118 pub fn loop_end(&self) -> f64 {
120 self.loop_end
121 }
122
123 pub fn set_loop_end(&mut self, end: f64) {
125 let max = self.reader.len() as f64;
126 self.loop_end = end.clamp(0.0, max);
127 }
128
129 pub fn gate(&self) -> bool {
131 self.gate
132 }
133
134 pub fn set_gate(&mut self, gate: bool) {
138 if gate && !self.gate {
139 self.reader.set_position(self.loop_start);
140 self.state = PlayState::Playing;
141 } else if !gate {
142 self.state = PlayState::Stopped;
143 }
144 self.gate = gate;
145 }
146
147 pub fn play_state(&self) -> PlayState {
149 self.state
150 }
151
152 pub fn set_buffer(&mut self, buffer: Vec<T>) {
154 self.reader.set_buffer(buffer);
155 self.loop_end = self.reader.len() as f64;
156 self.loop_start = 0.0;
157 }
158
159 pub fn set_cubic(&mut self, cubic: bool) {
161 self.reader.set_cubic(cubic);
162 }
163
164 pub fn is_cubic(&self) -> bool {
166 self.reader.is_cubic()
167 }
168
169 pub fn set_playback_rate(&mut self, rate: f64) {
171 self.reader.set_rate(rate);
172 }
173
174 pub fn playback_rate(&self) -> f64 {
176 self.reader.rate()
177 }
178}
179
180impl<T: Transcendental> Algorithm<T> for SamplePlayer<T> {
181 fn init(&mut self, sample_rate: f32) {
182 self.sample_rate = sample_rate;
183 self.reader.set_position(self.loop_start);
184 self.state = PlayState::Stopped;
185 }
186
187 fn reset(&mut self) {
188 self.gate = false;
189 self.state = PlayState::Stopped;
190 self.reader.set_position(self.loop_start);
191 }
192
193 fn process(&mut self, _input: Option<&[T]>, output: &mut [T]) -> ProcessResult<()> {
194 if !self.gate || self.state == PlayState::Stopped || self.is_empty() {
195 for s in output.iter_mut() {
196 *s = T::ZERO;
197 }
198 return Ok(());
199 }
200
201 let amp = self.amplitude;
202 let start = self.loop_start;
203 let end = self.loop_end;
204
205 for s in output.iter_mut() {
206 if !self.gate || self.state == PlayState::Stopped {
207 *s = T::ZERO;
208 continue;
209 }
210
211 *s = self.reader.read_one() * amp;
212 self.reader.advance();
213
214 let pos = self.reader.position();
215 let going_forward = self.reader.rate() >= 0.0;
216
217 if self.loop_mode == LoopMode::OneShot {
218 if pos >= end || pos < 0.0 {
219 self.state = PlayState::Stopped;
220 self.gate = false;
221 }
222 } else if self.loop_mode == LoopMode::Forward {
223 if going_forward && pos >= end {
224 self.reader.set_position(start + (pos - end));
225 } else if !going_forward && pos < start {
226 self.reader.set_position(end - (start - pos));
227 }
228 } else if going_forward && pos >= end {
229 self.reader.set_rate(-self.reader.rate());
231 self.reader.set_position(end - 1.0);
232 } else if !going_forward && pos <= start {
233 self.reader.set_rate(-self.reader.rate());
235 self.reader.set_position(start);
236 }
237 }
238
239 Ok(())
240 }
241
242 fn metadata(&self) -> AlgorithmMetadata {
243 AlgorithmMetadata {
244 name: "SamplePlayer",
245 category: AlgorithmCategory::Generator,
246 description: "Sample playback with loop modes",
247 author: "Rill",
248 version: env!("CARGO_PKG_VERSION"),
249 }
250 }
251}
252
253impl<T: Transcendental + Copy> Generator<T> for SamplePlayer<T> {
254 fn phase(&self) -> T {
255 let len = self.reader.len() as f64;
256 if len == 0.0 {
257 return T::ZERO;
258 }
259 T::from_f64((self.reader.position() / len).clamp(0.0, 1.0))
260 }
261
262 fn set_phase(&mut self, phase: T) {
263 let p = phase.to_f64().clamp(0.0, 1.0);
264 let len = self.reader.len() as f64;
265 self.reader.set_position(p * len);
266 }
267
268 fn reset_phase(&mut self) {
269 self.reader.set_position(0.0);
270 }
271
272 fn frequency(&self) -> f32 {
273 if self.is_empty() {
274 return 0.0;
275 }
276 let rate = self.reader.rate();
277 let len = self.reader.len() as f64;
278 (rate * self.sample_rate as f64 / len) as f32
279 }
280
281 fn set_frequency(&mut self, freq: f32) {
282 if self.is_empty() {
283 return;
284 }
285 let len = self.reader.len() as f64;
286 let rate = freq as f64 * len / self.sample_rate as f64;
287 self.reader.set_rate(rate);
288 }
289
290 fn amplitude(&self) -> T {
291 self.amplitude
292 }
293
294 fn set_amplitude(&mut self, amp: T) {
295 self.amplitude = amp.clamp(T::ZERO, T::from_f32(1.0));
296 }
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302 fn process(player: &mut SamplePlayer<f64>, out: &mut [f64]) {
303 player.process(None, out).unwrap();
304 }
305
306 #[test]
307 fn test_one_shot() {
308 let buf = vec![1.0, 2.0, 3.0, 4.0];
309 let mut player = SamplePlayer::new(buf);
310 player.set_gate(true);
311 let mut out = [0.0f64; 6];
312 process(&mut player, &mut out[..3]);
313 assert!(
314 player.play_state() == PlayState::Playing,
315 "still playing after 3/4"
316 );
317 process(&mut player, &mut out[3..]);
318 assert_eq!(out[0..4], [1.0, 2.0, 3.0, 4.0], "all samples read");
319 assert_eq!(out[4..6], [0.0, 0.0], "silence after end");
320 assert_eq!(player.play_state(), PlayState::Stopped, "stopped after end");
321 }
322
323 #[test]
324 fn test_loop_forward() {
325 let buf = vec![1.0, 2.0, 3.0];
326 let mut player = SamplePlayer::new(buf);
327 player.set_loop_mode(LoopMode::Forward);
328 player.set_gate(true);
329 let mut out = [0.0f64; 6];
330 process(&mut player, &mut out);
331 assert_eq!(out, [1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
332 }
333
334 #[test]
335 fn test_ping_pong() {
336 let buf = vec![1.0, 2.0, 3.0, 4.0];
337 let mut player = SamplePlayer::new(buf);
338 player.set_loop_mode(LoopMode::PingPong);
339 player.set_gate(true);
340 let mut out = [0.0f64; 12];
341 process(&mut player, &mut out);
342 assert_eq!(out[0..4], [1.0, 2.0, 3.0, 4.0], "forward pass");
344 assert_eq!(out[5..8], [3.0, 2.0, 1.0], "reverse pass (minus endpoint)");
345 assert_eq!(out[8..11], [2.0, 3.0, 4.0], "second forward pass");
346 }
347
348 #[test]
349 fn test_gate_restart() {
350 let buf = vec![10.0, 20.0, 30.0];
351 let mut player = SamplePlayer::new(buf);
352 player.set_gate(true);
353 let mut out = [0.0f64; 2];
354 process(&mut player, &mut out);
355 assert_eq!(out, [10.0, 20.0]);
356 player.set_gate(false);
357 process(&mut player, &mut out);
358 assert_eq!(out, [0.0, 0.0]);
359 player.set_gate(true);
360 process(&mut player, &mut out);
361 assert_eq!(out, [10.0, 20.0]);
362 }
363
364 #[test]
365 fn test_frequency_mapping() {
366 let buf = vec![1.0, 2.0, 3.0, 4.0];
367 let mut player = SamplePlayer::new(buf);
368 player.init(44100.0);
369 let freq_at_unit_rate = player.frequency();
370 assert!(
371 (freq_at_unit_rate - 44100.0 / 4.0).abs() < 1.0,
372 "expected ~11025 Hz at rate=1, got {}",
373 freq_at_unit_rate
374 );
375 player.set_frequency(freq_at_unit_rate * 2.0);
376 assert!(
377 (player.playback_rate() - 2.0).abs() < 1e-6,
378 "expected rate=2.0, got {}",
379 player.playback_rate()
380 );
381 }
382
383 #[test]
384 fn test_empty_buffer() {
385 let buf: Vec<f64> = vec![];
386 let mut player = SamplePlayer::new(buf);
387 player.set_gate(true);
388 let mut out = [1.0f64; 4];
389 process(&mut player, &mut out);
390 assert_eq!(out, [0.0; 4]);
391 }
392}