1use crate::parse_error::*;
2use crate::util::*;
3use alloc::vec::Vec;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct TuningNoteChange {
9 pub tuning_program_num: u8,
11 pub tuning_bank_num: Option<u8>,
13 pub tunings: Vec<(u8, Option<Tuning>)>,
16}
17
18impl TuningNoteChange {
19 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
20 push_u7(self.tuning_program_num, v);
22 push_u7(self.tunings.len() as u8, v);
23 for (note, tuning) in self.tunings.iter() {
24 push_u7(*note, v);
25 if let Some(tuning) = tuning {
26 tuning.extend_midi(v);
27 } else {
28 v.push(0x7F);
30 v.push(0x7F);
31 v.push(0x7F);
32 }
33 }
34 }
35
36 #[allow(dead_code)]
37 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
38 Err(ParseError::NotImplemented("TuningNoteChange"))
39 }
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct KeyBasedTuningDump {
46 pub tuning_program_num: u8,
48 pub tuning_bank_num: Option<u8>,
50 pub name: [u8; 16],
52 pub tunings: Vec<Option<Tuning>>,
57}
58
59impl KeyBasedTuningDump {
60 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
61 if let Some(bank_num) = self.tuning_bank_num {
62 v.push(to_u7(bank_num))
63 }
64 push_u7(self.tuning_program_num, v);
65 for ch in self.name.iter() {
66 v.push(*ch);
67 }
68 let mut i = 0;
69 loop {
70 if i >= 128 {
71 break;
72 }
73 if let Some(tuning) = self.tunings.get(i) {
74 if let Some(tuning) = tuning {
75 tuning.extend_midi(v);
76 } else {
77 v.push(0x7F);
79 v.push(0x7F);
80 v.push(0x7F);
81 }
82 } else {
83 push_u7(i as u8, v);
85 v.push(0);
86 v.push(0);
87 }
88 i += 1;
89 }
90 v.push(0); }
92
93 #[allow(dead_code)]
94 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
95 Err(ParseError::NotImplemented("KeyBasedTuningDump"))
96 }
97}
98
99#[derive(Debug, Copy, Clone, PartialEq, Eq)]
101pub struct Tuning {
102 pub semitone: u8,
104 pub fraction: u16,
107}
108
109impl Tuning {
110 pub fn from_freq(freq: f32) -> Self {
111 if freq < 8.17358 {
112 Self {
113 semitone: 0,
114 fraction: 0,
115 }
116 } else if freq > 13289.73 {
117 Self {
118 semitone: 127,
119 fraction: 16383,
120 }
121 } else {
122 let (semitone, c) = freq_to_midi_note_cents(freq);
123 Self {
124 semitone,
125 fraction: cents_to_u14(c).min(0x3FFE),
126 }
127 }
128 }
129
130 fn extend_midi(&self, v: &mut Vec<u8>) {
131 push_u7(self.semitone, v);
132 let [msb, lsb] = to_u14(self.fraction);
133 v.push(msb); v.push(lsb);
135 }
136}
137
138#[derive(Debug, Copy, Clone, PartialEq, Eq)]
143pub struct ScaleTuningDump1Byte {
144 pub tuning_program_num: u8,
146 pub tuning_bank_num: u8,
148 pub name: [u8; 16],
150 pub tuning: [i8; 12],
154}
155
156impl ScaleTuningDump1Byte {
157 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
158 push_u7(self.tuning_bank_num, v);
159 push_u7(self.tuning_program_num, v);
160 for ch in self.name.iter() {
161 v.push(*ch);
162 }
163
164 for t in self.tuning.iter() {
165 v.push(i_to_u7(*t));
166 }
167
168 v.push(0); }
170
171 #[allow(dead_code)]
172 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
173 Err(ParseError::NotImplemented("ScaleTuningDump1Byte"))
174 }
175}
176
177#[derive(Debug, Copy, Clone, PartialEq, Eq)]
182pub struct ScaleTuningDump2Byte {
183 pub tuning_program_num: u8,
185 pub tuning_bank_num: u8,
187 pub name: [u8; 16],
189 pub tuning: [i16; 12],
193}
194
195impl ScaleTuningDump2Byte {
196 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
197 push_u7(self.tuning_bank_num, v);
198 push_u7(self.tuning_program_num, v);
199 for ch in self.name.iter() {
200 v.push(*ch);
201 }
202
203 for t in self.tuning.iter() {
204 let [msb, lsb] = i_to_u14(*t);
205 v.push(lsb);
206 v.push(msb);
207 }
208
209 v.push(0); }
211
212 #[allow(dead_code)]
213 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
214 Err(ParseError::NotImplemented("ScaleTuningDump2Byte"))
215 }
216}
217
218#[derive(Debug, Copy, Clone, PartialEq, Eq)]
223pub struct ScaleTuning1Byte {
224 pub channels: ChannelBitMap,
225 pub tuning: [i8; 12],
229}
230
231impl ScaleTuning1Byte {
232 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
233 self.channels.extend_midi(v);
234 for t in self.tuning.iter() {
235 v.push(i_to_u7(*t));
236 }
237 }
238
239 #[allow(dead_code)]
240 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
241 Err(ParseError::NotImplemented("ScaleTuning1Byte"))
242 }
243}
244
245#[derive(Debug, Copy, Clone, PartialEq, Eq)]
250pub struct ScaleTuning2Byte {
251 pub channels: ChannelBitMap,
252 pub tuning: [i16; 12],
256}
257
258impl ScaleTuning2Byte {
259 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
260 self.channels.extend_midi(v);
261 for t in self.tuning.iter() {
262 let [msb, lsb] = i_to_u14(*t);
263 v.push(lsb);
264 v.push(msb);
265 }
266 }
267
268 #[allow(dead_code)]
269 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
270 Err(ParseError::NotImplemented("ScaleTuning2Byte"))
271 }
272}
273
274#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
276pub struct ChannelBitMap {
277 pub channel_1: bool,
278 pub channel_2: bool,
279 pub channel_3: bool,
280 pub channel_4: bool,
281 pub channel_5: bool,
282 pub channel_6: bool,
283 pub channel_7: bool,
284 pub channel_8: bool,
285 pub channel_9: bool,
286 pub channel_10: bool,
287 pub channel_11: bool,
288 pub channel_12: bool,
289 pub channel_13: bool,
290 pub channel_14: bool,
291 pub channel_15: bool,
292 pub channel_16: bool,
293}
294
295impl ChannelBitMap {
296 pub fn all() -> Self {
298 Self {
299 channel_1: true,
300 channel_2: true,
301 channel_3: true,
302 channel_4: true,
303 channel_5: true,
304 channel_6: true,
305 channel_7: true,
306 channel_8: true,
307 channel_9: true,
308 channel_10: true,
309 channel_11: true,
310 channel_12: true,
311 channel_13: true,
312 channel_14: true,
313 channel_15: true,
314 channel_16: true,
315 }
316 }
317
318 pub fn none() -> Self {
320 Self::default()
321 }
322
323 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
324 let mut byte1: u8 = 0;
325 if self.channel_16 {
326 byte1 += 1 << 1;
327 }
328 if self.channel_15 {
329 byte1 += 1 << 0;
330 }
331 v.push(byte1);
332
333 let mut byte2: u8 = 0;
334 if self.channel_14 {
335 byte2 += 1 << 6;
336 }
337 if self.channel_13 {
338 byte2 += 1 << 5;
339 }
340 if self.channel_12 {
341 byte2 += 1 << 4;
342 }
343 if self.channel_11 {
344 byte2 += 1 << 3;
345 }
346 if self.channel_10 {
347 byte2 += 1 << 2;
348 }
349 if self.channel_9 {
350 byte2 += 1 << 1;
351 }
352 if self.channel_8 {
353 byte2 += 1 << 0;
354 }
355 v.push(byte2);
356
357 let mut byte3: u8 = 0;
358 if self.channel_7 {
359 byte3 += 1 << 6;
360 }
361 if self.channel_6 {
362 byte3 += 1 << 5;
363 }
364 if self.channel_5 {
365 byte3 += 1 << 4;
366 }
367 if self.channel_4 {
368 byte3 += 1 << 3;
369 }
370 if self.channel_3 {
371 byte3 += 1 << 2;
372 }
373 if self.channel_2 {
374 byte3 += 1 << 1;
375 }
376 if self.channel_1 {
377 byte3 += 1 << 0;
378 }
379 v.push(byte3);
380 }
381
382 #[allow(dead_code)]
383 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
384 Err(ParseError::NotImplemented("ChannelBitMap"))
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use crate::*;
391 use alloc::vec;
392 use bstr::B;
393 use core::convert::TryInto;
394
395 #[test]
396 fn serialize_tuning_note_change() {
397 assert_eq!(
398 MidiMsg::SystemExclusive {
399 msg: SystemExclusiveMsg::UniversalRealTime {
400 device: DeviceID::AllCall,
401 msg: UniversalRealTimeMsg::TuningNoteChange(TuningNoteChange {
402 tuning_program_num: 5,
403 tuning_bank_num: None,
404 tunings: vec![
405 (
406 1,
407 Some(Tuning {
408 semitone: 1,
409 fraction: 255,
410 }),
411 ),
412 (
413 0x33,
414 Some(Tuning {
415 semitone: 0x33,
416 fraction: 511,
417 }),
418 ),
419 (0x45, None),
420 (0x78, Some(Tuning::from_freq(8_372.063)))
421 ],
422 }),
423 },
424 }
425 .to_midi(),
426 &[
427 0xF0, 0x7F, 0x7F, 0x08, 0x02, 0x05, 4, 0x01, 0x01, 0x01, 0x7f, 0x33, 0x33, 0x03, 0x7f, 0x45, 0x7f, 0x7f, 0x7f, 0x78, 0x78, 0x00, 0x02, 0xF7,
434 ]
435 );
436 }
437
438 #[test]
439 fn serialize_tuning_bulk_dump_reply() {
440 let packet_msg = MidiMsg::SystemExclusive {
441 msg: SystemExclusiveMsg::UniversalNonRealTime {
442 device: DeviceID::AllCall,
443 msg: UniversalNonRealTimeMsg::KeyBasedTuningDump(KeyBasedTuningDump {
444 tuning_program_num: 5,
445 tuning_bank_num: None,
446 name: B("A tuning program").try_into().unwrap(), tunings: vec![Some(Tuning {
448 semitone: 1,
449 fraction: 255,
450 })],
451 }),
452 },
453 }
454 .to_midi();
455
456 assert_eq!(packet_msg.len(), 408);
457 assert_eq!(
458 &packet_msg[0..7],
459 &[0xF0, 0x7E, 0x7F, 0x08, 0x01, 0x05, b"A"[0]]
460 );
461
462 assert_eq!(
463 &packet_msg[22..31],
464 &[
465 0x01, 0x01, 0x7f, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00 ]
469 );
470 }
471}