1mod control_menu;
11mod mixer;
12mod tempo;
13mod trig_mode_midi_tracks;
14
15pub use control_menu::{
16 AudioControlPage, ControlMenu, InputControlPage, MemoryControlPage, MetronomeControlPage,
17 MidiChannelsMidiPage, MidiControlMidiPage, MidiSequencerControlPage, MidiSubMenu,
18 MidiSyncMidiPage, SequencerControlPage,
19};
20pub use mixer::MixerMenu;
21pub use tempo::TempoMenu;
22pub use trig_mode_midi_tracks::MidiTrackTrigModes;
23
24use crate::projects::{
25 parse_hashmap_string_value_bool, string_to_hashmap, ProjectParseError, SectionHeader,
26};
27use crate::settings::MidiChannel;
28use serde::{Deserialize, Serialize};
29
30#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
100pub struct Settings {
101 pub write_protected: bool,
103
104 pub control: ControlMenu,
106
107 pub midi_soft_thru: bool,
109
110 pub mixer: MixerMenu,
112
113 pub tempo: TempoMenu,
115
116 pub midi_tracks_trig_mode: MidiTrackTrigModes,
118}
119
120impl Default for Settings {
121 fn default() -> Self {
122 Self {
123 write_protected: false,
124 control: ControlMenu {
125 audio: AudioControlPage {
126 master_track: false,
127 cue_studio_mode: false,
128 },
129 input: InputControlPage {
130 gate_ab: 127,
131 gate_cd: 127,
132 input_delay_compensation: false,
133 },
134 sequencer: SequencerControlPage {
135 pattern_change_chain_behaviour: 0,
136 pattern_change_auto_silence_tracks: false,
137 pattern_change_auto_trig_lfos: false,
138 },
139 midi_sequencer: MidiSequencerControlPage {},
140 memory: MemoryControlPage {
141 load_24bit_flex: false,
142 dynamic_recorders: false,
143 record_24bit: false,
144 reserved_recorder_count: 8,
145 reserved_recorder_length: 16,
146 },
147 metronome: MetronomeControlPage {
148 metronome_time_signature: 3,
149 metronome_time_signature_denominator: 2,
150 metronome_preroll: 0,
151 metronome_cue_volume: 32,
152 metronome_main_volume: 0,
153 metronome_pitch: 12,
154 metronome_tonal: true,
155 metronome_enabled: false,
156 },
157 midi: MidiSubMenu {
158 control: MidiControlMidiPage {
159 midi_audio_track_cc_in: true,
160 midi_audio_track_cc_out: 3,
161 midi_audio_track_note_in: 1,
162 midi_audio_track_note_out: 3,
163 midi_midi_track_cc_in: 1,
164 },
165 sync: MidiSyncMidiPage {
166 midi_clock_send: false,
167 midi_clock_receive: false,
168 midi_transport_send: false,
169 midi_transport_receive: false,
170 midi_progchange_send: false,
171 midi_progchange_send_channel: MidiChannel::Disabled,
172 midi_progchange_receive: false,
173 midi_progchange_receive_channel: MidiChannel::Disabled,
174 },
175 channels: MidiChannelsMidiPage {
176 midi_trig_ch1: 0,
177 midi_trig_ch2: 1,
178 midi_trig_ch3: 2,
179 midi_trig_ch4: 3,
180 midi_trig_ch5: 4,
181 midi_trig_ch6: 5,
182 midi_trig_ch7: 6,
183 midi_trig_ch8: 7,
184 midi_auto_channel: 10,
185 },
186 },
187 },
188 midi_soft_thru: false,
189 mixer: MixerMenu {
190 gain_ab: 64,
191 gain_cd: 64,
192 dir_ab: 0,
193 dir_cd: 0,
194 phones_mix: 64,
195 main_to_cue: 0,
196 main_level: 64,
197 cue_level: 64,
198 },
199 tempo: TempoMenu {
200 tempo: 120,
201 pattern_tempo_enabled: false,
202 },
203 midi_tracks_trig_mode: MidiTrackTrigModes {
204 trig_mode_midi_track_1: 0,
205 trig_mode_midi_track_2: 0,
206 trig_mode_midi_track_3: 0,
207 trig_mode_midi_track_4: 0,
208 trig_mode_midi_track_5: 0,
209 trig_mode_midi_track_6: 0,
210 trig_mode_midi_track_7: 0,
211 trig_mode_midi_track_8: 0,
212 },
213 }
214 }
215}
216
217impl std::str::FromStr for Settings {
218 type Err = ProjectParseError;
219
220 fn from_str(s: &str) -> Result<Self, Self::Err> {
222 let hmap = string_to_hashmap(s, &SectionHeader::Settings)?;
223
224 let write_protected = parse_hashmap_string_value_bool(&hmap, "writeprotected", None)?;
225 let midi_soft_thru = parse_hashmap_string_value_bool(&hmap, "midi_soft_thru", None)?;
227 let control = ControlMenu::try_from(&hmap)?;
228 let mixer = MixerMenu::try_from(&hmap)?;
229 let tempo = TempoMenu::try_from(&hmap)?;
230 let midi_tracks_trig_mode = MidiTrackTrigModes::try_from(&hmap)?;
231
232 Ok(Self {
233 write_protected,
234 midi_soft_thru,
235 control,
237 mixer,
238 tempo,
239 midi_tracks_trig_mode,
240 })
241 }
242}
243
244impl std::fmt::Display for Settings {
245 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
246 let mut s = "".to_string();
247 s.push_str("[SETTINGS]");
248 s.push_str("\r\n");
249
250 s.push_str(format!("WRITEPROTECTED={}", self.write_protected as u8).as_str());
251 s.push_str("\r\n");
252 s.push_str(format!("TEMPOx24={}", self.tempo.tempo * 24).as_str());
253 s.push_str("\r\n");
254 s.push_str(
255 format!(
256 "PATTERN_TEMPO_ENABLED={}",
257 self.tempo.pattern_tempo_enabled as u8
258 )
259 .as_str(),
260 );
261 s.push_str("\r\n");
262
263 s.push_str(
264 format!(
265 "MIDI_CLOCK_SEND={}",
266 self.control.midi.sync.midi_clock_send as u8
267 )
268 .as_str(),
269 );
270 s.push_str("\r\n");
271 s.push_str(
272 format!(
273 "MIDI_CLOCK_RECEIVE={}",
274 self.control.midi.sync.midi_clock_receive as u8
275 )
276 .as_str(),
277 );
278 s.push_str("\r\n");
279 s.push_str(
280 format!(
281 "MIDI_TRANSPORT_SEND={}",
282 self.control.midi.sync.midi_transport_send as u8
283 )
284 .as_str(),
285 );
286 s.push_str("\r\n");
287 s.push_str(
288 format!(
289 "MIDI_TRANSPORT_RECEIVE={}",
290 self.control.midi.sync.midi_transport_receive as u8
291 )
292 .as_str(),
293 );
294 s.push_str("\r\n");
295 s.push_str(
296 format!(
297 "MIDI_PROGRAM_CHANGE_SEND={}",
298 self.control.midi.sync.midi_progchange_send as u8
299 )
300 .as_str(),
301 );
302 s.push_str("\r\n");
303 s.push_str(
304 format!(
305 "MIDI_PROGRAM_CHANGE_SEND_CH={}",
306 self.control.midi.sync.midi_progchange_send_channel as i8
308 )
309 .as_str(),
310 );
311 s.push_str("\r\n");
312 s.push_str(
313 format!(
314 "MIDI_PROGRAM_CHANGE_RECEIVE={}",
315 self.control.midi.sync.midi_progchange_receive as u8
316 )
317 .as_str(),
318 );
319 s.push_str("\r\n");
320 s.push_str(
321 format!(
322 "MIDI_PROGRAM_CHANGE_RECEIVE_CH={}",
323 self.control.midi.sync.midi_progchange_receive_channel as i8
325 )
326 .as_str(),
327 );
328 s.push_str("\r\n");
329
330 s.push_str(format!("MIDI_TRIG_CH1={}", self.control.midi.channels.midi_trig_ch1).as_str());
331 s.push_str("\r\n");
332 s.push_str(format!("MIDI_TRIG_CH2={}", self.control.midi.channels.midi_trig_ch2).as_str());
333 s.push_str("\r\n");
334 s.push_str(format!("MIDI_TRIG_CH3={}", self.control.midi.channels.midi_trig_ch3).as_str());
335 s.push_str("\r\n");
336 s.push_str(format!("MIDI_TRIG_CH4={}", self.control.midi.channels.midi_trig_ch4).as_str());
337 s.push_str("\r\n");
338 s.push_str(format!("MIDI_TRIG_CH5={}", self.control.midi.channels.midi_trig_ch5).as_str());
339 s.push_str("\r\n");
340 s.push_str(format!("MIDI_TRIG_CH6={}", self.control.midi.channels.midi_trig_ch6).as_str());
341 s.push_str("\r\n");
342 s.push_str(format!("MIDI_TRIG_CH7={}", self.control.midi.channels.midi_trig_ch7).as_str());
343 s.push_str("\r\n");
344 s.push_str(format!("MIDI_TRIG_CH8={}", self.control.midi.channels.midi_trig_ch8).as_str());
345 s.push_str("\r\n");
346 s.push_str(
347 format!(
348 "MIDI_AUTO_CHANNEL={}",
349 self.control.midi.channels.midi_auto_channel
350 )
351 .as_str(),
352 );
353 s.push_str("\r\n");
354
355 s.push_str(format!("MIDI_SOFT_THRU={}", self.midi_soft_thru as u8).as_str());
356 s.push_str("\r\n");
357
358 s.push_str(
359 format!(
360 "MIDI_AUDIO_TRK_CC_IN={}",
361 self.control.midi.control.midi_audio_track_cc_in as u8
362 )
363 .as_str(),
364 );
365 s.push_str("\r\n");
366 s.push_str(
367 format!(
368 "MIDI_AUDIO_TRK_CC_OUT={}",
369 self.control.midi.control.midi_audio_track_cc_out
370 )
371 .as_str(),
372 );
373 s.push_str("\r\n");
374 s.push_str(
375 format!("MIDI_AUDIO_TRK_NOTE_IN={}", {
376 self.control.midi.control.midi_audio_track_note_in
377 })
378 .as_str(),
379 );
380 s.push_str("\r\n");
381 s.push_str(
382 format!(
383 "MIDI_AUDIO_TRK_NOTE_OUT={}",
384 self.control.midi.control.midi_audio_track_note_out
385 )
386 .as_str(),
387 );
388 s.push_str("\r\n");
389 s.push_str(
390 format!(
391 "MIDI_MIDI_TRK_CC_IN={}",
392 self.control.midi.control.midi_midi_track_cc_in
393 )
394 .as_str(),
395 );
396 s.push_str("\r\n");
397
398 s.push_str(
399 format!(
400 "PATTERN_CHANGE_CHAIN_BEHAVIOR={}",
401 self.control.sequencer.pattern_change_chain_behaviour
402 )
403 .as_str(),
404 );
405 s.push_str("\r\n");
406 s.push_str(
407 format!(
408 "PATTERN_CHANGE_AUTO_SILENCE_TRACKS={}",
409 self.control.sequencer.pattern_change_auto_silence_tracks as u8
410 )
411 .as_str(),
412 );
413 s.push_str("\r\n");
414 s.push_str(
415 format!(
416 "PATTERN_CHANGE_AUTO_TRIG_LFOS={}",
417 self.control.sequencer.pattern_change_auto_trig_lfos as u8
418 )
419 .as_str(),
420 );
421 s.push_str("\r\n");
422
423 s.push_str(
424 format!(
425 "LOAD_24BIT_FLEX={}",
426 self.control.memory.load_24bit_flex as u8
427 )
428 .as_str(),
429 );
430 s.push_str("\r\n");
431 s.push_str(
432 format!(
433 "DYNAMIC_RECORDERS={}",
434 self.control.memory.dynamic_recorders as u8
435 )
436 .as_str(),
437 );
438 s.push_str("\r\n");
439 s.push_str(format!("RECORD_24BIT={}", self.control.memory.record_24bit as u8).as_str());
440 s.push_str("\r\n");
441 s.push_str(
442 format!(
443 "RESERVED_RECORDER_COUNT={}",
444 self.control.memory.reserved_recorder_count
445 )
446 .as_str(),
447 );
448 s.push_str("\r\n");
449 s.push_str(
450 format!(
451 "RESERVED_RECORDER_LENGTH={}",
452 self.control.memory.reserved_recorder_length
453 )
454 .as_str(),
455 );
456 s.push_str("\r\n");
457
458 s.push_str(
459 format!(
460 "INPUT_DELAY_COMPENSATION={}",
461 self.control.input.input_delay_compensation as u8
462 )
463 .as_str(),
464 );
465 s.push_str("\r\n");
466
467 s.push_str(format!("GATE_AB={}", self.control.input.gate_ab).as_str());
468 s.push_str("\r\n");
469 s.push_str(format!("GATE_CD={}", self.control.input.gate_cd).as_str());
470 s.push_str("\r\n");
471 s.push_str(format!("GAIN_AB={}", self.mixer.gain_ab).as_str());
472 s.push_str("\r\n");
473 s.push_str(format!("GAIN_CD={}", self.mixer.gain_cd).as_str());
474 s.push_str("\r\n");
475 s.push_str(format!("DIR_AB={}", self.mixer.dir_ab).as_str());
476 s.push_str("\r\n");
477 s.push_str(format!("DIR_CD={}", self.mixer.dir_cd).as_str());
478 s.push_str("\r\n");
479 s.push_str(format!("PHONES_MIX={}", self.mixer.phones_mix).as_str());
480 s.push_str("\r\n");
481 s.push_str(format!("MAIN_TO_CUE={}", self.mixer.main_to_cue).as_str());
482 s.push_str("\r\n");
483
484 s.push_str(format!("MASTER_TRACK={}", self.control.audio.master_track as u8).as_str());
485 s.push_str("\r\n");
486 s.push_str(
487 format!(
488 "CUE_STUDIO_MODE={}",
489 self.control.audio.cue_studio_mode as u8
490 )
491 .as_str(),
492 );
493 s.push_str("\r\n");
494
495 s.push_str(format!("MAIN_LEVEL={}", self.mixer.main_level).as_str());
496 s.push_str("\r\n");
497 s.push_str(format!("CUE_LEVEL={}", self.mixer.cue_level).as_str());
498 s.push_str("\r\n");
499
500 s.push_str(
501 format!(
502 "METRONOME_TIME_SIGNATURE={}",
503 self.control.metronome.metronome_time_signature
504 )
505 .as_str(),
506 );
507 s.push_str("\r\n");
508 s.push_str(
509 format!(
510 "METRONOME_TIME_SIGNATURE_DENOMINATOR={}",
511 self.control.metronome.metronome_time_signature_denominator
512 )
513 .as_str(),
514 );
515 s.push_str("\r\n");
516 s.push_str(
517 format!(
518 "METRONOME_PREROLL={}",
519 self.control.metronome.metronome_preroll
520 )
521 .as_str(),
522 );
523 s.push_str("\r\n");
524 s.push_str(
525 format!(
526 "METRONOME_CUE_VOLUME={}",
527 self.control.metronome.metronome_cue_volume
528 )
529 .as_str(),
530 );
531 s.push_str("\r\n");
532 s.push_str(
533 format!(
534 "METRONOME_MAIN_VOLUME={}",
535 self.control.metronome.metronome_main_volume
536 )
537 .as_str(),
538 );
539 s.push_str("\r\n");
540 s.push_str(format!("METRONOME_PITCH={}", self.control.metronome.metronome_pitch).as_str());
541 s.push_str("\r\n");
542 s.push_str(
543 format!(
544 "METRONOME_TONAL={}",
545 self.control.metronome.metronome_tonal as u8
546 )
547 .as_str(),
548 );
549 s.push_str("\r\n");
550 s.push_str(
551 format!(
552 "METRONOME_ENABLED={}",
553 self.control.metronome.metronome_enabled as u8
554 )
555 .as_str(),
556 );
557 s.push_str("\r\n");
558
559 s.push_str(
560 format!(
561 "TRIG_MODE_MIDI={}",
562 self.midi_tracks_trig_mode.trig_mode_midi_track_1
563 )
564 .as_str(),
565 );
566 s.push_str("\r\n");
567 s.push_str(
568 format!(
569 "TRIG_MODE_MIDI={}",
570 self.midi_tracks_trig_mode.trig_mode_midi_track_2
571 )
572 .as_str(),
573 );
574 s.push_str("\r\n");
575 s.push_str(
576 format!(
577 "TRIG_MODE_MIDI={}",
578 self.midi_tracks_trig_mode.trig_mode_midi_track_3
579 )
580 .as_str(),
581 );
582 s.push_str("\r\n");
583 s.push_str(
584 format!(
585 "TRIG_MODE_MIDI={}",
586 self.midi_tracks_trig_mode.trig_mode_midi_track_4
587 )
588 .as_str(),
589 );
590 s.push_str("\r\n");
591 s.push_str(
592 format!(
593 "TRIG_MODE_MIDI={}",
594 self.midi_tracks_trig_mode.trig_mode_midi_track_5
595 )
596 .as_str(),
597 );
598 s.push_str("\r\n");
599 s.push_str(
600 format!(
601 "TRIG_MODE_MIDI={}",
602 self.midi_tracks_trig_mode.trig_mode_midi_track_6
603 )
604 .as_str(),
605 );
606 s.push_str("\r\n");
607 s.push_str(
608 format!(
609 "TRIG_MODE_MIDI={}",
610 self.midi_tracks_trig_mode.trig_mode_midi_track_7
611 )
612 .as_str(),
613 );
614 s.push_str("\r\n");
615 s.push_str(
616 format!(
617 "TRIG_MODE_MIDI={}",
618 self.midi_tracks_trig_mode.trig_mode_midi_track_8
619 )
620 .as_str(),
621 );
622
623 s.push_str("\r\n[/SETTINGS]");
624
625 write!(f, "{s:#}")
626 }
627}