1use rill_core::time::ClockTick;
2use rill_core::traits::{
3 Algorithm, SignalNode, NodeCategory, NodeId, NodeMetadata, NodeState, ParamValue, ParameterId,
4 Port, 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![Port::output(NodeId(0), 0, "left")],
60 state: None,
61 _phantom: PhantomData,
62 }
63 }
64
65 pub fn load(&mut self, sample: SampleBuffer<T>) {
67 let len = sample.len() as f64;
68 self.loop_end = len;
69 self.loop_start = 0.0;
70
71 self.left.set_buffer(sample.data);
72 self.left
73 .set_loop_start(self.loop_start);
74 self.left.set_loop_end(self.loop_end);
75 self.left
76 .set_loop_mode(self.loop_mode);
77 self.left
78 .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
92 .push(Port::output(NodeId(0), 1, "right"));
93 }
94 } else {
95 self.right = None;
96 self.outputs.truncate(1);
97 }
98 }
99
100 pub fn play(&mut self) {
102 self.gate = true;
103 self.left.set_gate(true);
104 if let Some(ref mut r) = self.right {
105 r.set_gate(true);
106 }
107 }
108
109 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> SignalNode<T, BUF_SIZE>
137 for SamplePlayerNode<T, BUF_SIZE>
138{
139 fn metadata(&self) -> NodeMetadata {
140 NodeMetadata {
141 name: "SamplePlayer".to_string(),
142 type_name: None,
143 category: NodeCategory::Source,
144 description: "Sample playback node with loop modes and stereo".to_string(),
145 author: "Rill".to_string(),
146 version: env!("CARGO_PKG_VERSION").to_string(),
147 signal_inputs: 0,
148 signal_outputs: if self.right.is_some() { 2 } else { 1 },
149 control_inputs: 0,
150 control_outputs: 0,
151 clock_inputs: 0,
152 clock_outputs: 0,
153 feedback_ports: 0,
154 parameters: vec![],
155 }
156 }
157
158 fn init(&mut self, sample_rate: f32) {
159 self.left.init(sample_rate);
160 if let Some(ref mut r) = self.right {
161 r.init(sample_rate);
162 }
163 self.state = Some(NodeState::new(sample_rate));
164 }
165
166 fn reset(&mut self) {
167 self.left.reset();
168 if let Some(ref mut r) = self.right {
169 r.reset();
170 }
171 self.gate = false;
172 if let Some(state) = &mut self.state {
173 state.reset();
174 }
175 }
176
177 fn get_parameter(&self, id: &ParameterId) -> Option<ParamValue> {
178 match id.as_str() {
179 "gate" => Some(ParamValue::Bool(self.gate)),
180 "rate" => Some(ParamValue::Float(self.rate as f32)),
181 "loop_mode" => {
182 let s = match self.loop_mode {
183 LoopMode::OneShot => "oneshot",
184 LoopMode::Forward => "forward",
185 LoopMode::PingPong => "pingpong",
186 };
187 Some(ParamValue::Choice(s.into()))
188 }
189 "start" => {
190 let len = self.left.len().max(1) as f64;
191 Some(ParamValue::Float((self.loop_start / len) as f32))
192 }
193 "end" => {
194 let len = self.left.len().max(1) as f64;
195 Some(ParamValue::Float((self.loop_end / len) as f32))
196 }
197 "amplitude" => Some(Self::t_to_param(self.amplitude)),
198 "interpolation" => Some(ParamValue::Choice(
199 if self.cubic { "cubic" } else { "linear" }.into(),
200 )),
201 "position" => Some(ParamValue::Float(self.left.phase().to_f32())),
202 _ => None,
203 }
204 }
205
206 fn set_parameter(&mut self, id: &ParameterId, value: ParamValue) -> ProcessResult<()> {
207 let len = self.left.len().max(1) as f64;
208 match id.as_str() {
209 "gate" => {
210 if let ParamValue::Bool(b) = value {
211 self.gate = b;
212 self.left.set_gate(b);
213 if let Some(ref mut r) = self.right {
214 r.set_gate(b);
215 }
216 Ok(())
217 } else {
218 Err(ProcessError::Parameter("Expected bool".into()))
219 }
220 }
221 "rate" => {
222 if let Some(r) = Self::param_to_t(value) {
223 self.rate = r.to_f64().clamp(0.0, 4.0);
224 self.left.set_playback_rate(self.rate);
225 if let Some(ref mut rp) = self.right {
226 rp.set_playback_rate(self.rate);
227 }
228 Ok(())
229 } else {
230 Err(ProcessError::Parameter("Expected float".into()))
231 }
232 }
233 "loop_mode" => {
234 if let ParamValue::Choice(s) = &value {
235 self.loop_mode = match s.as_str() {
236 "forward" => LoopMode::Forward,
237 "pingpong" => LoopMode::PingPong,
238 _ => LoopMode::OneShot,
239 };
240 self.left.set_loop_mode(self.loop_mode);
241 if let Some(ref mut r) = self.right {
242 r.set_loop_mode(self.loop_mode);
243 }
244 Ok(())
245 } else {
246 Err(ProcessError::Parameter("Expected choice".into()))
247 }
248 }
249 "start" => {
250 if let Some(s) = Self::param_to_t(value) {
251 self.loop_start = (s.to_f64() * len).clamp(0.0, self.loop_end);
252 self.left.set_loop_start(self.loop_start);
253 if let Some(ref mut r) = self.right {
254 r.set_loop_start(self.loop_start);
255 }
256 Ok(())
257 } else {
258 Err(ProcessError::Parameter("Expected float".into()))
259 }
260 }
261 "end" => {
262 if let Some(e) = Self::param_to_t(value) {
263 self.loop_end = (e.to_f64() * len).clamp(self.loop_start, len);
264 self.left.set_loop_end(self.loop_end);
265 if let Some(ref mut r) = self.right {
266 r.set_loop_end(self.loop_end);
267 }
268 Ok(())
269 } else {
270 Err(ProcessError::Parameter("Expected float".into()))
271 }
272 }
273 "amplitude" => {
274 if let Some(a) = Self::param_to_t(value) {
275 self.amplitude = a.clamp(T::ZERO, T::from_f32(1.0));
276 Ok(())
277 } else {
278 Err(ProcessError::Parameter("Expected float".into()))
279 }
280 }
281 "interpolation" => {
282 if let ParamValue::Choice(s) = &value {
283 self.cubic = s == "cubic";
284 self.left.set_cubic(self.cubic);
285 if let Some(ref mut r) = self.right {
286 r.set_cubic(self.cubic);
287 }
288 Ok(())
289 } else {
290 Err(ProcessError::Parameter("Expected choice".into()))
291 }
292 }
293 _ => Err(ProcessError::Parameter(format!(
294 "Unknown parameter: {}",
295 id
296 ))),
297 }
298 }
299
300 fn id(&self) -> NodeId {
301 NodeId(0)
302 }
303
304 fn set_id(&mut self, _id: NodeId) {}
305
306 fn input_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
307 None
308 }
309
310 fn input_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
311 None
312 }
313
314 fn output_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
315 self.outputs.get(index)
316 }
317
318 fn output_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
319 self.outputs.get_mut(index)
320 }
321
322 fn control_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
323 None
324 }
325
326 fn control_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
327 None
328 }
329
330 fn state(&self) -> &NodeState<T, BUF_SIZE> {
331 self.state.as_ref().unwrap()
332 }
333
334 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE> {
335 self.state.as_mut().unwrap()
336 }
337
338 fn num_signal_inputs(&self) -> usize {
339 0
340 }
341
342 fn num_signal_outputs(&self) -> usize {
343 self.outputs.len()
344 }
345}
346
347impl<T: Transcendental, const BUF_SIZE: usize> Source<T, BUF_SIZE>
348 for SamplePlayerNode<T, BUF_SIZE>
349{
350 fn generate(
351 &mut self,
352 clock: &ClockTick,
353 _control_inputs: &[T],
354 _clock_inputs: &[ClockTick],
355 ) -> ProcessResult<()> {
356 let amp = self.amplitude;
357
358 let mut temp = [T::ZERO; BUF_SIZE];
359 self.left
360 .process(None, &mut temp[..], &rill_core::traits::ActionContext::new(clock))?;
361 if amp != T::from_f32(1.0) {
362 for s in temp.iter_mut() {
363 *s = *s * amp;
364 }
365 }
366 *self.outputs[0].buffer.as_mut_array() = temp;
367
368 if let Some(ref mut right_player) = self.right {
369 let mut right_temp = [T::ZERO; BUF_SIZE];
370 right_player
371 .process(None, &mut right_temp[..], &rill_core::traits::ActionContext::new(clock))?;
372 if amp != T::from_f32(1.0) {
373 for s in right_temp.iter_mut() {
374 *s = *s * amp;
375 }
376 }
377 if self.outputs.len() > 1 {
378 *self.outputs[1].buffer.as_mut_array() = right_temp;
379 }
380 }
381
382 Ok(())
383 }
384}