Skip to main content

ot_tools_io/parts/tracks/
midi.rs

1/*
2SPDX-License-Identifier: GPL-3.0-or-later
3Copyright © 2026 Mike Robeson [dijksterhuis]
4*/
5
6use crate::parts::lfos::{LfoParamsSetup1, LfoParamsSetup2, LfoParamsValues};
7use crate::Defaults;
8use ot_tools_io_derive::{ArrayDefaults, AsMutDerive, AsRefDerive, BoxedArrayDefaults};
9use serde::{Deserialize, Serialize};
10use serde_big_array::BigArray;
11use std::array::from_fn;
12
13/// Values for a MIDI Track's MIDI parameter page.
14#[derive(
15    Copy,
16    Clone,
17    Debug,
18    Eq,
19    Hash,
20    Ord,
21    PartialEq,
22    PartialOrd,
23    Serialize,
24    Deserialize,
25    AsMutDerive,
26    AsRefDerive,
27)]
28pub struct MidiTrackMidiParamsValues {
29    pub note: u8,
30    pub vel: u8,
31    pub len: u8,
32    pub not2: u8,
33    pub not3: u8,
34    pub not4: u8,
35}
36
37impl Default for MidiTrackMidiParamsValues {
38    fn default() -> Self {
39        Self {
40            note: 48,
41            vel: 100,
42            len: 6,
43            not2: 64,
44            not3: 64,
45            not4: 64,
46        }
47    }
48}
49
50#[cfg(test)]
51mod midi_track_params_values_midi {
52    use crate::parts::test_helper::get_default_test_bank;
53    use crate::parts::tracks::midi::MidiTrackMidiParamsValues;
54    use crate::OtToolsIoError;
55
56    #[test]
57    fn default() -> Result<(), OtToolsIoError> {
58        let b = get_default_test_bank()?;
59        for x in b.parts_unsaved[0].midi_track_params_values.iter() {
60            assert_eq!(x.midi, MidiTrackMidiParamsValues::default());
61        }
62        Ok(())
63    }
64}
65
66/// Values for a MIDI Track's Arp parameter page.
67#[derive(
68    Copy,
69    Clone,
70    Debug,
71    Eq,
72    Hash,
73    Ord,
74    PartialEq,
75    PartialOrd,
76    Serialize,
77    Deserialize,
78    AsMutDerive,
79    AsRefDerive,
80)]
81pub struct MidiTrackArpParamsValues {
82    pub tran: u8,
83    pub leg: u8,
84    pub mode: u8,
85    pub spd: u8,
86    pub rnge: u8,
87    pub nlen: u8,
88}
89
90impl Default for MidiTrackArpParamsValues {
91    fn default() -> Self {
92        Self {
93            tran: 64,
94            leg: 0,
95            mode: 0,
96            spd: 5,
97            rnge: 0,
98            nlen: 6,
99        }
100    }
101}
102
103#[cfg(test)]
104mod midi_track_params_values_arp {
105    use crate::parts::test_helper::get_default_test_bank;
106    use crate::parts::tracks::midi::MidiTrackArpParamsValues;
107    use crate::OtToolsIoError;
108
109    #[test]
110    fn default() -> Result<(), OtToolsIoError> {
111        let b = get_default_test_bank()?;
112        for x in b.parts_unsaved[0].midi_track_params_values.iter() {
113            assert_eq!(x.arp, MidiTrackArpParamsValues::default());
114        }
115        Ok(())
116    }
117}
118
119/// Values for a MIDI Track's CC1 parameter page.
120#[derive(
121    Copy,
122    Clone,
123    Debug,
124    Eq,
125    Hash,
126    Ord,
127    PartialEq,
128    PartialOrd,
129    Serialize,
130    Deserialize,
131    AsMutDerive,
132    AsRefDerive,
133)]
134pub struct MidiTrackCc1ParamsValues {
135    pub pb: u8,
136    pub at: u8,
137    pub cc1: u8,
138    pub cc2: u8,
139    pub cc3: u8,
140    pub cc4: u8,
141}
142
143impl Default for MidiTrackCc1ParamsValues {
144    fn default() -> Self {
145        Self {
146            pb: 64,
147            at: 0,
148            cc1: 127,
149            cc2: 0,
150            cc3: 0,
151            cc4: 64,
152        }
153    }
154}
155
156#[cfg(test)]
157mod midi_track_params_values_cc1 {
158    use crate::parts::test_helper::get_default_test_bank;
159    use crate::parts::tracks::midi::MidiTrackCc1ParamsValues;
160    use crate::OtToolsIoError;
161
162    #[test]
163    fn default() -> Result<(), OtToolsIoError> {
164        let b = get_default_test_bank()?;
165        for x in b.parts_unsaved[0].midi_track_params_values.iter() {
166            assert_eq!(x.ctrl1, MidiTrackCc1ParamsValues::default());
167        }
168        Ok(())
169    }
170}
171
172/// Values for a MIDI Track's CC2 parameter page.
173#[derive(
174    Copy,
175    Clone,
176    Debug,
177    Default,
178    Eq,
179    Hash,
180    Ord,
181    PartialEq,
182    PartialOrd,
183    Serialize,
184    Deserialize,
185    AsMutDerive,
186    AsRefDerive,
187)]
188pub struct MidiTrackCc2ParamsValues {
189    pub cc5: u8,
190    pub cc6: u8,
191    pub cc7: u8,
192    pub cc8: u8,
193    pub cc9: u8,
194    pub cc10: u8,
195}
196
197#[cfg(test)]
198mod midi_track_params_values_cc2 {
199    use crate::parts::test_helper::get_default_test_bank;
200    use crate::parts::tracks::midi::MidiTrackCc2ParamsValues;
201    use crate::OtToolsIoError;
202
203    #[test]
204    fn default() -> Result<(), OtToolsIoError> {
205        let b = get_default_test_bank()?;
206        for x in b.parts_unsaved[0].midi_track_params_values.iter() {
207            assert_eq!(x.ctrl2, MidiTrackCc2ParamsValues::default());
208        }
209        Ok(())
210    }
211}
212
213/// MIDI Track parameter values. MIDI/Note, LFO, Amp, Ctrl 1, Ctrl 2.
214#[derive(
215    Copy,
216    Clone,
217    Debug,
218    Default,
219    Eq,
220    Hash,
221    Ord,
222    PartialEq,
223    PartialOrd,
224    Serialize,
225    Deserialize,
226    AsMutDerive,
227    AsRefDerive,
228    ArrayDefaults,
229    BoxedArrayDefaults,
230)]
231pub struct MidiTrackParamsValues {
232    pub midi: MidiTrackMidiParamsValues,
233    pub lfo: LfoParamsValues,
234    pub arp: MidiTrackArpParamsValues,
235    pub ctrl1: MidiTrackCc1ParamsValues,
236    pub ctrl2: MidiTrackCc2ParamsValues,
237    #[serde(with = "BigArray")]
238    pub unknown: [u8; 2],
239}
240
241#[cfg(test)]
242mod midi_track_params_values {
243    use crate::parts::test_helper::get_default_test_bank;
244    use crate::parts::tracks::midi::MidiTrackParamsValues;
245    use crate::OtToolsIoError;
246
247    #[test]
248    fn default() -> Result<(), OtToolsIoError> {
249        let b = get_default_test_bank()?;
250        for x in b.parts_unsaved[0].midi_track_params_values.iter() {
251            assert_eq!(x, &MidiTrackParamsValues::default());
252        }
253        Ok(())
254    }
255}
256
257/// Values for a MIDI Track's Note Setup page.
258#[derive(
259    Copy,
260    Clone,
261    Debug,
262    Eq,
263    Hash,
264    Ord,
265    PartialEq,
266    PartialOrd,
267    Serialize,
268    Deserialize,
269    AsMutDerive,
270    AsRefDerive,
271)]
272pub struct MidiTrackNoteParamsSetup {
273    pub chan: u8,
274    pub bank: u8,
275    pub prog: u8,
276    pub unused_1: u8,
277    pub sbank: u8,
278    pub unused_2: u8,
279}
280
281impl Default for MidiTrackNoteParamsSetup {
282    fn default() -> Self {
283        Self {
284            chan: 0,
285            bank: 128,
286            prog: 128,
287            unused_1: 0,
288            sbank: 128,
289            unused_2: 0,
290        }
291    }
292}
293
294#[cfg(test)]
295mod midi_track_note_params_setup {
296    use crate::parts::test_helper::get_default_test_bank;
297    use crate::parts::tracks::midi::MidiTrackNoteParamsSetup;
298    use crate::OtToolsIoError;
299
300    #[test]
301    fn default() -> Result<(), OtToolsIoError> {
302        let b = get_default_test_bank()?;
303        for x in b.parts_unsaved[0].midi_track_params_setup.iter() {
304            assert_eq!(x.note, MidiTrackNoteParamsSetup::default());
305        }
306        Ok(())
307    }
308}
309
310/// Values for a MIDI Track's Arp Setup page.
311#[derive(
312    Copy,
313    Clone,
314    Debug,
315    Eq,
316    Hash,
317    Ord,
318    PartialEq,
319    PartialOrd,
320    Serialize,
321    Deserialize,
322    AsMutDerive,
323    AsRefDerive,
324)]
325pub struct MidiTrackArpParamsSetup {
326    pub unused_1: u8,
327    pub unused_2: u8,
328    /// Length of the arp sequence
329    pub len: u8,
330    pub unused_3: u8,
331    pub unused_4: u8,
332    /// maximum 24 -- B Min
333    /// minimum 0 -- Off
334    pub key: u8,
335}
336
337impl Default for MidiTrackArpParamsSetup {
338    fn default() -> Self {
339        Self {
340            unused_1: 0,
341            unused_2: 0,
342            len: 7,
343            unused_3: 0,
344            unused_4: 0,
345            key: 0,
346        }
347    }
348}
349
350#[cfg(test)]
351mod midi_track_arp_params_setup {
352    use crate::parts::test_helper::get_default_test_bank;
353    use crate::parts::tracks::midi::MidiTrackArpParamsSetup;
354    use crate::OtToolsIoError;
355
356    #[test]
357    fn default() -> Result<(), OtToolsIoError> {
358        let b = get_default_test_bank()?;
359        for x in b.parts_unsaved[0].midi_track_params_setup.iter() {
360            assert_eq!(x.arp, MidiTrackArpParamsSetup::default());
361        }
362        Ok(())
363    }
364}
365
366/// Values for a MIDI Track's CC1 Setup page.
367#[derive(
368    Copy,
369    Clone,
370    Debug,
371    Eq,
372    Hash,
373    Ord,
374    PartialEq,
375    PartialOrd,
376    Serialize,
377    Deserialize,
378    AsMutDerive,
379    AsRefDerive,
380)]
381pub struct MidiTrackCc1ParamsSetup {
382    pub unused_1: u8,
383    pub unused_2: u8,
384    pub cc1: u8,
385    pub cc2: u8,
386    pub cc3: u8,
387    pub cc4: u8,
388}
389
390impl Default for MidiTrackCc1ParamsSetup {
391    fn default() -> Self {
392        Self {
393            unused_1: 0,
394            unused_2: 0,
395            cc1: 7,
396            cc2: 1,
397            cc3: 2,
398            cc4: 10,
399        }
400    }
401}
402
403#[cfg(test)]
404mod midi_track_cc1_params_setup {
405    use crate::parts::test_helper::get_default_test_bank;
406    use crate::parts::tracks::midi::MidiTrackCc1ParamsSetup;
407    use crate::OtToolsIoError;
408
409    #[test]
410    fn default() -> Result<(), OtToolsIoError> {
411        let b = get_default_test_bank()?;
412        for x in b.parts_unsaved[0].midi_track_params_setup.iter() {
413            assert_eq!(x.ctrl1, MidiTrackCc1ParamsSetup::default());
414        }
415        Ok(())
416    }
417}
418
419/// Values for a MIDI Track's CC2 Setup page.
420#[derive(
421    Copy,
422    Clone,
423    Debug,
424    Eq,
425    Hash,
426    Ord,
427    PartialEq,
428    PartialOrd,
429    Serialize,
430    Deserialize,
431    AsMutDerive,
432    AsRefDerive,
433)]
434pub struct MidiTrackCc2ParamsSetup {
435    pub cc5: u8,
436    pub cc6: u8,
437    pub cc7: u8,
438    pub cc8: u8,
439    pub cc9: u8,
440    pub cc10: u8,
441}
442
443impl Default for MidiTrackCc2ParamsSetup {
444    fn default() -> Self {
445        Self {
446            cc5: 71,
447            cc6: 72,
448            cc7: 73,
449            cc8: 74,
450            cc9: 75,
451            cc10: 76,
452        }
453    }
454}
455
456#[cfg(test)]
457mod midi_track_cc2_params_setup {
458    use crate::parts::test_helper::get_default_test_bank;
459    use crate::parts::tracks::midi::MidiTrackCc2ParamsSetup;
460    use crate::OtToolsIoError;
461
462    #[test]
463    fn default() -> Result<(), OtToolsIoError> {
464        let b = get_default_test_bank()?;
465        for x in b.parts_unsaved[0].midi_track_params_setup.iter() {
466            assert_eq!(x.ctrl2, MidiTrackCc2ParamsSetup::default());
467        }
468        Ok(())
469    }
470}
471
472/// MIDI Tracks Parameter Setup pages for LFO, Amp, FX etc.
473#[derive(
474    Copy,
475    Clone,
476    Debug,
477    Default,
478    Eq,
479    Hash,
480    Ord,
481    PartialEq,
482    PartialOrd,
483    Serialize,
484    Deserialize,
485    AsMutDerive,
486    AsRefDerive,
487    ArrayDefaults,
488    BoxedArrayDefaults,
489)]
490pub struct MidiTrackParamsSetup {
491    pub note: MidiTrackNoteParamsSetup,
492    pub lfo1: LfoParamsSetup1,
493    pub arp: MidiTrackArpParamsSetup,
494    pub ctrl1: MidiTrackCc1ParamsSetup,
495    pub ctrl2: MidiTrackCc2ParamsSetup,
496    pub lfo2: LfoParamsSetup2,
497}
498
499#[cfg(test)]
500mod midi_track_params_setup {
501    use crate::parts::test_helper::get_default_test_bank;
502    use crate::parts::tracks::midi::MidiTrackParamsSetup;
503    use crate::OtToolsIoError;
504
505    #[test]
506    fn default() -> Result<(), OtToolsIoError> {
507        let b = get_default_test_bank()?;
508        for x in b.parts_unsaved[0].midi_track_params_setup.iter() {
509            assert_eq!(x, &MidiTrackParamsSetup::default());
510        }
511        Ok(())
512    }
513}
514
515/// A MIDI Track's custom Arp sequence.
516/// `0` -> `+63` values (above line) maps to `0` -> `63`.
517/// `-1` -> `-63` values (below line) map to `255` -> `192`.
518#[derive(
519    Copy,
520    Clone,
521    Debug,
522    Eq,
523    Hash,
524    Ord,
525    PartialEq,
526    PartialOrd,
527    Serialize,
528    Deserialize,
529    AsMutDerive,
530    AsRefDerive,
531    ArrayDefaults,
532    BoxedArrayDefaults,
533)]
534pub struct MidiArpSequence(pub [u8; 16]);
535
536impl Default for MidiArpSequence {
537    fn default() -> Self {
538        Self(from_fn(|_| 0))
539    }
540}
541
542#[cfg(test)]
543mod midi_arp_seq {
544    use crate::parts::test_helper::get_default_test_bank;
545    use crate::parts::tracks::midi::MidiArpSequence;
546    use crate::OtToolsIoError;
547
548    #[test]
549    fn default() -> Result<(), OtToolsIoError> {
550        let b = get_default_test_bank()?;
551        for x in b.parts_unsaved[0].midi_tracks_arp_seqs.iter() {
552            assert_eq!(x, &MidiArpSequence::default());
553        }
554        Ok(())
555    }
556}