m8_file_parser/instruments/
midi.rs1use crate::instruments::common::*;
2use crate::reader::*;
3use crate::version::*;
4use crate::writer::Writer;
5
6use arr_macro::arr;
7
8use super::dests;
9use super::params;
10use super::CommandPack;
11
12#[derive(PartialEq, Debug, Clone, Copy)]
13pub struct ControlChange {
14 pub number: u8,
16
17 pub value: u8,
19}
20
21impl ControlChange {
22 pub fn write(self, writer: &mut Writer) {
23 writer.write(self.number);
24 writer.write(self.value);
25 }
26
27 pub fn from_reader(reader: &mut Reader) -> M8Result<Self> {
28 Ok(Self {
29 number: reader.read(),
30 value: reader.read(),
31 })
32 }
33}
34
35#[rustfmt::skip] const MIDI_OUT_COMMAND_NAMES : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT - 2] = [
37 "VOL",
38 "PIT",
39 "MPG",
40 "MPB",
41 "ADD",
42 "CHD",
43 "CCA",
44 "CCB",
45 "CCC",
46 "CCD",
47 "CCE",
48 "CCF",
49 "CCG",
50 "CCH",
51 "CCI",
52 "CCJ",
53];
54
55#[rustfmt::skip] const DESTINATIONS : [&'static str; 15] = [
57 dests::OFF,
58 params::CCA,
59 params::CCB,
60 params::CCC,
61 params::CCD,
62 "CCE",
63 "CCF",
64 "CCG",
65 "CCH",
66 "CCI",
67 "CCJ",
68 dests::MOD_AMT,
69 dests::MOD_RATE,
70 dests::MOD_BOTH,
71 dests::MOD_BINV,
72];
73
74#[rustfmt::skip] pub(crate) const PORTS : [&'static str; 4] = [
76 "MIDI + USB",
77 "MIDI",
78 "USB",
79 "INTERNAL"
80];
81
82#[derive(PartialEq, Debug, Clone)]
83pub struct MIDIOut {
84 pub number: u8,
85 pub name: String,
86 pub transpose: bool,
87 pub table_tick: u8,
88
89 pub port: u8,
90 pub channel: u8,
91 pub bank_select: u8,
92 pub program_change: u8,
93 pub custom_cc: [ControlChange; 10],
94
95 pub mods: SynthParams,
96}
97
98impl MIDIOut {
99 const MOD_OFFSET: usize = 21;
100
101 pub fn port_names(_ver: Version) -> &'static [&'static str] {
102 &PORTS
103 }
104
105 pub fn command_name(&self, _ver: Version) -> &'static [&'static str] {
106 &MIDI_OUT_COMMAND_NAMES
107 }
108
109 pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
110 &DESTINATIONS
111 }
112
113 pub fn human_readable_port(&self) -> &'static str {
114 PORTS[self.port as usize]
115 }
116
117 pub fn write(&self, _ver: Version, w: &mut Writer) {
118 w.write_string(&self.name, 12);
119 w.write(if self.transpose { 1 } else { 0 });
120 w.write(self.table_tick);
121 w.write(self.port);
122 w.write(self.channel);
123 w.write(self.bank_select);
124 w.write(self.program_change);
125
126 w.skip(3);
127
128 for cc in self.custom_cc {
129 cc.write(w);
130 }
131
132 self.mods.write_modes(w, MIDIOut::MOD_OFFSET)
133 }
134
135 pub fn from_reader(
136 _ver: Version,
137 reader: &mut Reader,
138 number: u8,
139 version: Version,
140 ) -> M8Result<Self> {
141 let name = reader.read_string(12);
142 let transpose = reader.read_bool();
143 let table_tick = reader.read();
144
145 let port = reader.read();
146 let channel = reader.read();
147 let bank_select = reader.read();
148 let program_change = reader.read();
149 reader.read_bytes(3); let custom_cc = arr![ControlChange::from_reader(reader)?; 10];
151 let mods = if version.at_least(3, 0) {
152 SynthParams::mod_only3(reader, MIDIOut::MOD_OFFSET)?
153 } else {
154 SynthParams::mod_only2(reader)?
155 };
156
157 Ok(MIDIOut {
158 number,
159 name,
160 transpose,
161 table_tick,
162
163 port,
164 channel,
165 bank_select,
166 program_change,
167 custom_cc,
168 mods,
169 })
170 }
171}