m8_files/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] = [
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] // Keep constants with important order vertical for maintenance
128const 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] // Keep constants with important order vertical for maintenance
148const 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    /// List of all the applyable filter types for the instrument
175    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}