1use 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 + 1] = [
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];
92
93#[rustfmt::skip] const DESTINATIONS : [&'static str; 15] = [
95 dests::OFF,
96 dests::VOLUME,
97 dests::PITCH,
98
99 "TIMBRE",
100 "COLOR",
101 dests::DEGRADE,
102 "REDUX",
103 dests::CUTOFF,
104 dests::RES,
105 dests::AMP,
106 dests::PAN,
107 dests::MOD_AMT,
108 dests::MOD_RATE,
109 dests::MOD_BOTH,
110 dests::MOD_BINV,
111];
112
113#[derive(PartialEq, Debug, Clone)]
114pub struct MacroSynth {
115 pub number: u8,
116 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, }
127
128impl MacroSynth {
129 pub const MOD_OFFSET: usize = 30;
130
131 pub fn command_name(&self, _ver: Version) -> &'static [&'static str] {
132 &MACRO_SYNTH_COMMANDS
133 }
134
135 pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
136 &DESTINATIONS
137 }
138
139 pub fn filter_types(&self, _ver: Version) -> &'static [&'static str] {
141 &super::common::COMMON_FILTER_TYPES
142 }
143
144 pub fn human_readable_filter(&self) -> &'static str {
145 COMMON_FILTER_TYPES[self.synth_params.filter_type as usize]
146 }
147
148 pub fn write(&self, ver: Version, w: &mut Writer) {
149 w.write_string(&self.name, 12);
150 w.write(TranspEq::from(ver, self.transpose, self.synth_params.associated_eq).into());
151 w.write(self.table_tick);
152 w.write(self.synth_params.volume);
153 w.write(self.synth_params.pitch);
154 w.write(self.synth_params.fine_tune);
155
156 w.write(self.shape.into());
157 w.write(self.timbre);
158 w.write(self.color);
159 w.write(self.degrade);
160 w.write(self.redux);
161
162 self.synth_params.write(ver, w, MacroSynth::MOD_OFFSET);
163 }
164
165 pub fn from_reader(
166 ver: Version,
167 reader: &mut Reader,
168 number: u8,
169 version: Version,
170 ) -> M8Result<Self> {
171 let ms_pos = reader.pos();
172 let name = reader.read_string(12);
173
174 let transp_eq = TranspEq::from_version(ver, reader.read());
175 let table_tick = reader.read();
176 let volume = reader.read();
177 let pitch = reader.read();
178 let fine_tune = reader.read();
179
180 let ofs_shape = reader.pos();
181 let shape = reader.read();
182 let timbre = reader.read();
183 let color = reader.read();
184 let degrade = reader.read();
185 let redux = reader.read();
186
187 let synth_params = if version.at_least(3, 0) {
188 SynthParams::from_reader3(
189 ver,
190 reader,
191 volume,
192 pitch,
193 fine_tune,
194 transp_eq.eq,
195 MacroSynth::MOD_OFFSET,
196 )?
197 } else {
198 SynthParams::from_reader2(reader, volume, pitch, fine_tune)?
199 };
200
201 let nc = name.clone();
202 Ok(MacroSynth {
203 number,
204 name,
205 transpose: transp_eq.transpose,
206 table_tick,
207 synth_params,
208
209 shape: shape.try_into().map_err(|_| {
210 ParseError(format!(
211 "I{number:X} Wrong macrosynth@{ms_pos} ({nc}) shape {shape}@0x{ofs_shape}"
212 ))
213 })?,
214 timbre,
215 color,
216 degrade,
217 redux,
218 })
219 }
220}