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