rytm_rs/object/sound/machine/
hh_lab.rs

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/// Parameters for the `HhLab` machine.
15#[derive(Derivative, Clone, Serialize, Deserialize)]
16#[derivative(Debug)]
17pub struct HhLabParameters {
18    lev: u8,
19    osc1: u16, // 0..=16256
20    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    /// Sets the `lev` parameter.
67    ///
68    /// Range: `0..=127`
69    #[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    /// Sets the `osc1` parameter.
76    ///
77    /// Range: `0..=16256`
78    #[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    /// Sets the `dec` parameter.
85    ///
86    /// Range: `0..=127`
87    #[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    /// Sets the `osc2` parameter.
94    ///
95    /// Range: `0..=16256`
96    #[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    /// Sets the `osc3` parameter.
103    ///
104    /// Range: `0..=16256`
105    #[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    /// Sets the `osc4` parameter.
112    ///
113    /// Range: `0..=16256`
114    #[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    /// Sets the `osc5` parameter.
121    ///
122    /// Range: `0..=16256`
123    #[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    /// Sets the `osc6` parameter.
130    ///
131    /// Range: `0..=16256`
132    #[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    /// Returns the `lev` parameter.
139    ///
140    /// Range: `0..=127`
141    pub const fn get_lev(&self) -> usize {
142        self.lev as usize
143    }
144
145    /// Returns the `osc1` parameter.
146    ///
147    /// Range: `0..=16256`
148    pub const fn get_osc1(&self) -> usize {
149        self.osc1 as usize
150    }
151
152    /// Returns the `dec` parameter.
153    ///
154    /// Range: `0..=127`
155    pub const fn get_dec(&self) -> usize {
156        self.dec as usize
157    }
158
159    /// Returns the `osc2` parameter.
160    ///
161    /// Range: `0..=16256`
162    pub const fn get_osc2(&self) -> usize {
163        self.osc2 as usize
164    }
165
166    /// Returns the `osc3` parameter.
167    ///
168    /// Range: `0..=16256`
169    pub const fn get_osc3(&self) -> usize {
170        self.osc3 as usize
171    }
172
173    /// Returns the `osc4` parameter.
174    ///
175    /// Range: `0..=16256`
176    pub const fn get_osc4(&self) -> usize {
177        self.osc4 as usize
178    }
179
180    /// Returns the `osc5` parameter.
181    ///
182    /// Range: `0..=16256`
183    pub const fn get_osc5(&self) -> usize {
184        self.osc5 as usize
185    }
186
187    /// Returns the `osc6` parameter.
188    ///
189    /// Range: `0..=16256`
190    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    /// Sets the parameter lock for the `lev` parameter.
218    ///
219    /// Range: `0..=127`
220    #[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    /// Gets the parameter lock for the `lev` parameter.
238    ///
239    /// Range: `0..=127`
240    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    /// Clears the parameter lock for the `lev` parameter if set.
260    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    /// Sets the parameter lock for the `osc1` parameter.
274    ///
275    /// Range: `0..=16256`
276    #[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    /// Gets the parameter lock for the `osc1` parameter.
294    ///
295    /// Range: `0..=16256`
296    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    /// Clears the parameter lock for the `osc1` parameter if set.
316    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    /// Sets the parameter lock for the `dec` parameter.
330    ///
331    /// Range: `0..=127`
332    #[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    /// Gets the parameter lock for the `dec` parameter.
350    ///
351    /// Range: `0..=127`
352    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    /// Clears the parameter lock for the `dec` parameter if set.
372    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    /// Sets the parameter lock for the `osc2` parameter.
386    ///
387    /// Range: `0..=16256`
388    #[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    /// Gets the parameter lock for the `osc2` parameter.
406    ///
407    /// Range: `0..=16256`
408    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    /// Clears the parameter lock for the `osc2` parameter if set.
428    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    /// Sets the parameter lock for the `osc3` parameter.
442    ///
443    /// Range: `0..=16256`
444    #[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    /// Gets the parameter lock for the `osc3` parameter.
462    ///
463    /// Range: `0..=16256`
464    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    /// Clears the parameter lock for the `osc3` parameter if set.
484    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    /// Sets the parameter lock for the `osc4` parameter.
498    ///
499    /// Range: `0..=16256`
500    #[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    /// Gets the parameter lock for the `osc4` parameter.
518    ///
519    /// Range: `0..=16256`
520    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    /// Clears the parameter lock for the `osc4` parameter if set.
540    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    /// Sets the parameter lock for the `osc5` parameter.   
554    ///
555    /// Range: `0..=16256`
556    #[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    /// Gets the parameter lock for the `osc5` parameter.
572    ///
573    /// Range: `0..=16256`
574    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    /// Clears the parameter lock for the `osc5` parameter if set.
591    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    /// Sets the parameter lock for the `osc6` parameter.
605    ///
606    /// Range: `0..=16256`
607    #[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    /// Gets the parameter lock for the `osc6` parameter.
623    ///
624    /// Range: `0..=16256`
625    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    /// Clears the parameter lock for the `osc6` parameter if set.
642    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}