1use crate::instruments::common::*;
2use crate::reader::*;
3use crate::version::*;
4use crate::writer::Writer;
5use crate::SEND_COMMAND_NAMES;
6use crate::SEND_COMMAND_NAMES_6_2;
7use array_concat::concat_arrays;
8use num_enum::IntoPrimitive;
9use num_enum::TryFromPrimitive;
10
11use super::dests;
12use super::CommandPack;
13
14#[repr(u8)]
16#[allow(non_camel_case_types)]
17#[derive(IntoPrimitive, TryFromPrimitive, PartialEq, Copy, Clone, Default, Debug)]
18pub enum WavShape {
19 #[default]
20 PULSE12,
21 PULSE25,
22 PULSE50,
23 PULSE75,
24 SAW,
25 TRIANGLE,
26 SINE,
27 NOISE_PITCHED,
28 NOISE,
29 WT_CRUSH,
30 WT_FOLDING,
31 WT_FREQ,
32 WT_FUZZY,
33 WT_GHOST,
34 WT_GRAPHIC,
35 WT_LFOPLAY,
36 WT_LIQUID,
37 WT_MORPHING,
38 WT_MYSTIC,
39 WT_STICKY,
40 WT_TIDAL,
41 WT_TIDY,
42 WT_TUBE,
43 WT_UMBRELLA,
44 WT_UNWIND,
45 WT_VIRAL,
46 WT_WAVES,
47 WT_DRIP,
48 WT_FROGGY,
49 WT_INSONIC,
50 WT_RADIUS,
51 WT_SCRATCH,
52 WT_SMOOTH,
53 WT_WOBBLE,
54 WT_ASIMMTRY,
55 WT_BLEEN,
56 WT_FRACTAL,
57 WT_GENTLE,
58 WT_HARMONIC,
59 WT_HYPNOTIC,
60 WT_ITERATIV,
61 WT_MICROWAV,
62 WT_PLAITS01,
63 WT_PLAITS02,
64 WT_RISEFALL,
65 WT_TONAL,
66 WT_TWINE,
67 WT_ALIEN,
68 WT_CYBERNET,
69 WT_DISORDR,
70 WT_FORMANT,
71 WT_HYPER,
72 WT_JAGGED,
73 WT_MIXED,
74 WT_MULTIPLY,
75 WT_NOWHERE,
76 WT_PINBALL,
77 WT_RINGS,
78 WT_SHIMMER,
79 WT_SPECTRAL,
80 WT_SPOOKY,
81 WT_TRANSFRM,
82 WT_TWISTED,
83 WT_VOCAL,
84 WT_WASHED,
85 WT_WONDER,
86 WT_WOWEE,
87 WT_ZAP,
88 WT_BRAIDS,
89 WT_VOXSYNTH,
90}
91
92#[derive(PartialEq, Debug, Clone)]
93pub struct WavSynth {
94 pub number: u8,
95 pub name: String,
96 pub transpose: bool,
97 pub table_tick: u8,
98 pub synth_params: SynthParams,
99
100 pub shape: WavShape,
101 pub size: u8,
102 pub mult: u8,
103 pub warp: u8,
104 pub scan: u8,
105}
106
107#[rustfmt::skip] const WAVSYNTH_COMMAND_NAMES_BASE : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT - 3] = [
109 "VOL",
110 "PIT",
111 "FIN",
112 "OSC",
113 "SIZ",
114 "MUL",
115 "WRP",
116 "MIR",
117 "FIL",
118 "CUT",
119 "RES",
120 "AMP",
121 "LIM",
122 "PAN",
123 "DRY"
124];
125
126#[rustfmt::skip] const WAVSYNTH_COMMAND_NAMES_EXTRA : [&'static str; 2] = [
128 "SNC",
129 "ERR"
130];
131
132const WAVSYNTH_COMMAND_NAMES : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] =
133 concat_arrays!(WAVSYNTH_COMMAND_NAMES_BASE, SEND_COMMAND_NAMES, WAVSYNTH_COMMAND_NAMES_EXTRA);
134
135const WAVSYNTH_COMMAND_NAMES_6_2 : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] =
136 concat_arrays!(WAVSYNTH_COMMAND_NAMES_BASE, SEND_COMMAND_NAMES_6_2, WAVSYNTH_COMMAND_NAMES_EXTRA);
137
138#[rustfmt::skip] const DESTINATIONS : [&'static str; 15] = [
140 dests::OFF,
141 dests::VOLUME,
142 dests::PITCH,
143
144 "SIZE",
145 "MULT",
146 "WARP",
147 "SCAN",
148 dests::CUTOFF,
149 dests::RES,
150 dests::AMP,
151 dests::PAN,
152 dests::MOD_AMT,
153 dests::MOD_RATE,
154 dests::MOD_BOTH,
155 dests::MOD_BINV,
156];
157
158#[rustfmt::skip] const WAVSYNTH_FILTER_TYPES : [&'static str; 12] = [
160 "OFF",
161 "LOWPASS",
162 "HIGHPAS",
163 "BANDPAS",
164 "BANDSTP",
165 "LP > HP",
166 "ZDF LP",
167 "ZDF HP",
168 "WAV LP",
169 "WAV HP",
170 "WAV BP",
171 "WAV BS"
172];
173
174impl WavSynth {
175 pub const MOD_OFFSET: usize = 30;
176
177 pub fn command_name(&self, ver: Version) -> &'static [&'static str] {
178 if ver.at_least(6, 1) {
179 &WAVSYNTH_COMMAND_NAMES_6_2
180 } else {
181 &WAVSYNTH_COMMAND_NAMES
182 }
183 }
184
185 pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
186 &DESTINATIONS
187 }
188
189 pub fn filter_types(&self, _ver: Version) -> &'static [&'static str] {
191 &WAVSYNTH_FILTER_TYPES
192 }
193
194 pub fn human_readable_filter(&self) -> &'static str {
195 WAVSYNTH_FILTER_TYPES[self.synth_params.filter_type as usize]
196 }
197
198 pub fn write(&self, ver: Version, w: &mut Writer) {
199 w.write_string(&self.name[..], 12);
200 w.write(TranspEq::from(ver, self.transpose, self.synth_params.associated_eq).into());
201 w.write(self.table_tick);
202 w.write(self.synth_params.volume);
203 w.write(self.synth_params.pitch);
204 w.write(self.synth_params.fine_tune);
205
206 w.write(self.shape.into());
207 w.write(self.size);
208 w.write(self.mult);
209 w.write(self.warp);
210 w.write(self.scan);
211 self.synth_params.write(ver, w, WavSynth::MOD_OFFSET);
212 }
213
214 pub fn from_reader(
215 ver: Version,
216 reader: &mut Reader,
217 number: u8,
218 version: Version,
219 ) -> M8Result<Self> {
220 let name = reader.read_string(12);
221 let transp_eq = TranspEq::from_version(ver, reader.read());
222 let table_tick = reader.read();
223 let volume = reader.read();
224 let pitch = reader.read();
225 let fine_tune = reader.read();
226
227 let shape = reader.read();
228 let size = reader.read();
229 let mult = reader.read();
230 let warp = reader.read();
231 let scan = reader.read();
232 let synth_params = if version.at_least(3, 0) {
233 SynthParams::from_reader3(
234 ver,
235 reader,
236 volume,
237 pitch,
238 fine_tune,
239 transp_eq.eq,
240 WavSynth::MOD_OFFSET,
241 )?
242 } else {
243 SynthParams::from_reader2(reader, volume, pitch, fine_tune)?
244 };
245
246 Ok(WavSynth {
247 number,
248 name,
249 transpose: transp_eq.transpose,
250 table_tick,
251 synth_params,
252
253 shape: shape
254 .try_into()
255 .map_err(|_| ParseError(format!("Invalid wavsynth shape")))?,
256 size,
257 mult,
258 warp,
259 scan,
260 })
261 }
262}