m8_files/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] 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 command_name(&self, _ver: Version) -> &'static [&'static str] {
102 &MIDI_OUT_COMMAND_NAMES
103 }
104
105 pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
106 &DESTINATIONS
107 }
108
109 pub fn human_readable_port(&self) -> &'static str {
110 PORTS[self.port as usize]
111 }
112
113 pub fn write(&self, _ver: Version, w: &mut Writer) {
114 w.write_string(&self.name, 12);
115 w.write(if self.transpose { 1 } else { 0 });
116 w.write(self.table_tick);
117 w.write(self.port);
118 w.write(self.channel);
119 w.write(self.bank_select);
120 w.write(self.program_change);
121
122 w.skip(3);
123
124 for cc in self.custom_cc {
125 cc.write(w);
126 }
127
128 self.mods.write_modes(w, MIDIOut::MOD_OFFSET)
129 }
130
131 pub fn from_reader(
132 _ver: Version,
133 reader: &mut Reader,
134 number: u8,
135 version: Version,
136 ) -> M8Result<Self> {
137 let name = reader.read_string(12);
138 let transpose = reader.read_bool();
139 let table_tick = reader.read();
140
141 let port = reader.read();
142 let channel = reader.read();
143 let bank_select = reader.read();
144 let program_change = reader.read();
145 reader.read_bytes(3); let custom_cc = arr![ControlChange::from_reader(reader)?; 10];
147 let mods = if version.at_least(3, 0) {
148 SynthParams::mod_only3(reader, MIDIOut::MOD_OFFSET)?
149 } else {
150 SynthParams::mod_only2(reader)?
151 };
152
153 Ok(MIDIOut {
154 number,
155 name,
156 transpose,
157 table_tick,
158
159 port,
160 channel,
161 bank_select,
162 program_change,
163 custom_cc,
164 mods,
165 })
166 }
167}