1use crate::{
2 error::{ParameterError, RytmError},
3 object::pattern::plock::ParameterLockPool,
4 util::{from_s_u16_t, to_s_u16_t_union_a},
5 RytmError::OrphanTrig,
6};
7use derivative::Derivative;
8use parking_lot::Mutex;
9use rytm_rs_macro::parameter_range;
10use rytm_sys::ar_sound_t;
11use serde::{Deserialize, Serialize};
12use std::sync::Arc;
13
14#[derive(Derivative, Clone, Serialize, Deserialize)]
16#[derivative(Debug)]
17pub struct HhLabParameters {
18 lev: u8,
19 osc1: u16, dec: u8,
21 osc2: u16,
22 osc3: u16,
23 osc4: u16,
24 osc5: u16,
25 osc6: u16,
26
27 #[derivative(Debug = "ignore")]
28 #[serde(skip)]
29 parameter_lock_pool: Option<Arc<Mutex<ParameterLockPool>>>,
30 assigned_track: Option<usize>,
31}
32
33impl Default for HhLabParameters {
34 fn default() -> Self {
35 Self {
36 lev: 110,
37 osc1: 512,
38 dec: 29,
39 osc2: 768,
40 osc3: 1024,
41 osc4: 1280,
42 osc5: 1536,
43 osc6: 1792,
44 parameter_lock_pool: None,
45 assigned_track: None,
46 }
47 }
48}
49
50impl HhLabParameters {
51 pub(crate) fn link_parameter_lock_pool(&mut self, pool: Arc<Mutex<ParameterLockPool>>) {
52 self.parameter_lock_pool = Some(pool);
53 }
54
55 pub(crate) fn apply_to_raw_sound(&self, raw_sound: &mut ar_sound_t) {
56 raw_sound.synth_param_1 = to_s_u16_t_union_a((self.lev as u16) << 8);
57 raw_sound.synth_param_2 = to_s_u16_t_union_a(self.osc1);
58 raw_sound.synth_param_3 = to_s_u16_t_union_a((self.dec as u16) << 8);
59 raw_sound.synth_param_4 = to_s_u16_t_union_a(self.osc2);
60 raw_sound.synth_param_5 = to_s_u16_t_union_a(self.osc3);
61 raw_sound.synth_param_6 = to_s_u16_t_union_a(self.osc4);
62 raw_sound.synth_param_7 = to_s_u16_t_union_a(self.osc5);
63 raw_sound.synth_param_8 = to_s_u16_t_union_a(self.osc6);
64 }
65
66 #[parameter_range(range = "lev:0..=127")]
70 pub fn set_lev(&mut self, lev: usize) -> Result<(), RytmError> {
71 self.lev = lev as u8;
72 Ok(())
73 }
74
75 #[parameter_range(range = "osc1:0..=16256")]
79 pub fn set_osc1(&mut self, osc1: usize) -> Result<(), RytmError> {
80 self.osc1 = osc1 as u16;
81 Ok(())
82 }
83
84 #[parameter_range(range = "dec:0..=127")]
88 pub fn set_dec(&mut self, dec: usize) -> Result<(), RytmError> {
89 self.dec = dec as u8;
90 Ok(())
91 }
92
93 #[parameter_range(range = "osc2:0..=16256")]
97 pub fn set_osc2(&mut self, osc2: usize) -> Result<(), RytmError> {
98 self.osc2 = osc2 as u16;
99 Ok(())
100 }
101
102 #[parameter_range(range = "osc3:0..=16256")]
106 pub fn set_osc3(&mut self, osc3: usize) -> Result<(), RytmError> {
107 self.osc3 = osc3 as u16;
108 Ok(())
109 }
110
111 #[parameter_range(range = "osc4:0..=16256")]
115 pub fn set_osc4(&mut self, osc4: usize) -> Result<(), RytmError> {
116 self.osc4 = osc4 as u16;
117 Ok(())
118 }
119
120 #[parameter_range(range = "osc5:0..=16256")]
124 pub fn set_osc5(&mut self, osc5: usize) -> Result<(), RytmError> {
125 self.osc5 = osc5 as u16;
126 Ok(())
127 }
128
129 #[parameter_range(range = "osc6:0..=16256")]
133 pub fn set_osc6(&mut self, osc6: usize) -> Result<(), RytmError> {
134 self.osc6 = osc6 as u16;
135 Ok(())
136 }
137
138 pub const fn get_lev(&self) -> usize {
142 self.lev as usize
143 }
144
145 pub const fn get_osc1(&self) -> usize {
149 self.osc1 as usize
150 }
151
152 pub const fn get_dec(&self) -> usize {
156 self.dec as usize
157 }
158
159 pub const fn get_osc2(&self) -> usize {
163 self.osc2 as usize
164 }
165
166 pub const fn get_osc3(&self) -> usize {
170 self.osc3 as usize
171 }
172
173 pub const fn get_osc4(&self) -> usize {
177 self.osc4 as usize
178 }
179
180 pub const fn get_osc5(&self) -> usize {
184 self.osc5 as usize
185 }
186
187 pub const fn get_osc6(&self) -> usize {
191 self.osc6 as usize
192 }
193
194 #[parameter_range(range = "track_index[opt]:0..=11")]
195 pub(crate) fn from_raw_sound(
196 raw_sound: &ar_sound_t,
197 track_index: Option<usize>,
198 ) -> Result<Self, RytmError> {
199 unsafe {
200 Ok(Self {
201 parameter_lock_pool: None,
202 assigned_track: track_index,
203 lev: (from_s_u16_t(raw_sound.synth_param_1) >> 8) as u8,
204 osc1: from_s_u16_t(raw_sound.synth_param_2),
205 dec: (from_s_u16_t(raw_sound.synth_param_3) >> 8) as u8,
206 osc2: from_s_u16_t(raw_sound.synth_param_4),
207 osc3: from_s_u16_t(raw_sound.synth_param_5),
208 osc4: from_s_u16_t(raw_sound.synth_param_6),
209 osc5: from_s_u16_t(raw_sound.synth_param_7),
210 osc6: from_s_u16_t(raw_sound.synth_param_8),
211 })
212 }
213 }
214}
215
216impl HhLabParameters {
217 #[parameter_range(range = "lev:0..=127")]
221 pub fn plock_set_lev(&self, lev: usize, trig_index: usize) -> Result<(), RytmError> {
222 if let Some(ref pool) = self.parameter_lock_pool {
223 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
224
225 pool.lock().set_basic_plock(
226 trig_index,
227 assigned_track as u8,
228 rytm_sys::AR_PLOCK_TYPE_MP0 as u8,
229 lev as u8,
230 )?;
231
232 return Ok(());
233 }
234 Err(OrphanTrig)
235 }
236
237 pub fn plock_get_lev(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
241 if let Some(ref pool) = self.parameter_lock_pool {
242 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
243
244 let lev = pool.lock().get_basic_plock(
245 trig_index,
246 assigned_track as u8,
247 rytm_sys::AR_PLOCK_TYPE_MP0 as u8,
248 );
249
250 if let Some(lev) = lev {
251 return Ok(Some(lev as usize));
252 }
253
254 return Ok(None);
255 }
256 Err(OrphanTrig)
257 }
258
259 pub fn plock_clear_lev(&self, trig_index: usize) -> Result<(), RytmError> {
261 if let Some(ref pool) = self.parameter_lock_pool {
262 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
263 pool.lock().clear_basic_plock(
264 trig_index,
265 assigned_track as u8,
266 rytm_sys::AR_PLOCK_TYPE_MP0 as u8,
267 );
268 return Ok(());
269 }
270 Err(OrphanTrig)
271 }
272
273 #[parameter_range(range = "osc1:0..=16256")]
277 pub fn plock_set_osc1(&self, osc1: usize, trig_index: usize) -> Result<(), RytmError> {
278 if let Some(ref pool) = self.parameter_lock_pool {
279 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
280
281 pool.lock().set_compound_plock(
282 trig_index,
283 assigned_track as u8,
284 rytm_sys::AR_PLOCK_TYPE_MP1 as u8,
285 osc1 as u16,
286 )?;
287
288 return Ok(());
289 }
290 Err(OrphanTrig)
291 }
292
293 pub fn plock_get_osc1(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
297 if let Some(ref pool) = self.parameter_lock_pool {
298 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
299
300 let osc1 = pool.lock().get_compound_plock(
301 trig_index,
302 assigned_track as u8,
303 rytm_sys::AR_PLOCK_TYPE_MP1 as u8,
304 );
305
306 if let Some(osc1) = osc1 {
307 return Ok(Some(osc1 as usize));
308 }
309
310 return Ok(None);
311 }
312 Err(OrphanTrig)
313 }
314
315 pub fn plock_clear_osc1(&self, trig_index: usize) -> Result<(), RytmError> {
317 if let Some(ref pool) = self.parameter_lock_pool {
318 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
319 pool.lock().clear_compound_plock(
320 trig_index,
321 assigned_track as u8,
322 rytm_sys::AR_PLOCK_TYPE_MP1 as u8,
323 );
324 return Ok(());
325 }
326 Err(OrphanTrig)
327 }
328
329 #[parameter_range(range = "dec:0..=127")]
333 pub fn plock_set_dec(&self, dec: usize, trig_index: usize) -> Result<(), RytmError> {
334 if let Some(ref pool) = self.parameter_lock_pool {
335 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
336
337 pool.lock().set_basic_plock(
338 trig_index,
339 assigned_track as u8,
340 rytm_sys::AR_PLOCK_TYPE_MP2 as u8,
341 dec as u8,
342 )?;
343
344 return Ok(());
345 }
346 Err(OrphanTrig)
347 }
348
349 pub fn plock_get_dec(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
353 if let Some(ref pool) = self.parameter_lock_pool {
354 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
355
356 let dec = pool.lock().get_basic_plock(
357 trig_index,
358 assigned_track as u8,
359 rytm_sys::AR_PLOCK_TYPE_MP2 as u8,
360 );
361
362 if let Some(dec) = dec {
363 return Ok(Some(dec as usize));
364 }
365
366 return Ok(None);
367 }
368 Err(OrphanTrig)
369 }
370
371 pub fn plock_clear_dec(&self, trig_index: usize) -> Result<(), RytmError> {
373 if let Some(ref pool) = self.parameter_lock_pool {
374 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
375 pool.lock().clear_basic_plock(
376 trig_index,
377 assigned_track as u8,
378 rytm_sys::AR_PLOCK_TYPE_MP2 as u8,
379 );
380 return Ok(());
381 }
382 Err(OrphanTrig)
383 }
384
385 #[parameter_range(range = "osc2:0..=16256")]
389 pub fn plock_set_osc2(&self, osc2: usize, trig_index: usize) -> Result<(), RytmError> {
390 if let Some(ref pool) = self.parameter_lock_pool {
391 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
392
393 pool.lock().set_compound_plock(
394 trig_index,
395 assigned_track as u8,
396 rytm_sys::AR_PLOCK_TYPE_MP3 as u8,
397 osc2 as u16,
398 )?;
399
400 return Ok(());
401 }
402 Err(OrphanTrig)
403 }
404
405 pub fn plock_get_osc2(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
409 if let Some(ref pool) = self.parameter_lock_pool {
410 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
411
412 let osc2 = pool.lock().get_compound_plock(
413 trig_index,
414 assigned_track as u8,
415 rytm_sys::AR_PLOCK_TYPE_MP3 as u8,
416 );
417
418 if let Some(osc2) = osc2 {
419 return Ok(Some(osc2 as usize));
420 }
421
422 return Ok(None);
423 }
424 Err(OrphanTrig)
425 }
426
427 pub fn plock_clear_osc2(&self, trig_index: usize) -> Result<(), RytmError> {
429 if let Some(ref pool) = self.parameter_lock_pool {
430 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
431 pool.lock().clear_compound_plock(
432 trig_index,
433 assigned_track as u8,
434 rytm_sys::AR_PLOCK_TYPE_MP3 as u8,
435 );
436 return Ok(());
437 }
438 Err(OrphanTrig)
439 }
440
441 #[parameter_range(range = "osc3:0..=16256")]
445 pub fn plock_set_osc3(&self, osc3: usize, trig_index: usize) -> Result<(), RytmError> {
446 if let Some(ref pool) = self.parameter_lock_pool {
447 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
448
449 pool.lock().set_compound_plock(
450 trig_index,
451 assigned_track as u8,
452 rytm_sys::AR_PLOCK_TYPE_MP4 as u8,
453 osc3 as u16,
454 )?;
455
456 return Ok(());
457 }
458 Err(OrphanTrig)
459 }
460
461 pub fn plock_get_osc3(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
465 if let Some(ref pool) = self.parameter_lock_pool {
466 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
467
468 let osc3 = pool.lock().get_compound_plock(
469 trig_index,
470 assigned_track as u8,
471 rytm_sys::AR_PLOCK_TYPE_MP4 as u8,
472 );
473
474 if let Some(osc3) = osc3 {
475 return Ok(Some(osc3 as usize));
476 }
477
478 return Ok(None);
479 }
480 Err(OrphanTrig)
481 }
482
483 pub fn plock_clear_osc3(&self, trig_index: usize) -> Result<(), RytmError> {
485 if let Some(ref pool) = self.parameter_lock_pool {
486 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
487 pool.lock().clear_compound_plock(
488 trig_index,
489 assigned_track as u8,
490 rytm_sys::AR_PLOCK_TYPE_MP4 as u8,
491 );
492 return Ok(());
493 }
494 Err(OrphanTrig)
495 }
496
497 #[parameter_range(range = "osc4:0..=16256")]
501 pub fn plock_set_osc4(&self, osc4: usize, trig_index: usize) -> Result<(), RytmError> {
502 if let Some(ref pool) = self.parameter_lock_pool {
503 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
504
505 pool.lock().set_compound_plock(
506 trig_index,
507 assigned_track as u8,
508 rytm_sys::AR_PLOCK_TYPE_MP5 as u8,
509 osc4 as u16,
510 )?;
511
512 return Ok(());
513 }
514 Err(OrphanTrig)
515 }
516
517 pub fn plock_get_osc4(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
521 if let Some(ref pool) = self.parameter_lock_pool {
522 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
523
524 let osc4 = pool.lock().get_compound_plock(
525 trig_index,
526 assigned_track as u8,
527 rytm_sys::AR_PLOCK_TYPE_MP5 as u8,
528 );
529
530 if let Some(osc4) = osc4 {
531 return Ok(Some(osc4 as usize));
532 }
533
534 return Ok(None);
535 }
536 Err(OrphanTrig)
537 }
538
539 pub fn plock_clear_osc4(&self, trig_index: usize) -> Result<(), RytmError> {
541 if let Some(ref pool) = self.parameter_lock_pool {
542 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
543 pool.lock().clear_compound_plock(
544 trig_index,
545 assigned_track as u8,
546 rytm_sys::AR_PLOCK_TYPE_MP5 as u8,
547 );
548 return Ok(());
549 }
550 Err(OrphanTrig)
551 }
552
553 #[parameter_range(range = "osc5:0..=16256")]
557 pub fn plock_set_osc5(&self, osc5: usize, trig_index: usize) -> Result<(), RytmError> {
558 if let Some(ref pool) = self.parameter_lock_pool {
559 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
560 pool.lock().set_compound_plock(
561 trig_index,
562 assigned_track as u8,
563 rytm_sys::AR_PLOCK_TYPE_MP6 as u8,
564 osc5 as u16,
565 )?;
566 return Ok(());
567 }
568 Err(OrphanTrig)
569 }
570
571 pub fn plock_get_osc5(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
575 if let Some(ref pool) = self.parameter_lock_pool {
576 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
577 let osc5 = pool.lock().get_compound_plock(
578 trig_index,
579 assigned_track as u8,
580 rytm_sys::AR_PLOCK_TYPE_MP6 as u8,
581 );
582 if let Some(osc5) = osc5 {
583 return Ok(Some(osc5 as usize));
584 }
585 return Ok(None);
586 }
587 Err(OrphanTrig)
588 }
589
590 pub fn plock_clear_osc5(&self, trig_index: usize) -> Result<(), RytmError> {
592 if let Some(ref pool) = self.parameter_lock_pool {
593 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
594 pool.lock().clear_compound_plock(
595 trig_index,
596 assigned_track as u8,
597 rytm_sys::AR_PLOCK_TYPE_MP6 as u8,
598 );
599 return Ok(());
600 }
601 Err(OrphanTrig)
602 }
603
604 #[parameter_range(range = "osc6:0..=16256")]
608 pub fn plock_set_osc6(&self, osc6: usize, trig_index: usize) -> Result<(), RytmError> {
609 if let Some(ref pool) = self.parameter_lock_pool {
610 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
611 pool.lock().set_compound_plock(
612 trig_index,
613 assigned_track as u8,
614 rytm_sys::AR_PLOCK_TYPE_MP7 as u8,
615 osc6 as u16,
616 )?;
617 return Ok(());
618 }
619 Err(OrphanTrig)
620 }
621
622 pub fn plock_get_osc6(&self, trig_index: usize) -> Result<Option<usize>, RytmError> {
626 if let Some(ref pool) = self.parameter_lock_pool {
627 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
628 let osc6 = pool.lock().get_compound_plock(
629 trig_index,
630 assigned_track as u8,
631 rytm_sys::AR_PLOCK_TYPE_MP7 as u8,
632 );
633 if let Some(osc6) = osc6 {
634 return Ok(Some(osc6 as usize));
635 }
636 return Ok(None);
637 }
638 Err(OrphanTrig)
639 }
640
641 pub fn plock_clear_osc6(&self, trig_index: usize) -> Result<(), RytmError> {
643 if let Some(ref pool) = self.parameter_lock_pool {
644 let assigned_track = self.assigned_track.ok_or(OrphanTrig)?;
645 pool.lock().clear_compound_plock(
646 trig_index,
647 assigned_track as u8,
648 rytm_sys::AR_PLOCK_TYPE_MP7 as u8,
649 );
650 return Ok(());
651 }
652 Err(OrphanTrig)
653 }
654}