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