m8_file_parser/instruments/
hypersynth.rs

1use super::common::SynthParams;
2use super::common::TranspEq;
3use super::common::COMMON_FILTER_TYPES;
4use super::dests;
5use super::CommandPack;
6use super::Version;
7use crate::reader::*;
8use crate::writer::Writer;
9use crate::SEND_COMMAND_NAMES;
10use crate::SEND_COMMAND_NAMES_6_2;
11
12use arr_macro::arr;
13use array_concat::concat_arrays;
14
15#[derive(PartialEq, Debug, Clone)]
16pub struct HyperSynth {
17    pub number: u8,
18    pub name: String,
19    pub transpose: bool,
20    pub table_tick: u8,
21    pub synth_params: SynthParams,
22
23    pub scale: u8,
24    pub default_chord: [u8; 7],
25    pub shift: u8,
26    pub swarm: u8,
27    pub width: u8,
28    pub subosc: u8,
29
30    pub chords: [[u8; 6]; 0x10],
31}
32
33#[rustfmt::skip] // Keep constants with important order vertical for maintenance
34const HYPERSYNTH_COMMAND_NAMES_BASE : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT - 3] = [
35    "VOL",
36    "PIT",
37    "FIN",
38    "CRD",
39    "SHF",
40    "SWM",
41    "WID",
42    "SUB",
43    "FLT",
44    "CUT",
45    "RES",
46    "AMP",
47    "LIM",
48    "PAN",
49    "DRY"
50];
51    
52
53#[rustfmt::skip] // Keep constants with important order vertical for maintenance
54const HYPERSYNTH_COMMAND_NAMES : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] =
55    concat_arrays!(HYPERSYNTH_COMMAND_NAMES_BASE, SEND_COMMAND_NAMES, ["CVO", "SNC"]);
56
57#[rustfmt::skip] // Keep constants with important order vertical for maintenance
58const HYPERSYNTH_COMMAND_NAMES_BASE_6 : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT - 3] = [
59    "VOL",
60    "PIT",
61    "FIN",
62    "CRD",
63    "CVO",
64    "SWM",
65    "WID",
66    "SUB",
67    "FLT",
68    "CUT",
69    "RES",
70    "AMP",
71    "LIM",
72    "PAN",
73    "DRY"
74];
75    
76
77#[rustfmt::skip] // Keep constants with important order vertical for maintenance
78const HYPERSYNTH_COMMAND_NAMES_6 : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] =
79    concat_arrays!(HYPERSYNTH_COMMAND_NAMES_BASE_6, SEND_COMMAND_NAMES, ["SNC", "ERR"]);
80
81#[rustfmt::skip] // Keep constants with important order vertical for maintenance
82const HYPERSYNTH_COMMAND_NAMES_6_2 : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] =
83    concat_arrays!(HYPERSYNTH_COMMAND_NAMES_BASE_6, SEND_COMMAND_NAMES_6_2, ["SNC", "ERR"]);
84
85#[rustfmt::skip] // Keep constants with important order vertical for maintenance
86const DESTINATIONS : [&'static str; 15] = [
87    dests::OFF,
88    dests::VOLUME,
89    dests::PITCH,
90
91    "SHIFT",
92    "SWARM",
93    "WIDTH",
94    "SUBOSC",
95    dests::CUTOFF,
96    dests::RES,
97    dests::AMP,
98    dests::PAN,
99    dests::MOD_AMT,
100    dests::MOD_RATE,
101    dests::MOD_BOTH,
102    dests::MOD_BINV,
103];
104
105impl HyperSynth {
106    const MOD_OFFSET: usize = 23;
107
108    pub fn command_name(&self, ver: Version) -> &'static [&'static str] {
109        if ver.at_least(6, 1) {
110            &HYPERSYNTH_COMMAND_NAMES_6_2
111        } else if ver.at_least(6, 0) {
112            &HYPERSYNTH_COMMAND_NAMES_6
113        } else {
114            &HYPERSYNTH_COMMAND_NAMES
115        }
116    }
117
118    pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
119        &DESTINATIONS
120    }
121
122    /// List of all the applyable filter types for the instrument
123    pub fn filter_types(&self, _ver: Version) -> &'static [&'static str] {
124        &super::common::COMMON_FILTER_TYPES
125    }
126
127    pub fn human_readable_filter(&self) -> &'static str {
128        COMMON_FILTER_TYPES[self.synth_params.filter_type as usize]
129    }
130
131    pub fn write(&self, ver: Version, w: &mut Writer) {
132        w.write_string(&self.name, 12);
133        w.write(TranspEq::from(ver, self.transpose, self.synth_params.associated_eq).into());
134        w.write(self.table_tick);
135        w.write(self.synth_params.volume);
136        w.write(self.synth_params.pitch);
137        w.write(self.synth_params.fine_tune);
138
139        for c in self.default_chord {
140            w.write(c);
141        }
142
143        w.write(self.scale);
144        w.write(self.shift);
145        w.write(self.swarm);
146        w.write(self.width);
147        w.write(self.subosc);
148
149        self.synth_params.write(ver, w, HyperSynth::MOD_OFFSET);
150
151        for chd in self.chords {
152            w.write(0xFF);
153            for k in chd {
154                w.write(k);
155            }
156        }
157    }
158
159    fn load_chord(reader: &mut Reader) -> [u8; 6] {
160        // padding
161        let _ = reader.read();
162        arr![reader.read(); 6]
163    }
164
165    pub fn from_reader(ver: Version, reader: &mut Reader, number: u8) -> M8Result<Self> {
166        let name = reader.read_string(12);
167        let transp_eq = TranspEq::from_version(ver, reader.read());
168        let table_tick = reader.read();
169        let volume = reader.read();
170        let pitch = reader.read();
171        let fine_tune = reader.read();
172
173        let default_chord = arr![reader.read(); 7];
174        let scale = reader.read();
175        let shift = reader.read();
176        let swarm = reader.read();
177        let width = reader.read();
178        let subosc = reader.read();
179        let synth_params = SynthParams::from_reader3(
180            ver,
181            reader,
182            volume,
183            pitch,
184            fine_tune,
185            transp_eq.eq,
186            HyperSynth::MOD_OFFSET,
187        )?;
188
189        let chords = arr![HyperSynth::load_chord(reader); 0x10];
190
191        Ok(HyperSynth {
192            number,
193            name,
194            transpose: transp_eq.transpose,
195            table_tick,
196            synth_params,
197
198            scale,
199            default_chord,
200            shift,
201            swarm,
202            width,
203            subosc,
204            chords,
205        })
206    }
207}