m8_file_parser/instruments/modulator/
lfo.rs

1use 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}