m8_file_parser/instruments/
wavsynth.rs

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/// Wavsynth wave shape
12#[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] // Keep constants with important order vertical for maintenance
105const WAVSYNTH_COMMAND_NAMES : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] = [
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    "SNC",
127    "ERR"
128];
129
130#[rustfmt::skip] // Keep constants with important order vertical for maintenance
131const DESTINATIONS : [&'static str; 15] = [
132    dests::OFF,
133    dests::VOLUME,
134    dests::PITCH,
135
136    "SIZE",
137    "MULT",
138    "WARP",
139    "SCAN",
140    dests::CUTOFF,
141    dests::RES,
142    dests::AMP,
143    dests::PAN,
144    dests::MOD_AMT,
145    dests::MOD_RATE,
146    dests::MOD_BOTH,
147    dests::MOD_BINV,
148];
149
150#[rustfmt::skip] // Keep constants with important order vertical for maintenance
151const WAVSYNTH_FILTER_TYPES : [&'static str; 12] = [
152    "OFF",
153    "LOWPASS",
154    "HIGHPAS",
155    "BANDPAS",
156    "BANDSTP",
157    "LP > HP",
158    "ZDF LP",
159    "ZDF HP",
160    "WAV LP",
161    "WAV HP",
162    "WAV BP",
163    "WAV BS"
164];
165
166impl WavSynth {
167    pub const MOD_OFFSET: usize = 30;
168
169    pub fn command_name(&self, _ver: Version) -> &'static [&'static str] {
170        &WAVSYNTH_COMMAND_NAMES
171    }
172
173    pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
174        &DESTINATIONS
175    }
176
177    /// List of all the applyable filter types for the instrument
178    pub fn filter_types(&self, _ver: Version) -> &'static [&'static str] {
179        &WAVSYNTH_FILTER_TYPES
180    }
181
182    pub fn human_readable_filter(&self) -> &'static str {
183        WAVSYNTH_FILTER_TYPES[self.synth_params.filter_type as usize]
184    }
185
186    pub fn write(&self, ver: Version, w: &mut Writer) {
187        w.write_string(&self.name[..], 12);
188        w.write(TranspEq::from(ver, self.transpose, self.synth_params.associated_eq).into());
189        w.write(self.table_tick);
190        w.write(self.synth_params.volume);
191        w.write(self.synth_params.pitch);
192        w.write(self.synth_params.fine_tune);
193
194        w.write(self.shape.into());
195        w.write(self.size);
196        w.write(self.mult);
197        w.write(self.warp);
198        w.write(self.scan);
199        self.synth_params.write(ver, w, WavSynth::MOD_OFFSET);
200    }
201
202    pub fn from_reader(
203        ver: Version,
204        reader: &mut Reader,
205        number: u8,
206        version: Version,
207    ) -> M8Result<Self> {
208        let name = reader.read_string(12);
209        let transp_eq = TranspEq::from_version(ver, reader.read());
210        let table_tick = reader.read();
211        let volume = reader.read();
212        let pitch = reader.read();
213        let fine_tune = reader.read();
214
215        let shape = reader.read();
216        let size = reader.read();
217        let mult = reader.read();
218        let warp = reader.read();
219        let scan = reader.read();
220        let synth_params = if version.at_least(3, 0) {
221            SynthParams::from_reader3(
222                ver,
223                reader,
224                volume,
225                pitch,
226                fine_tune,
227                transp_eq.eq,
228                WavSynth::MOD_OFFSET,
229            )?
230        } else {
231            SynthParams::from_reader2(reader, volume, pitch, fine_tune)?
232        };
233
234        Ok(WavSynth {
235            number,
236            name,
237            transpose: transp_eq.transpose,
238            table_tick,
239            synth_params,
240
241            shape: shape
242                .try_into()
243                .map_err(|_| ParseError(format!("Invalid wavsynth shape")))?,
244            size,
245            mult,
246            warp,
247            scan,
248        })
249    }
250}