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