m8_file_parser/instruments/
macrosynth.rs1use crate::instruments::common::*;
2use crate::reader::*;
3use crate::version::*;
4use crate::writer::Writer;
5use num_enum::IntoPrimitive;
6use num_enum::TryFromPrimitive;
7
8use super::dests;
9use super::CommandPack;
10
11#[repr(u8)]
13#[allow(non_camel_case_types)]
14#[derive(IntoPrimitive, TryFromPrimitive, PartialEq, Copy, Clone, Default, Debug)]
15pub enum MacroSynthOsc {
16 #[default]
17 CSAW,
18 MORPH,
19 SAW_SQUARE,
20 SINE_TRIANGLE,
21 BUZZ,
22 SQUARE_SUB,
23 SAW_SUB,
24 SQUARE_SYNC,
25 SAW_SYNC,
26 TRIPLE_SAW,
27 TRIPLE_SQUARE,
28 TRIPLE_TRIANGLE,
29 TRIPLE_SIN,
30 TRIPLE_RNG,
31 SAW_SWARM,
32 SAW_COMB,
33 TOY,
34 DIGITAL_FILTER_LP,
35 DIGITAL_FILTER_PK,
36 DIGITAL_FILTER_BP,
37 DIGITAL_FILTER_HP,
38 VOSIM,
39 VOWEL,
40 VOWEL_FOF,
41 HARMONICS,
42 FM,
43 FEEDBACK_FM,
44 CHAOTIC_FEEDBACK_FM,
45 PLUCKED,
46 BOWED,
47 BLOWN,
48 FLUTED,
49 STRUCK_BELL,
50 STRUCK_DRUM,
51 KICK,
52 CYMBAL,
53 SNARE,
54 WAVETABLES,
55 WAVE_MAP,
56 WAV_LINE,
57 WAV_PARAPHONIC,
58 FILTERED_NOISE,
59 TWIN_PEAKS_NOISE,
60 CLOCKED_NOISE,
61 GRANULAR_CLOUD,
62 PARTICLE_NOISE,
63 DIGITAL_MOD,
64 MORSE_NOISE,
65}
66
67#[rustfmt::skip] const MACRO_SYNTH_COMMANDS : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] = [
69 "VOL",
70 "PIT",
71 "FIN",
72 "OSC",
73 "TBR",
74 "COL",
75 "DEG",
76 "RED",
77 "FIL",
78 "CUT",
79 "RES",
80 "AMP",
81 "LIM",
82 "PAN",
83 "DRY",
84
85 "SCH",
86 "SDL",
87 "SRV",
88
89 "TRG",
91 "ERR"
92];
93
94#[rustfmt::skip] const DESTINATIONS : [&'static str; 15] = [
96 dests::OFF,
97 dests::VOLUME,
98 dests::PITCH,
99
100 "TIMBRE",
101 "COLOR",
102 dests::DEGRADE,
103 "REDUX",
104 dests::CUTOFF,
105 dests::RES,
106 dests::AMP,
107 dests::PAN,
108 dests::MOD_AMT,
109 dests::MOD_RATE,
110 dests::MOD_BOTH,
111 dests::MOD_BINV,
112];
113
114#[derive(PartialEq, Debug, Clone)]
115pub struct MacroSynth {
116 pub number: u8,
117 pub name: String, pub transpose: bool, pub table_tick: u8, pub synth_params: SynthParams, pub shape: MacroSynthOsc, pub timbre: u8, pub color: u8, pub degrade: u8, pub redux: u8, }
128
129impl MacroSynth {
130 pub const MOD_OFFSET: usize = 30;
131
132 pub fn command_name(&self, _ver: Version) -> &'static [&'static str] {
133 &MACRO_SYNTH_COMMANDS
134 }
135
136 pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
137 &DESTINATIONS
138 }
139
140 pub fn filter_types(&self, _ver: Version) -> &'static [&'static str] {
142 &super::common::COMMON_FILTER_TYPES
143 }
144
145 pub fn human_readable_filter(&self) -> &'static str {
146 COMMON_FILTER_TYPES[self.synth_params.filter_type as usize]
147 }
148
149 pub fn write(&self, ver: Version, w: &mut Writer) {
150 w.write_string(&self.name, 12);
151 w.write(TranspEq::from(ver, self.transpose, self.synth_params.associated_eq).into());
152 w.write(self.table_tick);
153 w.write(self.synth_params.volume);
154 w.write(self.synth_params.pitch);
155 w.write(self.synth_params.fine_tune);
156
157 w.write(self.shape.into());
158 w.write(self.timbre);
159 w.write(self.color);
160 w.write(self.degrade);
161 w.write(self.redux);
162
163 self.synth_params.write(ver, w, MacroSynth::MOD_OFFSET);
164 }
165
166 pub fn from_reader(
167 ver: Version,
168 reader: &mut Reader,
169 number: u8,
170 version: Version,
171 ) -> M8Result<Self> {
172 let ms_pos = reader.pos();
173 let name = reader.read_string(12);
174
175 let transp_eq = TranspEq::from_version(ver, reader.read());
176 let table_tick = reader.read();
177 let volume = reader.read();
178 let pitch = reader.read();
179 let fine_tune = reader.read();
180
181 let ofs_shape = reader.pos();
182 let shape = reader.read();
183 let timbre = reader.read();
184 let color = reader.read();
185 let degrade = reader.read();
186 let redux = reader.read();
187
188 let synth_params = if version.at_least(3, 0) {
189 SynthParams::from_reader3(
190 ver,
191 reader,
192 volume,
193 pitch,
194 fine_tune,
195 transp_eq.eq,
196 MacroSynth::MOD_OFFSET,
197 )?
198 } else {
199 SynthParams::from_reader2(reader, volume, pitch, fine_tune)?
200 };
201
202 let nc = name.clone();
203 Ok(MacroSynth {
204 number,
205 name,
206 transpose: transp_eq.transpose,
207 table_tick,
208 synth_params,
209
210 shape: shape.try_into().map_err(|_| {
211 ParseError(format!(
212 "I{number:X} Wrong macrosynth@{ms_pos} ({nc}) shape {shape}@0x{ofs_shape}"
213 ))
214 })?,
215 timbre,
216 color,
217 degrade,
218 redux,
219 })
220 }
221}