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