1pub mod control_menu;
11pub mod mixer;
12pub mod tempo;
13pub mod trig_mode_midi_tracks;
14
15use control_menu::{
16 AudioControlPage, ControlMenu, InputControlPage, MemoryControlPage, MetronomeControlPage,
17 MidiChannelsMidiPage, MidiControlMidiPage, MidiSequencerControlPage, MidiSubMenu,
18 MidiSyncMidiPage, SequencerControlPage,
19};
20
21use mixer::MixerMenu;
22use tempo::TempoMenu;
23use trig_mode_midi_tracks::MidiTrackTrigModes;
24
25use serde::{Deserialize, Serialize};
26
27use crate::projects::{
28 parse_hashmap_string_value_bool, string_to_hashmap, FromHashMap, ProjectRawFileSection,
29};
30use crate::{OptionEnumValueConvert, OtToolsIoErrors, RBoxErr};
31
32#[derive(PartialEq, Debug, Clone, Default, Serialize, Deserialize, Copy)]
103#[repr(i8)]
104pub enum MidiChannel {
105 #[default]
107 Disabled = -1,
108 One = 1,
111 Two = 2,
113 Three = 3,
115 Four = 4,
117 Five = 5,
119 Six = 6,
121 Seven = 7,
123 Eight = 8,
125 Nine = 9,
127 Ten = 10,
129 Eleven = 11,
131 Twelve = 12,
133 Thirteen = 13,
135 Fourteen = 14,
137 Fifteen = 15,
139 Sixteen = 16,
141}
142
143impl OptionEnumValueConvert<i8> for MidiChannel {
144 fn from_value(v: &i8) -> RBoxErr<Self> {
145 match v {
146 -1 => Ok(Self::Disabled),
147 1 => Ok(Self::One),
148 2 => Ok(Self::Two),
149 3 => Ok(Self::Three),
150 4 => Ok(Self::Four),
151 5 => Ok(Self::Five),
152 6 => Ok(Self::Six),
153 7 => Ok(Self::Seven),
154 8 => Ok(Self::Eight),
155 9 => Ok(Self::Nine),
156 10 => Ok(Self::Ten),
157 11 => Ok(Self::Eleven),
158 12 => Ok(Self::Twelve),
159 13 => Ok(Self::Thirteen),
160 14 => Ok(Self::Fourteen),
161 15 => Ok(Self::Fifteen),
162 16 => Ok(Self::Sixteen),
163 _ => Err(OtToolsIoErrors::NoMatchingOptionEnumValue.into()),
164 }
165 }
166
167 fn value(&self) -> RBoxErr<i8> {
168 Ok(*self as i8)
169 }
170}
171
172#[cfg(test)]
173#[allow(unused_imports)]
174mod test_spec {
175
176 mod value {
177 use crate::projects::settings::MidiChannel;
178 use crate::OptionEnumValueConvert;
179
180 #[test]
181 fn test_disabled() {
182 assert_eq!(MidiChannel::Disabled.value().unwrap(), -1);
183 }
184 #[test]
185 fn test_1() {
186 assert_eq!(MidiChannel::One.value().unwrap(), 1);
187 }
188 #[test]
189 fn test_2() {
190 assert_eq!(MidiChannel::Two.value().unwrap(), 2);
191 }
192 #[test]
193 fn test_3() {
194 assert_eq!(MidiChannel::Three.value().unwrap(), 3);
195 }
196 #[test]
197 fn test_4() {
198 assert_eq!(MidiChannel::Four.value().unwrap(), 4);
199 }
200 #[test]
201 fn test_5() {
202 assert_eq!(MidiChannel::Five.value().unwrap(), 5);
203 }
204 #[test]
205 fn test_6() {
206 assert_eq!(MidiChannel::Six.value().unwrap(), 6);
207 }
208 #[test]
209 fn test_7() {
210 assert_eq!(MidiChannel::Seven.value().unwrap(), 7);
211 }
212 #[test]
213 fn test_8() {
214 assert_eq!(MidiChannel::Eight.value().unwrap(), 8);
215 }
216 #[test]
217 fn test_9() {
218 assert_eq!(MidiChannel::Nine.value().unwrap(), 9);
219 }
220 #[test]
221 fn test_10() {
222 assert_eq!(MidiChannel::Ten.value().unwrap(), 10);
223 }
224 #[test]
225 fn test_11() {
226 assert_eq!(MidiChannel::Eleven.value().unwrap(), 11);
227 }
228 #[test]
229 fn test_12() {
230 assert_eq!(MidiChannel::Twelve.value().unwrap(), 12);
231 }
232 #[test]
233 fn test_13() {
234 assert_eq!(MidiChannel::Thirteen.value().unwrap(), 13);
235 }
236 #[test]
237 fn test_14() {
238 assert_eq!(MidiChannel::Fourteen.value().unwrap(), 14);
239 }
240 #[test]
241 fn test_15() {
242 assert_eq!(MidiChannel::Fifteen.value().unwrap(), 15);
243 }
244 #[test]
245 fn test_16() {
246 assert_eq!(MidiChannel::Sixteen.value().unwrap(), 16);
247 }
248 }
249
250 mod from_value {
251
252 use crate::projects::settings::MidiChannel;
253 use crate::OptionEnumValueConvert;
254
255 #[test]
256 fn test_error_1() {
257 assert!(MidiChannel::from_value(&100).is_err());
258 }
259 #[test]
260 fn test_error_2() {
261 assert!(MidiChannel::from_value(&0).is_err());
262 }
263 #[test]
264 fn test_disabled() {
265 assert_eq!(MidiChannel::Disabled, MidiChannel::from_value(&-1).unwrap());
266 }
267 #[test]
268 fn test_1() {
269 assert_eq!(MidiChannel::One, MidiChannel::from_value(&1).unwrap());
270 }
271 #[test]
272 fn test_2() {
273 assert_eq!(MidiChannel::Two, MidiChannel::from_value(&2).unwrap());
274 }
275 #[test]
276 fn test_3() {
277 assert_eq!(MidiChannel::Three, MidiChannel::from_value(&3).unwrap());
278 }
279 #[test]
280 fn test_4() {
281 assert_eq!(MidiChannel::Four, MidiChannel::from_value(&4).unwrap());
282 }
283 #[test]
284 fn test_5() {
285 assert_eq!(MidiChannel::Five, MidiChannel::from_value(&5).unwrap());
286 }
287 #[test]
288 fn test_6() {
289 assert_eq!(MidiChannel::Six, MidiChannel::from_value(&6).unwrap());
290 }
291 #[test]
292 fn test_7() {
293 assert_eq!(MidiChannel::Seven, MidiChannel::from_value(&7).unwrap());
294 }
295 #[test]
296 fn test_8() {
297 assert_eq!(MidiChannel::Eight, MidiChannel::from_value(&8).unwrap());
298 }
299 #[test]
300 fn test_9() {
301 assert_eq!(MidiChannel::Nine, MidiChannel::from_value(&9).unwrap());
302 }
303 #[test]
304 fn test_10() {
305 assert_eq!(MidiChannel::Ten, MidiChannel::from_value(&10).unwrap());
306 }
307 #[test]
308 fn test_11() {
309 assert_eq!(MidiChannel::Eleven, MidiChannel::from_value(&11).unwrap());
310 }
311 #[test]
312 fn test_12() {
313 assert_eq!(MidiChannel::Twelve, MidiChannel::from_value(&12).unwrap());
314 }
315 #[test]
316 fn test_13() {
317 assert_eq!(MidiChannel::Thirteen, MidiChannel::from_value(&13).unwrap());
318 }
319 #[test]
320 fn test_14() {
321 assert_eq!(MidiChannel::Fourteen, MidiChannel::from_value(&14).unwrap());
322 }
323 #[test]
324 fn test_15() {
325 assert_eq!(MidiChannel::Fifteen, MidiChannel::from_value(&15).unwrap());
326 }
327 #[test]
328 fn test_16() {
329 assert_eq!(MidiChannel::Sixteen, MidiChannel::from_value(&16).unwrap());
330 }
331 }
332}
333
334#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
336pub struct Settings {
337 pub write_protected: bool,
339
340 pub control: ControlMenu,
342
343 pub midi_soft_thru: bool,
345
346 pub mixer: MixerMenu,
348
349 pub tempo: TempoMenu,
351
352 pub midi_tracks_trig_mode: MidiTrackTrigModes,
354}
355
356impl Default for Settings {
357 fn default() -> Self {
358 Self {
359 write_protected: false,
360 control: ControlMenu {
361 audio: AudioControlPage {
362 master_track: false,
363 cue_studio_mode: false,
364 },
365 input: InputControlPage {
366 gate_ab: 127,
367 gate_cd: 127,
368 input_delay_compensation: false,
369 },
370 sequencer: SequencerControlPage {
371 pattern_change_chain_behaviour: 0,
372 pattern_change_auto_silence_tracks: false,
373 pattern_change_auto_trig_lfos: false,
374 },
375 midi_sequencer: MidiSequencerControlPage {},
376 memory: MemoryControlPage {
377 load_24bit_flex: false,
378 dynamic_recorders: false,
379 record_24bit: false,
380 reserved_recorder_count: 8,
381 reserved_recorder_length: 16,
382 },
383 metronome: MetronomeControlPage {
384 metronome_time_signature: 3,
385 metronome_time_signature_denominator: 2,
386 metronome_preroll: 0,
387 metronome_cue_volume: 32,
388 metronome_main_volume: 0,
389 metronome_pitch: 12,
390 metronome_tonal: true,
391 metronome_enabled: false,
392 },
393 midi: MidiSubMenu {
394 control: MidiControlMidiPage {
395 midi_audio_track_cc_in: true,
396 midi_audio_track_cc_out: 3,
397 midi_audio_track_note_in: 1,
398 midi_audio_track_note_out: 3,
399 midi_midi_track_cc_in: 1,
400 },
401 sync: MidiSyncMidiPage {
402 midi_clock_send: false,
403 midi_clock_receive: false,
404 midi_transport_send: false,
405 midi_transport_receive: false,
406 midi_progchange_send: false,
407 midi_progchange_send_channel: MidiChannel::Disabled,
408 midi_progchange_receive: false,
409 midi_progchange_receive_channel: MidiChannel::Disabled,
410 },
411 channels: MidiChannelsMidiPage {
412 midi_trig_ch1: 0,
413 midi_trig_ch2: 1,
414 midi_trig_ch3: 2,
415 midi_trig_ch4: 3,
416 midi_trig_ch5: 4,
417 midi_trig_ch6: 5,
418 midi_trig_ch7: 6,
419 midi_trig_ch8: 7,
420 midi_auto_channel: 10,
421 },
422 },
423 },
424 midi_soft_thru: false,
425 mixer: MixerMenu {
426 gain_ab: 64,
427 gain_cd: 64,
428 dir_ab: 0,
429 dir_cd: 0,
430 phones_mix: 64,
431 main_to_cue: 0,
432 main_level: 64,
433 cue_level: 64,
434 },
435 tempo: TempoMenu {
436 tempo: 120,
437 pattern_tempo_enabled: false,
438 },
439 midi_tracks_trig_mode: MidiTrackTrigModes {
440 trig_mode_midi_track_1: 0,
441 trig_mode_midi_track_2: 0,
442 trig_mode_midi_track_3: 0,
443 trig_mode_midi_track_4: 0,
444 trig_mode_midi_track_5: 0,
445 trig_mode_midi_track_6: 0,
446 trig_mode_midi_track_7: 0,
447 trig_mode_midi_track_8: 0,
448 },
449 }
450 }
451}
452
453impl std::str::FromStr for Settings {
454 type Err = Box<dyn std::error::Error>;
455
456 fn from_str(s: &str) -> Result<Self, Self::Err> {
458 let hmap = string_to_hashmap(s, &ProjectRawFileSection::Settings)?;
459
460 let write_protected = parse_hashmap_string_value_bool(&hmap, "writeprotected", None)?;
461 let midi_soft_thru = parse_hashmap_string_value_bool(&hmap, "midi_soft_thru", None)?;
463 let control = ControlMenu::from_hashmap(&hmap)?;
464 let mixer = MixerMenu::from_hashmap(&hmap)?;
465 let tempo = TempoMenu::from_hashmap(&hmap)?;
466 let midi_tracks_trig_mode = MidiTrackTrigModes::from_hashmap(&hmap)?;
467
468 Ok(Self {
469 write_protected,
470 midi_soft_thru,
471 control,
473 mixer,
474 tempo,
475 midi_tracks_trig_mode,
476 })
477 }
478}
479
480impl std::fmt::Display for Settings {
481 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
482 let mut s = "".to_string();
483 s.push_str("[SETTINGS]");
484 s.push_str("\r\n");
485
486 s.push_str(format!("WRITEPROTECTED={}", self.write_protected as u8).as_str());
487 s.push_str("\r\n");
488 s.push_str(format!("TEMPOx24={}", self.tempo.tempo * 24).as_str());
489 s.push_str("\r\n");
490 s.push_str(
491 format!(
492 "PATTERN_TEMPO_ENABLED={}",
493 self.tempo.pattern_tempo_enabled as u8
494 )
495 .as_str(),
496 );
497 s.push_str("\r\n");
498
499 s.push_str(
500 format!(
501 "MIDI_CLOCK_SEND={}",
502 self.control.midi.sync.midi_clock_send as u8
503 )
504 .as_str(),
505 );
506 s.push_str("\r\n");
507 s.push_str(
508 format!(
509 "MIDI_CLOCK_RECEIVE={}",
510 self.control.midi.sync.midi_clock_receive as u8
511 )
512 .as_str(),
513 );
514 s.push_str("\r\n");
515 s.push_str(
516 format!(
517 "MIDI_TRANSPORT_SEND={}",
518 self.control.midi.sync.midi_transport_send as u8
519 )
520 .as_str(),
521 );
522 s.push_str("\r\n");
523 s.push_str(
524 format!(
525 "MIDI_TRANSPORT_RECEIVE={}",
526 self.control.midi.sync.midi_transport_receive as u8
527 )
528 .as_str(),
529 );
530 s.push_str("\r\n");
531 s.push_str(
532 format!(
533 "MIDI_PROGRAM_CHANGE_SEND={}",
534 self.control.midi.sync.midi_progchange_send as u8
535 )
536 .as_str(),
537 );
538 s.push_str("\r\n");
539 s.push_str(
540 format!(
541 "MIDI_PROGRAM_CHANGE_SEND_CH={}",
542 self.control
543 .midi
544 .sync
545 .midi_progchange_send_channel
546 .value()
547 .unwrap()
548 )
549 .as_str(),
550 );
551 s.push_str("\r\n");
552 s.push_str(
553 format!(
554 "MIDI_PROGRAM_CHANGE_RECEIVE={}",
555 self.control.midi.sync.midi_progchange_receive as u8
556 )
557 .as_str(),
558 );
559 s.push_str("\r\n");
560 s.push_str(
561 format!(
562 "MIDI_PROGRAM_CHANGE_RECEIVE_CH={}",
563 self.control
564 .midi
565 .sync
566 .midi_progchange_receive_channel
567 .value()
568 .unwrap()
569 )
570 .as_str(),
571 );
572 s.push_str("\r\n");
573
574 s.push_str(format!("MIDI_TRIG_CH1={}", self.control.midi.channels.midi_trig_ch1).as_str());
575 s.push_str("\r\n");
576 s.push_str(format!("MIDI_TRIG_CH2={}", self.control.midi.channels.midi_trig_ch2).as_str());
577 s.push_str("\r\n");
578 s.push_str(format!("MIDI_TRIG_CH3={}", self.control.midi.channels.midi_trig_ch3).as_str());
579 s.push_str("\r\n");
580 s.push_str(format!("MIDI_TRIG_CH4={}", self.control.midi.channels.midi_trig_ch4).as_str());
581 s.push_str("\r\n");
582 s.push_str(format!("MIDI_TRIG_CH5={}", self.control.midi.channels.midi_trig_ch5).as_str());
583 s.push_str("\r\n");
584 s.push_str(format!("MIDI_TRIG_CH6={}", self.control.midi.channels.midi_trig_ch6).as_str());
585 s.push_str("\r\n");
586 s.push_str(format!("MIDI_TRIG_CH7={}", self.control.midi.channels.midi_trig_ch7).as_str());
587 s.push_str("\r\n");
588 s.push_str(format!("MIDI_TRIG_CH8={}", self.control.midi.channels.midi_trig_ch8).as_str());
589 s.push_str("\r\n");
590 s.push_str(
591 format!(
592 "MIDI_AUTO_CHANNEL={}",
593 self.control.midi.channels.midi_auto_channel
594 )
595 .as_str(),
596 );
597 s.push_str("\r\n");
598
599 s.push_str(format!("MIDI_SOFT_THRU={}", self.midi_soft_thru as u8).as_str());
600 s.push_str("\r\n");
601
602 s.push_str(
603 format!(
604 "MIDI_AUDIO_TRK_CC_IN={}",
605 self.control.midi.control.midi_audio_track_cc_in as u8
606 )
607 .as_str(),
608 );
609 s.push_str("\r\n");
610 s.push_str(
611 format!(
612 "MIDI_AUDIO_TRK_CC_OUT={}",
613 self.control.midi.control.midi_audio_track_cc_out
614 )
615 .as_str(),
616 );
617 s.push_str("\r\n");
618 s.push_str(
619 format!("MIDI_AUDIO_TRK_NOTE_IN={}", {
620 self.control.midi.control.midi_audio_track_note_in
621 })
622 .as_str(),
623 );
624 s.push_str("\r\n");
625 s.push_str(
626 format!(
627 "MIDI_AUDIO_TRK_NOTE_OUT={}",
628 self.control.midi.control.midi_audio_track_note_out
629 )
630 .as_str(),
631 );
632 s.push_str("\r\n");
633 s.push_str(
634 format!(
635 "MIDI_MIDI_TRK_CC_IN={}",
636 self.control.midi.control.midi_midi_track_cc_in
637 )
638 .as_str(),
639 );
640 s.push_str("\r\n");
641
642 s.push_str(
643 format!(
644 "PATTERN_CHANGE_CHAIN_BEHAVIOR={}",
645 self.control.sequencer.pattern_change_chain_behaviour
646 )
647 .as_str(),
648 );
649 s.push_str("\r\n");
650 s.push_str(
651 format!(
652 "PATTERN_CHANGE_AUTO_SILENCE_TRACKS={}",
653 self.control.sequencer.pattern_change_auto_silence_tracks as u8
654 )
655 .as_str(),
656 );
657 s.push_str("\r\n");
658 s.push_str(
659 format!(
660 "PATTERN_CHANGE_AUTO_TRIG_LFOS={}",
661 self.control.sequencer.pattern_change_auto_trig_lfos as u8
662 )
663 .as_str(),
664 );
665 s.push_str("\r\n");
666
667 s.push_str(
668 format!(
669 "LOAD_24BIT_FLEX={}",
670 self.control.memory.load_24bit_flex as u8
671 )
672 .as_str(),
673 );
674 s.push_str("\r\n");
675 s.push_str(
676 format!(
677 "DYNAMIC_RECORDERS={}",
678 self.control.memory.dynamic_recorders as u8
679 )
680 .as_str(),
681 );
682 s.push_str("\r\n");
683 s.push_str(format!("RECORD_24BIT={}", self.control.memory.record_24bit as u8).as_str());
684 s.push_str("\r\n");
685 s.push_str(
686 format!(
687 "RESERVED_RECORDER_COUNT={}",
688 self.control.memory.reserved_recorder_count
689 )
690 .as_str(),
691 );
692 s.push_str("\r\n");
693 s.push_str(
694 format!(
695 "RESERVED_RECORDER_LENGTH={}",
696 self.control.memory.reserved_recorder_length
697 )
698 .as_str(),
699 );
700 s.push_str("\r\n");
701
702 s.push_str(
703 format!(
704 "INPUT_DELAY_COMPENSATION={}",
705 self.control.input.input_delay_compensation as u8
706 )
707 .as_str(),
708 );
709 s.push_str("\r\n");
710
711 s.push_str(format!("GATE_AB={}", self.control.input.gate_ab).as_str());
712 s.push_str("\r\n");
713 s.push_str(format!("GATE_CD={}", self.control.input.gate_cd).as_str());
714 s.push_str("\r\n");
715 s.push_str(format!("GAIN_AB={}", self.mixer.gain_ab).as_str());
716 s.push_str("\r\n");
717 s.push_str(format!("GAIN_CD={}", self.mixer.gain_cd).as_str());
718 s.push_str("\r\n");
719 s.push_str(format!("DIR_AB={}", self.mixer.dir_ab).as_str());
720 s.push_str("\r\n");
721 s.push_str(format!("DIR_CD={}", self.mixer.dir_cd).as_str());
722 s.push_str("\r\n");
723 s.push_str(format!("PHONES_MIX={}", self.mixer.phones_mix).as_str());
724 s.push_str("\r\n");
725 s.push_str(format!("MAIN_TO_CUE={}", self.mixer.main_to_cue).as_str());
726 s.push_str("\r\n");
727
728 s.push_str(format!("MASTER_TRACK={}", self.control.audio.master_track as u8).as_str());
729 s.push_str("\r\n");
730 s.push_str(
731 format!(
732 "CUE_STUDIO_MODE={}",
733 self.control.audio.cue_studio_mode as u8
734 )
735 .as_str(),
736 );
737 s.push_str("\r\n");
738
739 s.push_str(format!("MAIN_LEVEL={}", self.mixer.main_level).as_str());
740 s.push_str("\r\n");
741 s.push_str(format!("CUE_LEVEL={}", self.mixer.cue_level).as_str());
742 s.push_str("\r\n");
743
744 s.push_str(
745 format!(
746 "METRONOME_TIME_SIGNATURE={}",
747 self.control.metronome.metronome_time_signature
748 )
749 .as_str(),
750 );
751 s.push_str("\r\n");
752 s.push_str(
753 format!(
754 "METRONOME_TIME_SIGNATURE_DENOMINATOR={}",
755 self.control.metronome.metronome_time_signature_denominator
756 )
757 .as_str(),
758 );
759 s.push_str("\r\n");
760 s.push_str(
761 format!(
762 "METRONOME_PREROLL={}",
763 self.control.metronome.metronome_preroll
764 )
765 .as_str(),
766 );
767 s.push_str("\r\n");
768 s.push_str(
769 format!(
770 "METRONOME_CUE_VOLUME={}",
771 self.control.metronome.metronome_cue_volume
772 )
773 .as_str(),
774 );
775 s.push_str("\r\n");
776 s.push_str(
777 format!(
778 "METRONOME_MAIN_VOLUME={}",
779 self.control.metronome.metronome_main_volume
780 )
781 .as_str(),
782 );
783 s.push_str("\r\n");
784 s.push_str(format!("METRONOME_PITCH={}", self.control.metronome.metronome_pitch).as_str());
785 s.push_str("\r\n");
786 s.push_str(
787 format!(
788 "METRONOME_TONAL={}",
789 self.control.metronome.metronome_tonal as u8
790 )
791 .as_str(),
792 );
793 s.push_str("\r\n");
794 s.push_str(
795 format!(
796 "METRONOME_ENABLED={}",
797 self.control.metronome.metronome_enabled as u8
798 )
799 .as_str(),
800 );
801 s.push_str("\r\n");
802
803 s.push_str(
804 format!(
805 "TRIG_MODE_MIDI={}",
806 self.midi_tracks_trig_mode.trig_mode_midi_track_1
807 )
808 .as_str(),
809 );
810 s.push_str("\r\n");
811 s.push_str(
812 format!(
813 "TRIG_MODE_MIDI={}",
814 self.midi_tracks_trig_mode.trig_mode_midi_track_2
815 )
816 .as_str(),
817 );
818 s.push_str("\r\n");
819 s.push_str(
820 format!(
821 "TRIG_MODE_MIDI={}",
822 self.midi_tracks_trig_mode.trig_mode_midi_track_3
823 )
824 .as_str(),
825 );
826 s.push_str("\r\n");
827 s.push_str(
828 format!(
829 "TRIG_MODE_MIDI={}",
830 self.midi_tracks_trig_mode.trig_mode_midi_track_4
831 )
832 .as_str(),
833 );
834 s.push_str("\r\n");
835 s.push_str(
836 format!(
837 "TRIG_MODE_MIDI={}",
838 self.midi_tracks_trig_mode.trig_mode_midi_track_5
839 )
840 .as_str(),
841 );
842 s.push_str("\r\n");
843 s.push_str(
844 format!(
845 "TRIG_MODE_MIDI={}",
846 self.midi_tracks_trig_mode.trig_mode_midi_track_6
847 )
848 .as_str(),
849 );
850 s.push_str("\r\n");
851 s.push_str(
852 format!(
853 "TRIG_MODE_MIDI={}",
854 self.midi_tracks_trig_mode.trig_mode_midi_track_7
855 )
856 .as_str(),
857 );
858 s.push_str("\r\n");
859 s.push_str(
860 format!(
861 "TRIG_MODE_MIDI={}",
862 self.midi_tracks_trig_mode.trig_mode_midi_track_8
863 )
864 .as_str(),
865 );
866
867 s.push_str("\r\n[/SETTINGS]");
868
869 write!(f, "{s:#}")
870 }
871}