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