m8_file_parser/instruments/
common.rs1use std::fmt;
2
3use super::modulator::*;
4use crate::reader::*;
5use crate::writer::Writer;
6use crate::Version;
7use arr_macro::arr;
8
9#[derive(PartialEq, Copy, Clone, Default, Debug)]
11pub struct TranspEq {
12 pub transpose: bool,
13 pub eq: u8,
14}
15
16impl TranspEq {
17 pub fn from(ver: Version, transpose: bool, eq: u8) -> TranspEq {
18 if ver.at_least(4, 1) {
19 Self {
20 transpose,
21 eq: 0x00,
22 }
23 } else {
24 Self { transpose, eq }
25 }
26 }
27
28 pub fn from_version(ver: Version, value: u8) -> Self {
29 if ver.at_least(4, 1) {
30 Self {
31 transpose: (value & 1) != 0,
32 eq: 0x00,
33 }
34 } else {
35 Self {
36 transpose: (value & 1) != 0,
37 eq: value >> 1,
38 }
39 }
40 }
41}
42
43impl From<TranspEq> for u8 {
44 fn from(value: TranspEq) -> Self {
45 (if value.transpose { 1 } else { 0 }) | (value.eq << 1)
46 }
47}
48
49#[rustfmt::skip] const LIMIT_TYPE : [&str; 9] = [
51 "CLIP",
52 "SIN",
53 "FOLD",
54 "WRAP",
55 "POST",
56 "POSTAD",
57 "POST:W1",
58 "POST:W2",
59 "POST:W3"
60];
61
62#[derive(PartialEq, Clone, Copy)]
63pub struct LimitType(pub u8);
64
65impl fmt::Debug for LimitType {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 f.write_str(LIMIT_TYPE[self.0 as usize])
68 }
69}
70
71impl TryFrom<u8> for LimitType {
72 type Error = ParseError;
73
74 fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
75 if (value as usize) < LIMIT_TYPE.len() {
76 Ok(LimitType(value))
77 } else {
78 Err(ParseError(format!("Invalid fm wave {}", value)))
79 }
80 }
81}
82
83impl LimitType {
84 pub fn id(self) -> u8 {
85 let LimitType(v) = self;
86 v
87 }
88
89 pub fn str(self) -> &'static str {
90 LIMIT_TYPE[self.id() as usize]
91 }
92}
93
94#[derive(PartialEq, Debug, Clone)]
95pub struct SynthParams {
96 pub volume: u8,
97 pub pitch: u8,
98 pub fine_tune: u8,
99
100 pub filter_type: u8,
101 pub filter_cutoff: u8,
102 pub filter_res: u8,
103
104 pub amp: u8,
105 pub limit: LimitType,
106
107 pub mixer_pan: u8,
108 pub mixer_dry: u8,
109 pub mixer_mfx: u8,
110 pub mixer_delay: u8,
111 pub mixer_reverb: u8,
112
113 pub associated_eq: u8,
114
115 pub mods: [Mod; SynthParams::MODULATOR_COUNT],
116}
117
118#[rustfmt::skip] pub(crate) const COMMON_FILTER_TYPES : [&'static str; 8] = [
120 "OFF",
121 "LOWPASS",
122 "HIGHPAS",
123 "BANDPAS",
124 "BANDSTP",
125 "LP > HP",
126 "ZDF LP",
127 "ZDF HP",
128];
129
130impl SynthParams {
131 pub const MODULATOR_COUNT: usize = 4;
132
133 pub fn set_eq(&mut self, eq: u8) {
134 self.associated_eq = eq
135 }
136
137 pub fn mod_only2(_reader: &mut Reader) -> M8Result<Self> {
138 Ok(Self {
139 volume: 0,
140 pitch: 0,
141 fine_tune: 0,
142
143 filter_type: 0,
144 filter_cutoff: 0,
145 filter_res: 0,
146
147 amp: 0,
148 limit: LimitType::try_from(0)?,
149
150 mixer_pan: 0,
151 mixer_dry: 0,
152 mixer_mfx: 0,
153 mixer_delay: 0,
154 mixer_reverb: 0,
155
156 associated_eq: 0xFF,
157 mods: arr![AHDEnv::default().to_mod(); 4],
158 })
159 }
160
161 pub fn mod_only3(reader: &mut Reader, mod_offset: usize) -> M8Result<Self> {
162 reader.set_pos(reader.pos() + mod_offset);
163
164 let mods = arr![Mod::from_reader(reader)?; 4];
165
166 Ok(Self {
167 volume: 0,
168 pitch: 0,
169 fine_tune: 0,
170
171 filter_type: 0,
172 filter_cutoff: 0,
173 filter_res: 0,
174
175 amp: 0,
176 limit: LimitType::try_from(0)?,
177
178 mixer_pan: 0,
179 mixer_dry: 0,
180 mixer_mfx: 0,
181 mixer_delay: 0,
182 mixer_reverb: 0,
183 associated_eq: 0xFF,
184
185 mods,
186 })
187 }
188
189 pub fn from_reader2(
190 reader: &mut Reader,
191 volume: u8,
192 pitch: u8,
193 fine_tune: u8,
194 ) -> M8Result<Self> {
195 Ok(Self {
196 volume,
197 pitch,
198 fine_tune,
199
200 filter_type: reader.read(),
201 filter_cutoff: reader.read(),
202 filter_res: reader.read(),
203
204 amp: reader.read(),
205 limit: LimitType::try_from(reader.read())?,
206
207 mixer_pan: reader.read(),
208 mixer_dry: reader.read(),
209 mixer_mfx: reader.read(),
210 mixer_delay: reader.read(),
211 mixer_reverb: reader.read(),
212
213 associated_eq: 0xFF,
214
215 mods: [
216 AHDEnv::from_reader2(reader)?.to_mod(),
217 AHDEnv::from_reader2(reader)?.to_mod(),
218 LFO::from_reader2(reader)?.to_mod(),
219 LFO::from_reader2(reader)?.to_mod(),
220 ],
221 })
222 }
223
224 pub fn write(&self, ver: Version, w: &mut Writer, mod_offset: usize) {
225 w.write(self.filter_type);
226 w.write(self.filter_cutoff);
227 w.write(self.filter_res);
228
229 w.write(self.amp);
230 w.write(self.limit.0);
231
232 w.write(self.mixer_pan);
233 w.write(self.mixer_dry);
234 w.write(self.mixer_mfx);
235 w.write(self.mixer_delay);
236 w.write(self.mixer_reverb);
237
238 let writer_pos = w.pos();
239 if ver.at_least(4, 1) {
240 w.seek(writer_pos + mod_offset - 1);
241 w.write(self.associated_eq);
242 }
243
244 w.seek(writer_pos + mod_offset);
245 for m in &self.mods {
246 m.write(w);
247 }
248 }
249
250 pub fn write_modes(&self, w: &mut Writer, mod_offset: usize) {
251 w.seek(w.pos() + mod_offset);
252 for m in &self.mods {
253 m.write(w);
254 }
255 }
256
257 pub fn from_reader3(
258 version: Version,
259 reader: &mut Reader,
260 volume: u8,
261 pitch: u8,
262 fine_tune: u8,
263 eq: u8,
264 mod_offset: usize,
265 ) -> M8Result<Self> {
266 let filter_type = reader.read();
267 let filter_cutoff = reader.read();
268 let filter_res = reader.read();
269
270 let amp = reader.read();
271 let limit = reader.read();
272
273 let mixer_pan = reader.read();
274 let mixer_dry = reader.read();
275 let mixer_chorus = reader.read();
276 let mixer_delay = reader.read();
277 let mixer_reverb = reader.read();
278
279 let reader_pos = reader.pos();
280 let associated_eq = if version.at_least(4, 1) {
281 reader.set_pos(reader_pos + mod_offset - 1);
282 reader.read()
283 } else if version.at_least(4, 0) {
284 eq
285 } else {
286 0xFF
287 };
288
289 reader.set_pos(reader_pos + mod_offset);
290
291 let mods = arr![Mod::from_reader(reader)?; 4];
292
293 Ok(Self {
294 volume,
295 pitch,
296 fine_tune,
297
298 filter_type,
299 filter_cutoff,
300 filter_res,
301
302 amp,
303 limit: LimitType::try_from(limit)?,
304
305 mixer_pan,
306 mixer_dry,
307 mixer_mfx: mixer_chorus,
308 mixer_delay,
309 mixer_reverb,
310
311 associated_eq,
312
313 mods,
314 })
315 }
316}