midi_msg/system_exclusive/
global_parameter.rs1use crate::parse_error::*;
2use crate::util::*;
3use alloc::vec;
4use alloc::vec::Vec;
5#[allow(unused_imports)]
6use micromath::F32Ext;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct GlobalParameterControl {
17 pub slot_paths: Vec<SlotPath>,
21 pub param_id_width: u8,
24 pub value_width: u8,
27 pub params: Vec<GlobalParameter>,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum ReverbType {
34 SmallRoom = 0,
35 MediumRoom = 1,
36 LargeRoom = 2,
37 MediumHall = 3,
38 LargeHall = 4,
39 Plate = 8,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum ChorusType {
45 Chorus1 = 0,
46 Chorus2 = 1,
47 Chorus3 = 2,
48 Chorus4 = 3,
49 FBChorus = 4,
50 Flanger = 5,
51}
52
53impl GlobalParameterControl {
54 pub fn reverb(reverb_type: Option<ReverbType>, reverb_time: Option<f32>) -> Self {
59 let mut params = vec![];
60
61 if let Some(reverb_type) = reverb_type {
62 params.push(GlobalParameter {
63 id: vec![0],
64 value: vec![reverb_type as u8],
65 });
66 }
67 if let Some(reverb_time) = reverb_time {
68 params.push(GlobalParameter {
69 id: vec![1],
70 value: vec![to_u7((F32Ext::ln(reverb_time) / 0.025 + 40.0) as u8)],
71 });
72 }
73 Self {
74 slot_paths: vec![SlotPath::Reverb],
75 param_id_width: 1,
76 value_width: 1,
77 params,
78 }
79 }
80
81 pub fn chorus(
91 chorus_type: Option<ChorusType>,
92 mod_rate: Option<f32>,
93 mod_depth: Option<f32>,
94 feedback: Option<f32>,
95 send_to_reverb: Option<f32>,
96 ) -> Self {
97 let mut params = vec![];
98
99 if let Some(chorus_type) = chorus_type {
100 params.push(GlobalParameter {
101 id: vec![0],
102 value: vec![chorus_type as u8],
103 });
104 }
105
106 if let Some(mod_rate) = mod_rate {
107 params.push(GlobalParameter {
108 id: vec![1],
109 value: vec![to_u7((mod_rate / 0.122) as u8)],
110 });
111 }
112
113 if let Some(mod_depth) = mod_depth {
114 params.push(GlobalParameter {
115 id: vec![2],
116 value: vec![to_u7(((mod_depth * 3.2) - 1.0) as u8)],
117 });
118 }
119
120 if let Some(feedback) = feedback {
121 params.push(GlobalParameter {
122 id: vec![3],
123 value: vec![to_u7((feedback / 0.763) as u8)],
124 });
125 }
126
127 if let Some(send_to_reverb) = send_to_reverb {
128 params.push(GlobalParameter {
129 id: vec![4],
130 value: vec![to_u7((send_to_reverb / 0.787) as u8)],
131 });
132 }
133
134 Self {
135 slot_paths: vec![SlotPath::Chorus],
136 param_id_width: 1,
137 value_width: 1,
138 params,
139 }
140 }
141
142 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
143 v.push(self.slot_paths.len().min(127) as u8);
144 push_u7(self.param_id_width, v);
145 push_u7(self.value_width, v);
146 for (i, sp) in self.slot_paths.iter().enumerate() {
147 if i > 127 {
148 break;
149 }
150 sp.extend_midi(v);
151 }
152 for p in self.params.iter() {
153 p.extend_midi_with_limits(v, self.param_id_width.max(1), self.value_width.max(1));
154 }
155 }
156
157 #[allow(dead_code)]
158 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
159 Err(ParseError::NotImplemented("GlobalParameterControl"))
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166pub enum SlotPath {
167 Reverb,
168 Chorus,
169 Unregistered(u8, u8),
171}
172
173impl SlotPath {
174 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
175 match self {
176 Self::Reverb => {
177 v.push(1);
178 v.push(1);
179 }
180 Self::Chorus => {
181 v.push(1);
182 v.push(2);
183 }
184 Self::Unregistered(a, b) => {
185 push_u7(*a, v); push_u7(*b, v);
187 }
188 }
189 }
190
191 #[allow(dead_code)]
192 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
193 Err(ParseError::NotImplemented("SlotPath"))
194 }
195}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
199pub struct GlobalParameter {
200 pub id: Vec<u8>,
201 pub value: Vec<u8>,
202}
203
204impl GlobalParameter {
205 pub(crate) fn extend_midi_with_limits(
206 &self,
207 v: &mut Vec<u8>,
208 param_id_width: u8,
209 value_width: u8,
210 ) {
211 for i in 0..param_id_width {
212 if let Some(x) = self.id.get(i as usize) {
214 push_u7(*x, v);
215 } else {
216 v.push(0);
217 }
218 }
219 for i in (0..value_width).rev() {
220 if let Some(x) = self.value.get(i as usize) {
222 push_u7(*x, v);
223 } else {
224 v.push(0);
225 }
226 }
227 }
228
229 #[allow(dead_code)]
230 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
231 Err(ParseError::NotImplemented("GlobalParameter"))
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use crate::*;
238 use alloc::vec;
239
240 #[test]
241 fn serialize_global_parameter() {
242 assert_eq!(
243 MidiMsg::SystemExclusive {
244 msg: SystemExclusiveMsg::UniversalRealTime {
245 device: DeviceID::AllCall,
246 msg: UniversalRealTimeMsg::GlobalParameterControl(GlobalParameterControl {
247 slot_paths: vec![
248 SlotPath::Unregistered(1, 0x47),
249 SlotPath::Unregistered(2, 3)
250 ],
251 param_id_width: 1,
252 value_width: 2,
253 params: vec![
254 GlobalParameter {
255 id: vec![4],
256 value: vec![5, 6, 7] },
258 GlobalParameter {
259 id: vec![4],
260 value: vec![1] }
262 ]
263 }),
264 },
265 }
266 .to_midi(),
267 vec![
268 0xF0, 0x7F, 0x7F, 0x4, 0x5, 0x2, 1, 2, 1, 0x47, 2, 3, 4, 6, 5, 4, 0, 1, 0xF7
283 ]
284 );
285
286 assert_eq!(
287 MidiMsg::SystemExclusive {
288 msg: SystemExclusiveMsg::UniversalRealTime {
289 device: DeviceID::AllCall,
290 msg: UniversalRealTimeMsg::GlobalParameterControl(
291 GlobalParameterControl::chorus(
292 Some(ChorusType::Flanger),
293 Some(1.1),
294 None,
295 None,
296 Some(100.0)
297 )
298 ),
299 },
300 }
301 .to_midi(),
302 vec![
303 0xF0, 0x7F, 0x7F, 0x4, 0x5, 0x1, 0x1, 0x1, 0x1, 0x2, 0x0, 0x5, 0x1, 0x9, 0x4, 0x7F, 0xF7
316 ]
317 );
318 }
319}