m8_file_parser/instruments/
common.rs1use std::fmt;
2
3use super::modulator::*;
4use crate::{reader::*, FIRMWARE_5_0_SONG_VERSION, FIRMWARE_4_0_SONG_VERSION };
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.after(&FIRMWARE_5_0_SONG_VERSION) {
19 Self {
20 transpose,
21 eq: 0x80,
22 }
23 } else {
24 Self { transpose, eq }
25 }
26 }
27
28 pub fn from_version(ver: Version, value: u8) -> Self {
29 if ver.after(&FIRMWARE_5_0_SONG_VERSION) {
30 Self {
31 transpose: (value & 1) != 0,
32 eq: 0x80,
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 shape: u8,
109
110 pub mixer_pan: u8,
111 pub mixer_dry: u8,
112 pub mixer_mfx: u8,
113 pub mixer_delay: u8,
114 pub mixer_reverb: u8,
115
116 pub associated_eq: u8,
117
118 pub mods: [Mod; SynthParams::MODULATOR_COUNT],
119}
120
121#[rustfmt::skip] pub(crate) const COMMON_FILTER_TYPES : [&'static str; 8] = [
123 "OFF",
124 "LOWPASS",
125 "HIGHPAS",
126 "BANDPAS",
127 "BANDSTP",
128 "LP > HP",
129 "ZDF LP",
130 "ZDF HP",
131];
132
133impl SynthParams {
134 pub const MODULATOR_COUNT: usize = 4;
135
136 pub fn set_eq(&mut self, eq: u8) {
137 self.associated_eq = eq
138 }
139
140 pub fn mod_only2(_reader: &mut Reader) -> M8Result<Self> {
141 Ok(Self {
142 volume: 0,
143 pitch: 0,
144 fine_tune: 0,
145
146 filter_type: 0,
147 filter_cutoff: 0,
148 filter_res: 0,
149
150 amp: 0,
151 limit: LimitType::try_from(0)?,
152
153 shape: 0,
154 mixer_pan: 0,
155 mixer_dry: 0,
156 mixer_mfx: 0,
157 mixer_delay: 0,
158 mixer_reverb: 0,
159
160 associated_eq: 0xFF,
161 mods: arr![AHDEnv::default().to_mod(); 4],
162 })
163 }
164
165 pub fn mod_only3(reader: &mut Reader, mod_offset: usize) -> M8Result<Self> {
166 reader.set_pos(reader.pos() + mod_offset);
167
168 let mods = arr![Mod::from_reader(reader)?; 4];
169
170 Ok(Self {
171 volume: 0,
172 pitch: 0,
173 fine_tune: 0,
174
175 filter_type: 0,
176 filter_cutoff: 0,
177 filter_res: 0,
178
179 amp: 0,
180 limit: LimitType::try_from(0)?,
181
182 shape: 0,
183 mixer_pan: 0,
184 mixer_dry: 0,
185 mixer_mfx: 0,
186 mixer_delay: 0,
187 mixer_reverb: 0,
188 associated_eq: 0xFF,
189
190 mods,
191 })
192 }
193
194 pub fn from_reader2(
195 reader: &mut Reader,
196 volume: u8,
197 pitch: u8,
198 fine_tune: u8,
199 ) -> M8Result<Self> {
200 Ok(Self {
201 volume,
202 pitch,
203 fine_tune,
204
205 filter_type: reader.read(),
206 filter_cutoff: reader.read(),
207 filter_res: reader.read(),
208
209 amp: reader.read(),
210 limit: LimitType::try_from(reader.read())?,
211
212 shape: 0,
213 mixer_pan: reader.read(),
214 mixer_dry: reader.read(),
215 mixer_mfx: reader.read(),
216 mixer_delay: reader.read(),
217 mixer_reverb: reader.read(),
218
219 associated_eq: 0xFF,
220
221 mods: [
222 AHDEnv::from_reader2(reader)?.to_mod(),
223 AHDEnv::from_reader2(reader)?.to_mod(),
224 LFO::from_reader2(reader)?.to_mod(),
225 LFO::from_reader2(reader)?.to_mod(),
226 ],
227 })
228 }
229
230 pub fn write(&self, ver: Version, w: &mut Writer, mod_offset: usize) {
231 w.write(self.filter_type);
232 w.write(self.filter_cutoff);
233 w.write(self.filter_res);
234
235 w.write(self.amp);
236 w.write(self.limit.0);
237
238 w.write(self.mixer_pan);
239 w.write(self.mixer_dry);
240 w.write(self.mixer_mfx);
241 w.write(self.mixer_delay);
242 w.write(self.mixer_reverb);
243
244 let writer_pos = w.pos();
245 if ver.at_least(6, 6) {
246 w.skip(3);
247 w.write(self.shape);
248 }
249
250 if ver.after(&FIRMWARE_5_0_SONG_VERSION) {
251 w.seek(writer_pos + mod_offset - 1);
252 w.write(self.associated_eq);
253 }
254
255 w.seek(writer_pos + mod_offset);
256 for m in &self.mods {
257 m.write(w);
258 }
259 }
260
261 pub fn write_modes(&self, w: &mut Writer, mod_offset: usize) {
262 w.seek(w.pos() + mod_offset);
263 for m in &self.mods {
264 m.write(w);
265 }
266 }
267
268 pub fn from_reader3(
269 version: Version,
270 reader: &mut Reader,
271 volume: u8,
272 pitch: u8,
273 fine_tune: u8,
274 eq: u8,
275 mod_offset: usize,
276 ) -> M8Result<Self> {
277 let filter_type = reader.read();
278 let filter_cutoff = reader.read();
279 let filter_res = reader.read();
280
281 let amp = reader.read();
282 let limit = reader.read();
283
284 let mixer_pan = reader.read();
285 let mixer_dry = reader.read();
286 let mixer_chorus = reader.read();
287 let mixer_delay = reader.read();
288 let mixer_reverb = reader.read();
289
290 let reader_pos = reader.pos();
291
292 reader.skip(3);
294 let shape = reader.read();
295
296 let associated_eq = if version.after(&FIRMWARE_5_0_SONG_VERSION) {
297 reader.set_pos(reader_pos + mod_offset - 1);
298 reader.read()
299 } else if version.after(&FIRMWARE_4_0_SONG_VERSION) {
300 eq
301 } else {
302 0xFF
303 };
304
305 reader.set_pos(reader_pos + mod_offset);
306
307 let mods = arr![Mod::from_reader(reader)?; 4];
308
309 Ok(Self {
310 volume,
311 pitch,
312 fine_tune,
313
314 filter_type,
315 filter_cutoff,
316 filter_res,
317
318 amp,
319 limit: LimitType::try_from(limit)?,
320
321 mixer_pan,
322 mixer_dry,
323 mixer_mfx: mixer_chorus,
324 mixer_delay,
325 mixer_reverb,
326
327 associated_eq,
328 shape,
329
330 mods,
331 })
332 }
333}