rytm_rs/object/
kit.rs

1// All casts in this file are intended or safe within the context of this library.
2//
3// One can change `allow` to `warn` to review them if necessary.
4#![allow(
5    clippy::cast_lossless,
6    clippy::cast_possible_truncation,
7    clippy::cast_sign_loss
8)]
9
10// TODO: Check if we can get info about if this kit is assigned to a pattern.
11// TODO: Add control mod in parts once the pr merge to libanalogrytm is done.
12
13/// Holds the structure to represent compressor fx parameters.
14pub mod comp;
15/// Holds the structure to represent delay fx parameters.
16pub mod delay;
17/// Holds the structure to represent distortion fx parameters.
18pub mod dist;
19/// Holds the structure to represent lfo fx parameters.
20pub mod lfo;
21/// Holds the structure to represent retrig settings scoped to a track.
22pub mod retrig;
23/// Holds the structure to represent reverb fx parameters.
24pub mod reverb;
25/// Holds types relevant to the kit object.
26pub mod types;
27pub(crate) mod unknown;
28
29use self::{
30    comp::FxCompressor, delay::FxDelay, dist::FxDistortion, lfo::FxLfo, reverb::FxReverb,
31    types::ControlInModTarget, unknown::KitUnknown,
32};
33use super::pattern::plock::ParameterLockPool;
34use crate::{
35    defaults::{default_perf_ctl_array, default_scene_ctl_array},
36    error::{ParameterError, RytmError, SysexConversionError},
37    impl_sysex_compatible,
38    object::types::ObjectName,
39    sysex::{SysexCompatible, SysexMeta, SysexType, KIT_SYSEX_SIZE},
40    util::{
41        assemble_u32_from_u8_array_be, break_u32_into_u8_array_be,
42        to_s_u16_t_union_b_from_u8_as_msb,
43    },
44    AnySysexType, Sound,
45};
46use derivative::Derivative;
47use parking_lot::Mutex;
48use rytm_rs_macro::parameter_range;
49use rytm_sys::{ar_kit_raw_to_syx, ar_kit_t, ar_sysex_meta_t};
50use serde::{Deserialize, Serialize};
51use serde_big_array::BigArray;
52use std::sync::Arc;
53
54impl_sysex_compatible!(
55    Kit,
56    ar_kit_t,
57    ar_kit_raw_to_syx,
58    SysexType::Kit,
59    KIT_SYSEX_SIZE
60);
61
62/// Represents a kit in the analog rytm.
63///
64/// It does not map identically to the structure in the firmware.
65#[derive(Derivative, Clone, Serialize, Deserialize)]
66#[derivative(Debug)]
67pub struct Kit {
68    #[derivative(Debug = "ignore")]
69    sysex_meta: SysexMeta,
70    /// Version of the kit structure.
71    version: u32,
72    pub(crate) index: usize,
73
74    /// Name of the kit.
75    name: ObjectName,
76
77    // 13th is the fx track.
78    #[derivative(Debug = "ignore")]
79    track_levels: [u8; 13],
80    // We don't have retrig settings for the fx track.
81    #[derivative(Debug = "ignore")]
82    track_retrig_settings: [retrig::TrackRetrigMenu; 12],
83    #[derivative(Debug = "ignore")]
84    sounds: Vec<Sound>,
85
86    fx_delay: FxDelay,
87    fx_distortion: FxDistortion,
88    fx_reverb: FxReverb,
89    fx_compressor: FxCompressor,
90    fx_lfo: FxLfo,
91
92    control_in_1_mod_target_1: ControlInModTarget,
93    control_in_1_mod_target_2: ControlInModTarget,
94    control_in_1_mod_target_3: ControlInModTarget,
95    control_in_1_mod_target_4: ControlInModTarget,
96
97    control_in_2_mod_target_1: ControlInModTarget,
98    control_in_2_mod_target_2: ControlInModTarget,
99    control_in_2_mod_target_3: ControlInModTarget,
100    control_in_2_mod_target_4: ControlInModTarget,
101
102    control_in_1_mod_amt_1: i8,
103    control_in_1_mod_amt_2: i8,
104    control_in_1_mod_amt_3: i8,
105    control_in_1_mod_amt_4: i8,
106
107    control_in_2_mod_amt_1: i8,
108    control_in_2_mod_amt_2: i8,
109    control_in_2_mod_amt_3: i8,
110    control_in_2_mod_amt_4: i8,
111
112    // Currently these are out of my interest.
113    // Maybe in the feature we can add support for these.
114    //
115    // ---- TODO: ----
116    #[derivative(Debug = "ignore")]
117    #[serde(with = "BigArray")]
118    pub(crate) perf_ctl: [u8; 48 * 4], /* @0x0842..0x0901 */
119    #[derivative(Debug = "ignore")]
120    #[serde(with = "BigArray")]
121    pub(crate) scene_ctl: [u8; 48 * 4], /* @0x0917..0x09D6 */
122    // 0..=11 device 0..=11
123    #[derivative(Debug = "ignore")]
124    pub(crate) current_scene_id: u8, /* @0x09D8 (0..11) */
125    // ----------------
126    //
127    #[derivative(Debug = "ignore")]
128    pub(crate) __unknown: KitUnknown,
129}
130
131impl From<&Kit> for ar_kit_t {
132    fn from(kit: &Kit) -> Self {
133        let mut raw_kit = Self {
134            // Version
135            __unknown_arr1: break_u32_into_u8_array_be(kit.version),
136            name: kit.name.copy_inner(),
137            perf_ctl: kit.perf_ctl,
138            scene_ctl: kit.scene_ctl,
139            current_scene_id: kit.current_scene_id,
140
141            ctrl_in_mod_1_target_1: kit.control_in_1_mod_target_1.into(),
142            ctrl_in_mod_1_target_2: kit.control_in_1_mod_target_2.into(),
143            ctrl_in_mod_1_target_3: kit.control_in_1_mod_target_3.into(),
144            ctrl_in_mod_1_target_4: kit.control_in_1_mod_target_4.into(),
145
146            ctrl_in_mod_2_target_1: kit.control_in_2_mod_target_1.into(),
147            ctrl_in_mod_2__target_2: kit.control_in_2_mod_target_2.into(),
148            ctrl_in_mod_2_target_3: kit.control_in_2_mod_target_3.into(),
149            ctrl_in_mod_2_target_4: kit.control_in_2_mod_target_4.into(),
150
151            ctrl_in_mod_1_amt_1: kit.control_in_1_mod_amt_1 as u8,
152            ctrl_in_mod_1_amt_2: kit.control_in_1_mod_amt_2 as u8,
153            ctrl_in_mod_1_amt_3: kit.control_in_1_mod_amt_3 as u8,
154            ctrl_in_mod_1_amt_4: kit.control_in_1_mod_amt_4 as u8,
155
156            ctrl_in_mod_2_amt_1: kit.control_in_2_mod_amt_1 as u8,
157            ctrl_in_mod_2_amt_2: kit.control_in_2_mod_amt_2 as u8,
158            ctrl_in_mod_2_amt_3: kit.control_in_2_mod_amt_3 as u8,
159            ctrl_in_mod_2_amt_4: kit.control_in_2_mod_amt_4 as u8,
160
161            ..Default::default()
162        };
163
164        for (i, sound) in kit.sounds.iter().enumerate() {
165            raw_kit.tracks[i] = sound.into();
166        }
167
168        for (i, track_level) in kit.track_levels.iter().enumerate() {
169            // Only the high byte is used for the levels.
170            raw_kit.track_levels[i] = to_s_u16_t_union_b_from_u8_as_msb(*track_level);
171        }
172
173        kit.fx_delay.apply_to_raw_kit(&mut raw_kit);
174        kit.fx_distortion.apply_to_raw_kit(&mut raw_kit);
175        kit.fx_reverb.apply_to_raw_kit(&mut raw_kit);
176        kit.fx_compressor.apply_to_raw_kit(&mut raw_kit);
177        kit.fx_lfo.apply_to_raw_kit(&mut raw_kit);
178
179        for retrig_settings in &kit.track_retrig_settings {
180            retrig_settings.apply_to_raw_kit(&mut raw_kit);
181        }
182
183        kit.__unknown.apply_to_raw_kit(&mut raw_kit);
184
185        raw_kit
186    }
187}
188
189impl Kit {
190    pub(crate) fn try_from_raw(
191        sysex_meta: SysexMeta,
192        raw_kit: &ar_kit_t,
193    ) -> Result<Self, RytmError> {
194        let kit_number = sysex_meta.get_normalized_object_index();
195
196        let name = ObjectName::from_u8_array(raw_kit.name);
197
198        let mut sounds = vec![
199            Sound::try_kit_default(0, kit_number, sysex_meta)?,
200            Sound::try_kit_default(1, kit_number, sysex_meta)?,
201            Sound::try_kit_default(2, kit_number, sysex_meta)?,
202            Sound::try_kit_default(3, kit_number, sysex_meta)?,
203            Sound::try_kit_default(4, kit_number, sysex_meta)?,
204            Sound::try_kit_default(5, kit_number, sysex_meta)?,
205            Sound::try_kit_default(6, kit_number, sysex_meta)?,
206            Sound::try_kit_default(7, kit_number, sysex_meta)?,
207            Sound::try_kit_default(8, kit_number, sysex_meta)?,
208            Sound::try_kit_default(9, kit_number, sysex_meta)?,
209            Sound::try_kit_default(10, kit_number, sysex_meta)?,
210            Sound::try_kit_default(11, kit_number, sysex_meta)?,
211        ];
212
213        for (i, sound) in raw_kit.tracks.iter().enumerate() {
214            sounds[i] = Sound::try_from_raw(sysex_meta, sound, Some((kit_number, i)))?;
215        }
216
217        let mut track_levels = [0; 13];
218        for (i, track_level) in raw_kit.track_levels.iter().enumerate() {
219            // Only the high byte is used for the levels.
220            track_levels[i] = unsafe { track_level.b.hi };
221        }
222
223        #[allow(clippy::cast_possible_wrap)]
224        Ok(Self {
225            index: kit_number,
226            sysex_meta,
227            version: assemble_u32_from_u8_array_be(&raw_kit.__unknown_arr1),
228
229            name,
230
231            track_levels,
232            track_retrig_settings: retrig::TrackRetrigMenu::get_default_for_12_tracks(),
233            sounds,
234
235            fx_delay: raw_kit.try_into()?,
236            fx_distortion: raw_kit.try_into()?,
237            fx_reverb: raw_kit.try_into()?,
238            fx_compressor: raw_kit.try_into()?,
239            fx_lfo: raw_kit.try_into()?,
240
241            perf_ctl: raw_kit.perf_ctl,
242            scene_ctl: raw_kit.scene_ctl,
243            current_scene_id: raw_kit.current_scene_id,
244
245            control_in_1_mod_target_1: raw_kit.ctrl_in_mod_1_target_1.try_into()?,
246            control_in_1_mod_target_2: raw_kit.ctrl_in_mod_1_target_2.try_into()?,
247            control_in_1_mod_target_3: raw_kit.ctrl_in_mod_1_target_3.try_into()?,
248            control_in_1_mod_target_4: raw_kit.ctrl_in_mod_1_target_4.try_into()?,
249
250            control_in_2_mod_target_1: raw_kit.ctrl_in_mod_2_target_1.try_into()?,
251            control_in_2_mod_target_2: raw_kit.ctrl_in_mod_2__target_2.try_into()?,
252            control_in_2_mod_target_3: raw_kit.ctrl_in_mod_2_target_3.try_into()?,
253            control_in_2_mod_target_4: raw_kit.ctrl_in_mod_2_target_4.try_into()?,
254
255            control_in_1_mod_amt_1: raw_kit.ctrl_in_mod_1_amt_1 as i8,
256            control_in_1_mod_amt_2: raw_kit.ctrl_in_mod_1_amt_2 as i8,
257            control_in_1_mod_amt_3: raw_kit.ctrl_in_mod_1_amt_3 as i8,
258            control_in_1_mod_amt_4: raw_kit.ctrl_in_mod_1_amt_4 as i8,
259
260            control_in_2_mod_amt_1: raw_kit.ctrl_in_mod_2_amt_1 as i8,
261            control_in_2_mod_amt_2: raw_kit.ctrl_in_mod_2_amt_2 as i8,
262            control_in_2_mod_amt_3: raw_kit.ctrl_in_mod_2_amt_3 as i8,
263            control_in_2_mod_amt_4: raw_kit.ctrl_in_mod_2_amt_4 as i8,
264
265            __unknown: raw_kit.into(),
266        })
267    }
268
269    pub(crate) fn as_raw_parts(&self) -> (SysexMeta, ar_kit_t) {
270        (self.sysex_meta, self.into())
271    }
272
273    /// Makes a new kit with the project defaults.
274    ///
275    /// Range `0..=127`
276    #[parameter_range(range = "index:0..=127")]
277    pub fn try_default(index: usize) -> Result<Self, RytmError> {
278        Self::try_default_with_device_id(index, 0)
279    }
280
281    /// Makes a new kit with the given index complying to project defaults.
282    ///
283    /// Kit index range: 0..=127`
284    /// Device id range: `0..=127`
285    #[parameter_range(range = "kit_index:0..=127", range = "device_id:0..=127")]
286    pub fn try_default_with_device_id(kit_index: usize, device_id: u8) -> Result<Self, RytmError> {
287        //    sU8 ctrl_in_mod_1_amt_1;    /* @0x0A12 (-128..127) */
288        //    sU8 ctrl_in_mod_1_target_1; /* @0x0A14 See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
289        //    sU8 ctrl_in_mod_1_amt_2;    /* @0x0A15 (-128..127) */
290        //    sU8 ctrl_in_mod_1_target_2; /* @0x0A17 See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
291        //    sU8 ctrl_in_mod_1_amt_3;    /* @0x0A18 (-128..127) */
292        //    sU8 ctrl_in_mod_1_target_3; /* @0x0A1A See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
293        //    sU8 ctrl_in_mod_1_amt_4;    /* @0x0A1B (-128..127) */
294        //    sU8 ctrl_in_mod_1_target_4; /* @0x0A1D See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
295        //    sU8 ctrl_in_mod_2_amt_1;     /* @0x0A22 (-128..127) */
296        //    sU8 ctrl_in_mod_2_target_1;  /* @0x0A24 See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
297        //    sU8 ctrl_in_mod_2_amt_2;     /* @0x0A25 (-128..127) */
298        //    sU8 ctrl_in_mod_2__target_2; /* @0x0A27 See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
299        //    sU8 ctrl_in_mod_2_amt_3;     /* @0x0A28 (-128..127) */
300        //    sU8 ctrl_in_mod_2_target_3;  /* @0x0A2A See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
301        //    sU8 ctrl_in_mod_2_amt_4;     /* @0x0A2B (-128..127) */
302        //    sU8 ctrl_in_mod_2_target_4;  /* @0x0A2D See sound.h, same as AR_SOUND_MOD_DEST_XXX, AR_SOUND_MOD_DEST_SYN_X variants can not be used. */
303        let meta = SysexMeta::try_default_for_kit(kit_index, Some(device_id))?;
304        Ok(Self {
305            index: kit_index,
306            sysex_meta: meta,
307            version: 6,
308
309            name: format!("KIT {kit_index}").try_into()?,
310
311            track_levels: [100; 13],
312            track_retrig_settings: retrig::TrackRetrigMenu::get_default_for_12_tracks(),
313
314            sounds: vec![
315                Sound::try_kit_default(0, kit_index, meta)?,
316                Sound::try_kit_default(1, kit_index, meta)?,
317                Sound::try_kit_default(2, kit_index, meta)?,
318                Sound::try_kit_default(3, kit_index, meta)?,
319                Sound::try_kit_default(4, kit_index, meta)?,
320                Sound::try_kit_default(5, kit_index, meta)?,
321                Sound::try_kit_default(6, kit_index, meta)?,
322                Sound::try_kit_default(7, kit_index, meta)?,
323                Sound::try_kit_default(8, kit_index, meta)?,
324                Sound::try_kit_default(9, kit_index, meta)?,
325                Sound::try_kit_default(10, kit_index, meta)?,
326                Sound::try_kit_default(11, kit_index, meta)?,
327            ],
328
329            fx_delay: FxDelay::default(),
330            fx_distortion: FxDistortion::default(),
331            fx_reverb: FxReverb::default(),
332            fx_compressor: FxCompressor::default(),
333            fx_lfo: FxLfo::default(),
334
335            perf_ctl: default_perf_ctl_array(),
336            scene_ctl: default_scene_ctl_array(),
337            current_scene_id: 0,
338
339            control_in_1_mod_target_1: ControlInModTarget::default(),
340            control_in_1_mod_target_2: ControlInModTarget::default(),
341            control_in_1_mod_target_3: ControlInModTarget::default(),
342            control_in_1_mod_target_4: ControlInModTarget::default(),
343
344            control_in_2_mod_target_1: ControlInModTarget::default(),
345            control_in_2_mod_target_2: ControlInModTarget::default(),
346            control_in_2_mod_target_3: ControlInModTarget::default(),
347            control_in_2_mod_target_4: ControlInModTarget::default(),
348
349            control_in_1_mod_amt_1: 0,
350            control_in_1_mod_amt_2: 0,
351            control_in_1_mod_amt_3: 0,
352            control_in_1_mod_amt_4: 0,
353
354            control_in_2_mod_amt_1: 0,
355            control_in_2_mod_amt_2: 0,
356            control_in_2_mod_amt_3: 0,
357            control_in_2_mod_amt_4: 0,
358
359            __unknown: KitUnknown::default(),
360        })
361    }
362
363    /// Makes a new kit in the work buffer complying to project defaults as if it comes from the work buffer.
364    pub fn work_buffer_default() -> Self {
365        Self::work_buffer_default_with_device_id(0)
366    }
367
368    /// Makes a new kit in the work buffer complying to project defaults as if it comes from the work buffer.
369    #[allow(clippy::missing_panics_doc)]
370    pub fn work_buffer_default_with_device_id(device_id: u8) -> Self {
371        Self {
372            index: 0,
373            sysex_meta: SysexMeta::default_for_kit_in_work_buffer(Some(device_id)),
374            version: 6,
375
376            name: "WB_KIT".try_into().unwrap(),
377
378            track_levels: [100; 13],
379            track_retrig_settings: retrig::TrackRetrigMenu::get_default_for_12_tracks(),
380
381            // TODO: I don't know if we choose wb defaults or kit defaults for sounds here..
382            sounds: vec![
383                Sound::try_work_buffer_default_with_device_id(0, device_id).unwrap(),
384                Sound::try_work_buffer_default_with_device_id(1, device_id).unwrap(),
385                Sound::try_work_buffer_default_with_device_id(2, device_id).unwrap(),
386                Sound::try_work_buffer_default_with_device_id(3, device_id).unwrap(),
387                Sound::try_work_buffer_default_with_device_id(4, device_id).unwrap(),
388                Sound::try_work_buffer_default_with_device_id(5, device_id).unwrap(),
389                Sound::try_work_buffer_default_with_device_id(6, device_id).unwrap(),
390                Sound::try_work_buffer_default_with_device_id(7, device_id).unwrap(),
391                Sound::try_work_buffer_default_with_device_id(8, device_id).unwrap(),
392                Sound::try_work_buffer_default_with_device_id(9, device_id).unwrap(),
393                Sound::try_work_buffer_default_with_device_id(10, device_id).unwrap(),
394                Sound::try_work_buffer_default_with_device_id(11, device_id).unwrap(),
395            ],
396
397            fx_delay: FxDelay::default(),
398            fx_distortion: FxDistortion::default(),
399            fx_reverb: FxReverb::default(),
400            fx_compressor: FxCompressor::default(),
401            fx_lfo: FxLfo::default(),
402
403            perf_ctl: default_perf_ctl_array(),
404            scene_ctl: default_scene_ctl_array(),
405            current_scene_id: 0,
406
407            control_in_1_mod_target_1: ControlInModTarget::default(),
408            control_in_1_mod_target_2: ControlInModTarget::default(),
409            control_in_1_mod_target_3: ControlInModTarget::default(),
410            control_in_1_mod_target_4: ControlInModTarget::default(),
411
412            control_in_2_mod_target_1: ControlInModTarget::default(),
413            control_in_2_mod_target_2: ControlInModTarget::default(),
414            control_in_2_mod_target_3: ControlInModTarget::default(),
415            control_in_2_mod_target_4: ControlInModTarget::default(),
416
417            control_in_1_mod_amt_1: 0,
418            control_in_1_mod_amt_2: 0,
419            control_in_1_mod_amt_3: 0,
420            control_in_1_mod_amt_4: 0,
421
422            control_in_2_mod_amt_1: 0,
423            control_in_2_mod_amt_2: 0,
424            control_in_2_mod_amt_3: 0,
425            control_in_2_mod_amt_4: 0,
426
427            __unknown: KitUnknown::default(),
428        }
429    }
430
431    /// Sets the name of the kit.
432    ///
433    /// # Errors
434    ///
435    /// The name must be ASCII and have a length of 15 characters or less. Other cases will result in an error.
436    pub fn set_name(&mut self, name: &str) -> Result<(), RytmError> {
437        self.name = name.try_into()?;
438        Ok(())
439    }
440
441    /// Returns the name of the kit.
442    pub fn name(&self) -> &str {
443        self.name.as_str()
444    }
445
446    /// Returns the sounds assigned to the kit in the order of the tracks.
447    pub fn sounds(&self) -> &[Sound] {
448        &self.sounds
449    }
450
451    /// Returns the sounds assigned to the kit in the order of the tracks mutably.
452    pub fn sounds_mut(&mut self) -> &mut [Sound] {
453        &mut self.sounds
454    }
455
456    /// Sets the level of a track.
457    ///
458    /// Range
459    /// - track_index: `0..=12`
460    /// - level: `0..=127`
461    ///
462    /// 12th track is the fx track.
463    #[parameter_range(range = "track_index:0..=12", range = "level:0..=127")]
464    pub fn set_track_level(&mut self, track_index: usize, level: usize) -> Result<(), RytmError> {
465        self.track_levels[track_index] = level as u8;
466        Ok(())
467    }
468
469    /// Sets the level of all tracks including the Fx track.
470    ///
471    /// Range `0..=127`
472    #[parameter_range(range = "level:0..=127")]
473    pub fn set_all_track_levels(&mut self, level: usize) -> Result<(), RytmError> {
474        for track_level in &mut self.track_levels {
475            *track_level = level as u8;
476        }
477        Ok(())
478    }
479
480    /// Sets the level of a range of tracks.
481    ///
482    /// 12th track is the fx track.
483    ///
484    /// Maximum range `0..=12`
485    ///
486    /// Level range `0..=127`
487    #[parameter_range(range = "level:0..=127")]
488    pub fn set_a_range_of_track_levels(
489        &mut self,
490        range: std::ops::Range<usize>,
491        level: usize,
492    ) -> Result<(), RytmError> {
493        if range.end > 12 {
494            return Err(RytmError::Parameter(ParameterError::Range {
495                value: format!("{range:?}"),
496                parameter_name: "range".to_string(),
497            }));
498        }
499
500        for track_index in range {
501            self.set_track_level(track_index, level)?;
502        }
503
504        Ok(())
505    }
506
507    /// Gets the level of a track.
508    ///
509    /// Range `0..=12`
510    #[parameter_range(range = "track_index:0..=12")]
511    pub fn track_level(&self, track_index: usize) -> Result<usize, RytmError> {
512        Ok(self.track_levels[track_index] as usize)
513    }
514
515    /// Gets the level of all tracks including the Fx track.
516    ///
517    /// Range `0..=127`
518    pub fn track_levels(&self) -> Vec<usize> {
519        self.track_levels
520            .iter()
521            .map(|&l| l as usize)
522            .collect::<Vec<_>>()
523    }
524
525    /// Gets the level of a range of tracks.
526    ///
527    /// 12th track is the fx track.
528    ///
529    /// Maximum range `0..=12`
530    ///
531    /// Level range `0..=127`
532    ///
533    /// # Errors
534    ///
535    /// Returns an error if the range is out of bounds.
536    pub fn range_of_track_levels(
537        &self,
538        range: std::ops::Range<usize>,
539    ) -> Result<Vec<usize>, RytmError> {
540        let mut levels = Vec::new();
541        for track_index in range {
542            levels.push(self.track_level(track_index)?);
543        }
544        Ok(levels)
545    }
546
547    /// Returns the version of the kit structure.
548    pub const fn structure_version(&self) -> u32 {
549        self.version
550    }
551
552    /// Gets the retrig menu of a track
553    ///
554    /// 12th track is the fx track.
555    ///
556    /// Range `0..=12`
557    #[parameter_range(range = "track_index:0..=12")]
558    pub fn track_retrig_settings(
559        &self,
560        track_index: usize,
561    ) -> Result<&retrig::TrackRetrigMenu, RytmError> {
562        Ok(&self.track_retrig_settings[track_index])
563    }
564
565    /// Gets the retrig menu of a track mutably
566    ///
567    /// 12th track is the fx track.
568    ///
569    /// Range `0..=12`
570    #[parameter_range(range = "track_index:0..=12")]
571    pub fn track_retrig_settings_mut(
572        &mut self,
573        track_index: usize,
574    ) -> Result<&mut retrig::TrackRetrigMenu, RytmError> {
575        Ok(&mut self.track_retrig_settings[track_index])
576    }
577
578    /// Gets the fx delay parameters.
579    pub const fn fx_delay(&self) -> &FxDelay {
580        &self.fx_delay
581    }
582
583    /// Gets the fx delay parameters mutably.
584    pub fn fx_delay_mut(&mut self) -> &mut FxDelay {
585        &mut self.fx_delay
586    }
587
588    /// Gets the fx distortion parameters.
589    pub const fn fx_distortion(&self) -> &FxDistortion {
590        &self.fx_distortion
591    }
592
593    /// Gets the fx distortion parameters mutably.
594    pub fn fx_distortion_mut(&mut self) -> &mut FxDistortion {
595        &mut self.fx_distortion
596    }
597
598    /// Gets the fx reverb parameters.
599    pub const fn fx_reverb(&self) -> &FxReverb {
600        &self.fx_reverb
601    }
602
603    /// Gets the fx reverb parameters mutably.
604    pub fn fx_reverb_mut(&mut self) -> &mut FxReverb {
605        &mut self.fx_reverb
606    }
607
608    /// Gets the fx compressor parameters.
609    pub const fn fx_compressor(&self) -> &FxCompressor {
610        &self.fx_compressor
611    }
612
613    /// Gets the fx compressor parameters mutably.
614    pub fn fx_compressor_mut(&mut self) -> &mut FxCompressor {
615        &mut self.fx_compressor
616    }
617
618    /// Gets the fx lfo parameters.
619    pub const fn fx_lfo(&self) -> &FxLfo {
620        &self.fx_lfo
621    }
622
623    /// Gets the fx lfo parameters mutably.
624    pub fn fx_lfo_mut(&mut self) -> &mut FxLfo {
625        &mut self.fx_lfo
626    }
627
628    /// Returns the index of the kit.
629    pub const fn index(&self) -> usize {
630        self.index
631    }
632
633    /// Sets the control in 1 mod target 1
634    pub fn set_control_in_1_mod_target_1(&mut self, control_in_1_mod_target_1: ControlInModTarget) {
635        self.control_in_1_mod_target_1 = control_in_1_mod_target_1;
636    }
637
638    /// Sets the control in 1 mod target 2
639    pub fn set_control_in_1_mod_target_2(&mut self, control_in_1_mod_target_2: ControlInModTarget) {
640        self.control_in_1_mod_target_2 = control_in_1_mod_target_2;
641    }
642
643    /// Sets the control in 1 mod target 3
644    pub fn set_control_in_1_mod_target_3(&mut self, control_in_1_mod_target_3: ControlInModTarget) {
645        self.control_in_1_mod_target_3 = control_in_1_mod_target_3;
646    }
647
648    /// Sets the control in 1 mod target 4
649    pub fn set_control_in_1_mod_target_4(&mut self, control_in_1_mod_target_4: ControlInModTarget) {
650        self.control_in_1_mod_target_4 = control_in_1_mod_target_4;
651    }
652
653    /// Sets the control in 2 mod target 1
654    pub fn set_control_in_2_mod_target_1(&mut self, control_in_2_mod_target_1: ControlInModTarget) {
655        self.control_in_2_mod_target_1 = control_in_2_mod_target_1;
656    }
657
658    /// Sets the control in 2 mod target 2
659    pub fn set_control_in_2_mod_target_2(&mut self, control_in_2_mod_target_2: ControlInModTarget) {
660        self.control_in_2_mod_target_2 = control_in_2_mod_target_2;
661    }
662
663    /// Sets the control in 2 mod target 3
664    pub fn set_control_in_2_mod_target_3(&mut self, control_in_2_mod_target_3: ControlInModTarget) {
665        self.control_in_2_mod_target_3 = control_in_2_mod_target_3;
666    }
667
668    /// Sets the control in 2 mod target 4
669    pub fn set_control_in_2_mod_target_4(&mut self, control_in_2_mod_target_4: ControlInModTarget) {
670        self.control_in_2_mod_target_4 = control_in_2_mod_target_4;
671    }
672
673    /// Sets the control in 1 mod amt 1
674    ///
675    /// Range: `-128..=127`
676    #[parameter_range(range = "control_in_1_mod_amt_1:-128..=127")]
677    pub fn set_control_in_1_mod_amt_1(
678        &mut self,
679        control_in_1_mod_amt_1: isize,
680    ) -> Result<(), RytmError> {
681        self.control_in_1_mod_amt_1 = control_in_1_mod_amt_1 as i8;
682        Ok(())
683    }
684
685    /// Sets the control in 1 mod amt 2
686    ///
687    /// Range: `-128..=127`
688    #[parameter_range(range = "control_in_1_mod_amt_2:-128..=127")]
689    pub fn set_control_in_1_mod_amt_2(
690        &mut self,
691        control_in_1_mod_amt_2: isize,
692    ) -> Result<(), RytmError> {
693        self.control_in_1_mod_amt_2 = control_in_1_mod_amt_2 as i8;
694        Ok(())
695    }
696
697    /// Sets the control in 1 mod amt 3
698    ///
699    /// Range: `-128..=127`
700    #[parameter_range(range = "control_in_1_mod_amt_3:-128..=127")]
701    pub fn set_control_in_1_mod_amt_3(
702        &mut self,
703        control_in_1_mod_amt_3: isize,
704    ) -> Result<(), RytmError> {
705        self.control_in_1_mod_amt_3 = control_in_1_mod_amt_3 as i8;
706        Ok(())
707    }
708
709    /// Sets the control in 1 mod amt 4
710    ///
711    /// Range: `-128..=127`
712    #[parameter_range(range = "control_in_1_mod_amt_4:-128..=127")]
713    pub fn set_control_in_1_mod_amt_4(
714        &mut self,
715        control_in_1_mod_amt_4: isize,
716    ) -> Result<(), RytmError> {
717        self.control_in_1_mod_amt_4 = control_in_1_mod_amt_4 as i8;
718        Ok(())
719    }
720
721    /// Sets the control in 2 mod amt 1
722    ///
723    /// Range: `-128..=127`
724    #[parameter_range(range = "control_in_2_mod_amt_1:-128..=127")]
725    pub fn set_control_in_2_mod_amt_1(
726        &mut self,
727        control_in_2_mod_amt_1: isize,
728    ) -> Result<(), RytmError> {
729        self.control_in_2_mod_amt_1 = control_in_2_mod_amt_1 as i8;
730        Ok(())
731    }
732
733    /// Sets the control in 2 mod amt 2
734    ///
735    /// Range: `-128..=127`
736    #[parameter_range(range = "control_in_2_mod_amt_2:-128..=127")]
737    pub fn set_control_in_2_mod_amt_2(
738        &mut self,
739        control_in_2_mod_amt_2: isize,
740    ) -> Result<(), RytmError> {
741        self.control_in_2_mod_amt_2 = control_in_2_mod_amt_2 as i8;
742        Ok(())
743    }
744
745    /// Sets the control in 2 mod amt 3
746    ///
747    /// Range: `-128..=127`
748    #[parameter_range(range = "control_in_2_mod_amt_3:-128..=127")]
749    pub fn set_control_in_2_mod_amt_3(
750        &mut self,
751        control_in_2_mod_amt_3: isize,
752    ) -> Result<(), RytmError> {
753        self.control_in_2_mod_amt_3 = control_in_2_mod_amt_3 as i8;
754        Ok(())
755    }
756
757    /// Sets the control in 2 mod amt 4
758    ///
759    /// Range: `-128..=127`
760    #[parameter_range(range = "control_in_2_mod_amt_4:-128..=127")]
761    pub fn set_control_in_2_mod_amt_4(
762        &mut self,
763        control_in_2_mod_amt_4: isize,
764    ) -> Result<(), RytmError> {
765        self.control_in_2_mod_amt_4 = control_in_2_mod_amt_4 as i8;
766        Ok(())
767    }
768
769    /// Gets the control in 1 mod target 1
770    pub const fn control_in_1_mod_target_1(&self) -> ControlInModTarget {
771        self.control_in_1_mod_target_1
772    }
773
774    /// Gets the control in 1 mod target 2
775    pub const fn control_in_1_mod_target_2(&self) -> ControlInModTarget {
776        self.control_in_1_mod_target_2
777    }
778
779    /// Gets the control in 1 mod target 3
780    pub const fn control_in_1_mod_target_3(&self) -> ControlInModTarget {
781        self.control_in_1_mod_target_3
782    }
783
784    /// Gets the control in 1 mod target 4
785    pub const fn control_in_1_mod_target_4(&self) -> ControlInModTarget {
786        self.control_in_1_mod_target_4
787    }
788
789    /// Gets the control in 2 mod target 1
790    pub const fn control_in_2_mod_target_1(&self) -> ControlInModTarget {
791        self.control_in_2_mod_target_1
792    }
793
794    /// Gets the control in 2 mod target 2
795    pub const fn control_in_2_mod_target_2(&self) -> ControlInModTarget {
796        self.control_in_2_mod_target_2
797    }
798
799    /// Gets the control in 2 mod target 3
800    pub const fn control_in_2_mod_target_3(&self) -> ControlInModTarget {
801        self.control_in_2_mod_target_3
802    }
803
804    /// Gets the control in 2 mod target 4
805    pub const fn control_in_2_mod_target_4(&self) -> ControlInModTarget {
806        self.control_in_2_mod_target_4
807    }
808
809    /// Gets the control in 1 mod amt 1
810    ///
811    /// Range: `-128..=127`
812    pub const fn control_in_1_mod_amt_1(&self) -> isize {
813        self.control_in_1_mod_amt_1 as isize
814    }
815
816    /// Gets the control in 1 mod amt 2
817    ///
818    /// Range: `-128..=127`
819    pub const fn control_in_1_mod_amt_2(&self) -> isize {
820        self.control_in_1_mod_amt_2 as isize
821    }
822
823    /// Gets the control in 1 mod amt 3
824    ///
825    /// Range: `-128..=127`
826    pub const fn control_in_1_mod_amt_3(&self) -> isize {
827        self.control_in_1_mod_amt_3 as isize
828    }
829
830    /// Gets the control in 1 mod amt 4
831    ///
832    /// Range: `-128..=127`
833    pub const fn control_in_1_mod_amt_4(&self) -> isize {
834        self.control_in_1_mod_amt_4 as isize
835    }
836
837    /// Gets the control in 2 mod amt 1
838    ///
839    /// Range: `-128..=127`
840    pub const fn control_in_2_mod_amt_1(&self) -> isize {
841        self.control_in_2_mod_amt_1 as isize
842    }
843
844    /// Gets the control in 2 mod amt 2
845    ///
846    /// Range: `-128..=127`
847    pub const fn control_in_2_mod_amt_2(&self) -> isize {
848        self.control_in_2_mod_amt_2 as isize
849    }
850
851    /// Gets the control in 2 mod amt 3
852    ///
853    /// Range: `-128..=127`
854    pub const fn control_in_2_mod_amt_3(&self) -> isize {
855        self.control_in_2_mod_amt_3 as isize
856    }
857
858    /// Gets the control in 2 mod amt 4
859    ///
860    /// Range: `-128..=127`
861    pub const fn control_in_2_mod_amt_4(&self) -> isize {
862        self.control_in_2_mod_amt_4 as isize
863    }
864
865    /// Calls the kit sounds' `link_parameter_lock_pool` method.
866    ///
867    /// Please check [`link_parameter_lock_pool`](crate::object::sound::Sound::link_parameter_lock_pool) for more information.
868    ///
869    /// # Errors
870    ///
871    /// Returns an error if the sound is a pool sound which does not support parameter locks.
872    pub fn link_parameter_lock_pool(
873        &mut self,
874        parameter_lock_pool: &Arc<Mutex<ParameterLockPool>>,
875    ) -> Result<(), RytmError> {
876        for sound in self.sounds_mut() {
877            sound.link_parameter_lock_pool(parameter_lock_pool)?;
878        }
879
880        Ok(())
881    }
882
883    pub(crate) fn set_device_id(&mut self, device_id: u8) {
884        self.sysex_meta.set_device_id(device_id);
885        self.sounds_mut()
886            .iter_mut()
887            .for_each(|sound| sound.set_device_id(device_id));
888    }
889}