1use rill_core::time::{ClockTick, RenderContext};
2use rill_core::traits::{
3 Algorithm, Node, NodeCategory, NodeId, NodeMetadata, NodeState, ParamValue, ParameterId, Port,
4 Source,
5};
6use rill_core::Transcendental;
7use rill_core::{ProcessError, ProcessResult};
8use rill_core_dsp::generators::{Generator, LoopMode, SamplePlayer};
9use std::marker::PhantomData;
10
11use crate::buffer::SampleBuffer;
12
13pub struct SamplePlayerNode<T: Transcendental, const BUF_SIZE: usize> {
32 left: SamplePlayer<T>,
33 right: Option<SamplePlayer<T>>,
34 gate: bool,
35 amplitude: T,
36 rate: f64,
37 loop_mode: LoopMode,
38 loop_start: f64,
39 loop_end: f64,
40 cubic: bool,
41 outputs: Vec<Port<T, BUF_SIZE>>,
42 state: Option<NodeState<T, BUF_SIZE>>,
43 _phantom: PhantomData<[T; BUF_SIZE]>,
44}
45
46impl<T: Transcendental, const BUF_SIZE: usize> SamplePlayerNode<T, BUF_SIZE> {
47 pub fn new() -> Self {
49 Self {
50 left: SamplePlayer::new(Vec::new()),
51 right: None,
52 gate: false,
53 amplitude: T::from_f32(1.0),
54 rate: 1.0,
55 loop_mode: LoopMode::OneShot,
56 loop_start: 0.0,
57 loop_end: 0.0,
58 cubic: false,
59 outputs: vec![
60 Port::output(NodeId(0), 0, "left"),
61 Port::output(NodeId(0), 1, "right"),
62 ],
63 state: None,
64 _phantom: PhantomData,
65 }
66 }
67
68 pub fn load(&mut self, sample: SampleBuffer<T>) {
70 let len = sample.len() as f64;
71 self.loop_end = len;
72 self.loop_start = 0.0;
73
74 self.left.set_buffer(sample.data);
75 self.left.set_loop_start(self.loop_start);
76 self.left.set_loop_end(self.loop_end);
77 self.left.set_loop_mode(self.loop_mode);
78 self.left.set_playback_rate(self.rate);
79 self.left.set_cubic(self.cubic);
80
81 if let Some(right_data) = sample.right {
82 let mut right_player = SamplePlayer::new(right_data);
83 right_player.set_loop_start(self.loop_start);
84 right_player.set_loop_end(self.loop_end);
85 right_player.set_loop_mode(self.loop_mode);
86 right_player.set_playback_rate(self.rate);
87 right_player.set_cubic(self.cubic);
88 self.right = Some(right_player);
89
90 if self.outputs.len() < 2 {
91 self.outputs.push(Port::output(NodeId(0), 1, "right"));
92 }
93 } else {
94 self.right = None;
95 self.outputs.truncate(1);
96 }
97 }
98
99 pub fn play(&mut self) {
101 self.gate = true;
102 self.left.set_gate(true);
103 if let Some(ref mut r) = self.right {
104 r.set_gate(true);
105 }
106 }
107
108 pub fn stop(&mut self) {
110 self.gate = false;
111 self.left.set_gate(false);
112 if let Some(ref mut r) = self.right {
113 r.set_gate(false);
114 }
115 }
116
117 fn param_to_t(value: ParamValue) -> Option<T> {
118 match value {
119 ParamValue::Float(f) => Some(T::from_f32(f)),
120 ParamValue::Int(i) => Some(T::from_f32(i as f32)),
121 _ => None,
122 }
123 }
124
125 fn t_to_param(value: T) -> ParamValue {
126 ParamValue::Float(value.to_f32())
127 }
128}
129
130impl<T: Transcendental, const BUF_SIZE: usize> Default for SamplePlayerNode<T, BUF_SIZE> {
131 fn default() -> Self {
132 Self::new()
133 }
134}
135
136impl<T: Transcendental, const BUF_SIZE: usize> Node<T, BUF_SIZE> for SamplePlayerNode<T, BUF_SIZE> {
137 fn metadata(&self) -> NodeMetadata {
138 NodeMetadata {
139 name: "SamplePlayer".to_string(),
140 type_name: None,
141 category: NodeCategory::Source,
142 description: "Sample playback node with loop modes and stereo".to_string(),
143 author: "Rill".to_string(),
144 version: env!("CARGO_PKG_VERSION").to_string(),
145 signal_inputs: 0,
146 signal_outputs: self.outputs.len(),
147 control_inputs: 0,
148 control_outputs: 0,
149 clock_inputs: 0,
150 clock_outputs: 0,
151 feedback_ports: 0,
152 parameters: vec![],
153 }
154 }
155
156 fn init(&mut self, sample_rate: f32) {
157 self.left.init(sample_rate);
158 if let Some(ref mut r) = self.right {
159 r.init(sample_rate);
160 }
161 self.state = Some(NodeState::new(sample_rate));
162 }
163
164 fn reset(&mut self) {
165 self.left.reset();
166 if let Some(ref mut r) = self.right {
167 r.reset();
168 }
169 self.gate = false;
170 if let Some(state) = &mut self.state {
171 state.reset();
172 }
173 }
174
175 fn get_parameter(&self, id: &ParameterId) -> Option<ParamValue> {
176 match id.as_str() {
177 "gate" => Some(ParamValue::Bool(self.gate)),
178 "rate" => Some(ParamValue::Float(self.rate as f32)),
179 "loop_mode" => {
180 let s = match self.loop_mode {
181 LoopMode::OneShot => "oneshot",
182 LoopMode::Forward => "forward",
183 LoopMode::PingPong => "pingpong",
184 };
185 Some(ParamValue::Choice(s.into()))
186 }
187 "start" => {
188 let len = self.left.len().max(1) as f64;
189 Some(ParamValue::Float((self.loop_start / len) as f32))
190 }
191 "end" => {
192 let len = self.left.len().max(1) as f64;
193 Some(ParamValue::Float((self.loop_end / len) as f32))
194 }
195 "amplitude" => Some(Self::t_to_param(self.amplitude)),
196 "interpolation" => Some(ParamValue::Choice(
197 if self.cubic { "cubic" } else { "linear" }.into(),
198 )),
199 "position" => Some(ParamValue::Float(self.left.phase().to_f32())),
200 _ => None,
201 }
202 }
203
204 fn set_parameter(&mut self, id: &ParameterId, value: ParamValue) -> ProcessResult<()> {
205 let len = self.left.len().max(1) as f64;
206 match id.as_str() {
207 "gate" => {
208 if let ParamValue::Bool(b) = value {
209 self.gate = b;
210 self.left.set_gate(b);
211 if let Some(ref mut r) = self.right {
212 r.set_gate(b);
213 }
214 Ok(())
215 } else {
216 Err(ProcessError::Parameter("Expected bool".into()))
217 }
218 }
219 "rate" => {
220 if let Some(r) = Self::param_to_t(value) {
221 self.rate = r.to_f64().clamp(0.0, 4.0);
222 self.left.set_playback_rate(self.rate);
223 if let Some(ref mut rp) = self.right {
224 rp.set_playback_rate(self.rate);
225 }
226 Ok(())
227 } else {
228 Err(ProcessError::Parameter("Expected float".into()))
229 }
230 }
231 "loop_mode" => {
232 if let ParamValue::Choice(s) = &value {
233 self.loop_mode = match s.as_str() {
234 "forward" => LoopMode::Forward,
235 "pingpong" => LoopMode::PingPong,
236 _ => LoopMode::OneShot,
237 };
238 self.left.set_loop_mode(self.loop_mode);
239 if let Some(ref mut r) = self.right {
240 r.set_loop_mode(self.loop_mode);
241 }
242 Ok(())
243 } else {
244 Err(ProcessError::Parameter("Expected choice".into()))
245 }
246 }
247 "start" => {
248 if let Some(s) = Self::param_to_t(value) {
249 self.loop_start = (s.to_f64() * len).clamp(0.0, self.loop_end);
250 self.left.set_loop_start(self.loop_start);
251 if let Some(ref mut r) = self.right {
252 r.set_loop_start(self.loop_start);
253 }
254 Ok(())
255 } else {
256 Err(ProcessError::Parameter("Expected float".into()))
257 }
258 }
259 "end" => {
260 if let Some(e) = Self::param_to_t(value) {
261 self.loop_end = (e.to_f64() * len).clamp(self.loop_start, len);
262 self.left.set_loop_end(self.loop_end);
263 if let Some(ref mut r) = self.right {
264 r.set_loop_end(self.loop_end);
265 }
266 Ok(())
267 } else {
268 Err(ProcessError::Parameter("Expected float".into()))
269 }
270 }
271 "amplitude" => {
272 if let Some(a) = Self::param_to_t(value) {
273 self.amplitude = a.clamp(T::ZERO, T::from_f32(1.0));
274 Ok(())
275 } else {
276 Err(ProcessError::Parameter("Expected float".into()))
277 }
278 }
279 "interpolation" => {
280 if let ParamValue::Choice(s) = &value {
281 self.cubic = s == "cubic";
282 self.left.set_cubic(self.cubic);
283 if let Some(ref mut r) = self.right {
284 r.set_cubic(self.cubic);
285 }
286 Ok(())
287 } else {
288 Err(ProcessError::Parameter("Expected choice".into()))
289 }
290 }
291 "source" => {
292 if let ParamValue::SignalSlab(slab) = value {
293 if let Ok(mut s) = std::sync::Arc::try_unwrap(slab) {
294 let len = s.num_frames as f64;
295 self.loop_end = len;
296 self.loop_start = 0.0;
297
298 if !s.channels.is_empty() {
299 let boxed: Box<[T]> = s
300 .channels
301 .remove(0)
302 .into_vec()
303 .into_iter()
304 .map(T::from_f32)
305 .collect::<Vec<T>>()
306 .into_boxed_slice();
307 self.left = SamplePlayer::from_boxed(boxed);
308 self.left.set_loop_start(0.0);
309 self.left.set_loop_end(len);
310 self.left.set_loop_mode(self.loop_mode);
311 self.left.set_playback_rate(self.rate);
312 self.left.set_cubic(self.cubic);
313 }
314
315 if !s.channels.is_empty() {
316 let boxed: Box<[T]> = s
317 .channels
318 .remove(0)
319 .into_vec()
320 .into_iter()
321 .map(T::from_f32)
322 .collect::<Vec<T>>()
323 .into_boxed_slice();
324 let mut rp = SamplePlayer::from_boxed(boxed);
325 rp.set_loop_start(0.0);
326 rp.set_loop_end(len);
327 rp.set_loop_mode(self.loop_mode);
328 rp.set_playback_rate(self.rate);
329 rp.set_cubic(self.cubic);
330 self.right = Some(rp);
331
332 if self.outputs.len() < 2 {
333 self.outputs.push(Port::output(NodeId(0), 1, "right"));
334 }
335 } else {
336 self.right = None;
337 self.outputs.truncate(1);
338 }
339
340 self.gate = true;
341 self.left.set_gate(true);
342 if let Some(ref mut r) = self.right {
343 r.set_gate(true);
344 }
345 Ok(())
346 } else {
347 Err(ProcessError::Parameter("SignalSlab is still shared".into()))
348 }
349 } else {
350 Err(ProcessError::Parameter("Expected SignalSlab".into()))
351 }
352 }
353 _ => Err(ProcessError::Parameter(format!(
354 "Unknown parameter: {}",
355 id
356 ))),
357 }
358 }
359
360 fn id(&self) -> NodeId {
361 NodeId(0)
362 }
363
364 fn set_id(&mut self, _id: NodeId) {}
365
366 fn input_port(&self, _index: usize) -> Option<&Port<T, BUF_SIZE>> {
367 None
368 }
369
370 fn input_port_mut(&mut self, _index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
371 None
372 }
373
374 fn output_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
375 self.outputs.get(index)
376 }
377
378 fn output_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
379 self.outputs.get_mut(index)
380 }
381
382 fn control_port(&self, _index: usize) -> Option<&Port<T, BUF_SIZE>> {
383 None
384 }
385
386 fn control_port_mut(&mut self, _index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
387 None
388 }
389
390 fn state(&self) -> &NodeState<T, BUF_SIZE> {
391 self.state.as_ref().unwrap()
392 }
393
394 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE> {
395 self.state.as_mut().unwrap()
396 }
397
398 fn num_signal_inputs(&self) -> usize {
399 0
400 }
401
402 fn num_signal_outputs(&self) -> usize {
403 self.outputs.len()
404 }
405}
406
407impl<T: Transcendental, const BUF_SIZE: usize> Source<T, BUF_SIZE>
408 for SamplePlayerNode<T, BUF_SIZE>
409{
410 fn generate(
411 &mut self,
412 _ctx: &RenderContext,
413 _control_inputs: &[T],
414 _clock_inputs: &[RenderContext],
415 _tick: &ClockTick,
416 ) -> ProcessResult<()> {
417 let amp = self.amplitude;
418
419 let left_out = self.outputs[0].write();
420 self.left.process(None, &mut left_out[..])?;
421 if amp != T::from_f32(1.0) {
422 for s in left_out.iter_mut() {
423 *s *= amp;
424 }
425 }
426
427 if let Some(ref mut right_player) = self.right {
428 if self.outputs.len() > 1 {
429 let right_out = self.outputs[1].write();
430 right_player.process(None, &mut right_out[..])?;
431 if amp != T::from_f32(1.0) {
432 for s in right_out.iter_mut() {
433 *s *= amp;
434 }
435 }
436 }
437 }
438
439 self.state.as_mut().unwrap().advance();
440 Ok(())
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447 use rill_core::traits::Node;
448
449 #[test]
450 fn test_set_and_get_parameter() {
451 const B: usize = 64;
452 let mut player = SamplePlayerNode::<f32, B>::new();
453
454 let pid = ParameterId::new("rate").unwrap();
456 let _ = player.set_parameter(&pid, ParamValue::Float(2.0));
457 let val = player.get_parameter(&pid);
458 assert_eq!(val, Some(ParamValue::Float(2.0)));
459
460 let pid = ParameterId::new("amplitude").unwrap();
462 let _ = player.set_parameter(&pid, ParamValue::Float(0.75));
463 let val = player.get_parameter(&pid);
464 assert_eq!(val, Some(ParamValue::Float(0.75)));
465
466 let pid = ParameterId::new("gate").unwrap();
468 let _ = player.set_parameter(&pid, ParamValue::Bool(true));
469 let val = player.get_parameter(&pid);
470 assert_eq!(val, Some(ParamValue::Bool(true)));
471
472 let unknown = ParameterId::new("nonexistent").unwrap();
474 let result = player.set_parameter(&unknown, ParamValue::Float(0.0));
475 assert!(result.is_err());
476 assert!(player.get_parameter(&unknown).is_none());
477 }
478}