m8_file_parser/instruments/modulator/
lfo.rs1use num_enum::{IntoPrimitive, TryFromPrimitive};
2
3use crate::{writer::Writer, Version};
4
5use super::{M8Result, Mod, ParseError, Reader};
6
7#[repr(u8)]
8#[allow(non_camel_case_types)]
9#[derive(IntoPrimitive, TryFromPrimitive, PartialEq, Copy, Clone, Default, Debug)]
10pub enum LfoShape {
11 #[default]
12 TRI,
13 SIN,
14 RAMP_DOWN,
15 RAMP_UP,
16 EXP_DN,
17 EXP_UP,
18 SQR_DN,
19 SQR_UP,
20 RANDOM,
21 DRUNK,
22 TRI_T,
23 SIN_T,
24 RAMPD_T,
25 RAMPU_T,
26 EXPD_T,
27 EXPU_T,
28 SQ_D_T,
29 SQ_U_T,
30 RAND_T,
31 DRNK_T,
32}
33
34#[repr(u8)]
35#[allow(non_camel_case_types)]
36#[derive(IntoPrimitive, TryFromPrimitive, PartialEq, Copy, Clone, Default, Debug)]
37pub enum LfoTriggerMode {
38 #[default]
39 FREE,
40 RETRIG,
41 HOLD,
42 ONCE,
43}
44
45#[derive(PartialEq, Debug, Clone)]
46pub struct LFO {
47 pub shape: LfoShape,
48 pub dest: u8,
49 pub trigger_mode: LfoTriggerMode,
50 pub freq: u8,
51 pub amount: u8,
52 pub retrigger: u8,
53}
54
55const LFO_COMMAND_NAMES: [[&'static str; 5]; 4] = [
56 ["LA1", "LO1", "LS1", "LF1", "LT1"],
57 ["LA2", "LO2", "LS2", "LF2", "LT2"],
58 ["LA3", "LO3", "LS3", "LF3", "LT3"],
59 ["LA4", "LO4", "LS4", "LF4", "LT4"],
60];
61
62impl LFO {
63 pub fn command_name(_ver: Version, mod_id: usize) -> &'static [&'static str] {
64 &LFO_COMMAND_NAMES[mod_id]
65 }
66
67 pub fn from_reader2(reader: &mut Reader) -> M8Result<Self> {
68 let shape = reader.read();
69 let dest = reader.read();
70 let trigger = reader.read();
71 let r = Self {
72 shape: shape
73 .try_into()
74 .map_err(|_| ParseError(format!("Invalid LFO shape {}", shape)))?,
75 dest,
76 trigger_mode: trigger
77 .try_into()
78 .map_err(|_| ParseError(format!("Invalid lfo trigger mode {}", trigger)))?,
79 freq: reader.read(),
80 amount: reader.read(),
81 retrigger: reader.read(),
82 };
83
84 Ok(r)
85 }
86
87 pub fn write(&self, w: &mut Writer) {
88 w.write(self.amount);
89 w.write(self.shape.into());
90 w.write(self.trigger_mode.into());
91 w.write(self.freq);
92 w.write(self.retrigger);
93 }
94
95 pub fn from_reader3(reader: &mut Reader, dest: u8) -> M8Result<Self> {
96 let amount = reader.read();
97 let shape = reader.read();
98 let trigger_mode = reader.read();
99 let freq = reader.read();
100 let retrigger = reader.read();
101
102 Ok(Self {
103 dest,
104 amount,
105 shape: shape
106 .try_into()
107 .map_err(|_| ParseError(format!("Invalid LFO shape {}", shape)))?,
108 trigger_mode: trigger_mode
109 .try_into()
110 .map_err(|_| ParseError(format!("Invalid lfo trigger mode {}", trigger_mode)))?,
111 freq,
112 retrigger,
113 })
114 }
115
116 pub fn to_mod(self) -> Mod {
117 Mod::LFO(self)
118 }
119}