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 constats 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 constats 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 constats 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    pub fn human_readable_filter(&self) -> &'static str {
175        WAVSYNTH_FILTER_TYPES[self.synth_params.filter_type as usize]
176    }
177
178    pub fn write(&self, ver: Version, w: &mut Writer) {
179        w.write_string(&self.name[..], 12);
180        w.write(TranspEq::from(ver, self.transpose, self.synth_params.associated_eq).into());
181        w.write(self.table_tick);
182        w.write(self.synth_params.volume);
183        w.write(self.synth_params.pitch);
184        w.write(self.synth_params.fine_tune);
185
186        w.write(self.shape.into());
187        w.write(self.size);
188        w.write(self.mult);
189        w.write(self.warp);
190        w.write(self.scan);
191        self.synth_params.write(ver, w, WavSynth::MOD_OFFSET);
192    }
193
194    pub fn from_reader(
195        ver: Version,
196        reader: &mut Reader,
197        number: u8,
198        version: Version,
199    ) -> M8Result<Self> {
200        let name = reader.read_string(12);
201        let transp_eq = TranspEq::from_version(ver, reader.read());
202        let table_tick = reader.read();
203        let volume = reader.read();
204        let pitch = reader.read();
205        let fine_tune = reader.read();
206
207        let shape = reader.read();
208        let size = reader.read();
209        let mult = reader.read();
210        let warp = reader.read();
211        let scan = reader.read();
212        let synth_params = if version.at_least(3, 0) {
213            SynthParams::from_reader3(
214                ver,
215                reader,
216                volume,
217                pitch,
218                fine_tune,
219                transp_eq.eq,
220                WavSynth::MOD_OFFSET,
221            )?
222        } else {
223            SynthParams::from_reader2(reader, volume, pitch, fine_tune)?
224        };
225
226        Ok(WavSynth {
227            number,
228            name,
229            transpose: transp_eq.transpose,
230            table_tick,
231            synth_params,
232
233            shape: shape
234                .try_into()
235                .map_err(|_| ParseError(format!("Invalid wavsynth shape")))?,
236            size,
237            mult,
238            warp,
239            scan,
240        })
241    }
242}