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