1use super::ParseError;
2use alloc::vec::Vec;
3use micromath::F32Ext;
4
5#[inline]
6pub fn to_u7(x: u8) -> u8 {
7 x.min(127)
8}
9
10#[inline]
11pub fn i_to_u7(x: i8) -> u8 {
12 to_u7((x.max(-64) + 64) as u8)
13}
14
15#[inline]
16pub fn u7_to_i(x: u8) -> i8 {
17 x as i8 - 64
18}
19
20#[inline]
21pub fn bool_from_u7(x: u8) -> Result<bool, ParseError> {
22 if x > 127 {
23 Err(ParseError::ByteOverflow)
24 } else {
25 Ok(x >= 0x40)
26 }
27}
28
29#[inline]
30pub fn u8_from_u7(x: u8) -> Result<u8, ParseError> {
31 if x > 127 {
32 Err(ParseError::ByteOverflow)
33 } else {
34 Ok(x)
35 }
36}
37
38#[inline]
39pub fn u7_from_midi(m: &[u8]) -> Result<u8, ParseError> {
40 if m.is_empty() {
41 Err(ParseError::UnexpectedEnd)
42 } else {
43 u8_from_u7(m[0])
44 }
45}
46
47#[inline]
59pub fn to_u14(x: u16) -> [u8; 2] {
60 if x > 16383 {
61 [0x7f, 0x7f]
62 } else {
63 [(x >> 7) as u8, x as u8 & 0b01111111]
64 }
65}
66
67#[inline]
68pub fn i_to_u14(x: i16) -> [u8; 2] {
69 to_u14((x.max(-8192) + 8192) as u16)
70}
71
72#[inline]
73pub fn u14_from_midi(m: &[u8]) -> Result<u16, ParseError> {
74 if m.len() < 2 {
75 Err(crate::ParseError::UnexpectedEnd)
76 } else {
77 let (lsb, msb) = (m[0], m[1]);
78 if lsb > 127 || msb > 127 {
79 Err(ParseError::ByteOverflow)
80 } else {
81 let mut x = lsb as u16;
82 x += (msb as u16) << 7;
83 Ok(x)
84 }
85 }
86}
87
88#[inline]
89pub fn replace_u14_lsb(msb: u16, lsb: u8) -> u16 {
90 (msb & 0b11111110000000) + (lsb as u16)
91}
92
93#[inline]
94pub fn u14_from_u7s(msb: u8, lsb: u8) -> u16 {
95 ((msb as u16) << 7) + (lsb as u16)
96}
97
98#[inline]
99pub fn i14_from_u7s(msb: u8, lsb: u8) -> i16 {
100 u14_from_u7s(msb, lsb) as i16 - 8192
101}
102
103#[inline]
104pub fn to_nibble(x: u8) -> [u8; 2] {
105 [x >> 4, x & 0b00001111]
106}
107
108#[inline]
109pub fn push_u7(x: u8, v: &mut Vec<u8>) {
110 v.push(to_u7(x));
111}
112
113#[inline]
119pub fn push_u14(x: u16, v: &mut Vec<u8>) {
120 let [msb, lsb] = to_u14(x);
121 v.push(lsb);
122 v.push(msb);
123}
124
125pub fn freq_to_midi_note_float(freq: f32) -> f32 {
127 12.0 * F32Ext::log2(freq / 440.0) + 69.0
128}
129
130pub fn midi_note_float_to_freq(note: f32) -> f32 {
132 F32Ext::powf(2.0, (note - 69.0) / 12.0) * 440.0
133}
134
135pub fn midi_note_cents_to_freq(note: u8, cents: f32) -> f32 {
137 midi_note_float_to_freq(note as f32 + cents / 100.0)
138}
139
140pub fn freq_to_midi_note_cents(freq: f32) -> (u8, f32) {
142 let semitone = freq_to_midi_note_float(freq);
143 (semitone as u8, F32Ext::fract(semitone) * 100.0)
144}
145
146#[cfg(feature = "sysex")]
147mod sysex_util {
148 use alloc::vec::Vec;
149
150 #[inline]
151 pub fn push_i14(x: i16, v: &mut Vec<u8>) {
152 let [msb, lsb] = to_i14(x);
153 v.push(lsb);
154 v.push(msb);
155 }
156
157 #[inline]
158 pub fn push_u21(x: u32, v: &mut Vec<u8>) {
159 let [msb, b, lsb] = to_u21(x);
160 v.push(lsb);
161 v.push(b);
162 v.push(msb);
163 }
164
165 #[inline]
166 pub fn push_u28(x: u32, v: &mut Vec<u8>) {
167 let [mmsb, msb, lsb, llsb] = to_u28(x);
168 v.push(llsb);
169 v.push(lsb);
170 v.push(msb);
171 v.push(mmsb);
172 }
173
174 #[inline]
175 pub fn push_u35(x: u64, v: &mut Vec<u8>) {
176 let [msb, b2, b3, b4, lsb] = to_u35(x);
177 v.push(lsb);
178 v.push(b4);
179 v.push(b3);
180 v.push(b2);
181 v.push(msb);
182 }
183
184 pub fn checksum(bytes: &[u8]) -> u8 {
185 let mut sum: u8 = 0;
186 for b in bytes.iter() {
187 sum ^= b;
188 }
189 sum
190 }
191
192 pub fn cents_to_u14(cents: f32) -> u16 {
195 let cents = cents.clamp(0.0, 100.0);
196 super::F32Ext::round(cents / 100.0 * (0b11111111111111 as f32)) as u16
197 }
198
199 #[inline]
200 pub fn to_i14(x: i16) -> [u8; 2] {
201 if x > 8191 {
202 [0x3f, 0x7f]
203 } else if x < -8191 {
204 [0x40, 0x00]
205 } else {
206 [(x >> 7) as u8 & 0b01111111, x as u8 & 0b01111111]
207 }
208 }
209
210 #[inline]
211 pub fn to_u21(x: u32) -> [u8; 3] {
212 if x > 2097151 {
213 [0x7f, 0x7f, 0x7f]
214 } else {
215 [
216 (x >> 14) as u8,
217 (x >> 7) as u8 & 0b01111111,
218 x as u8 & 0b01111111,
219 ]
220 }
221 }
222
223 #[inline]
224 pub fn to_u28(x: u32) -> [u8; 4] {
225 if x > 2684354561 {
226 [0x7f, 0x7f, 0x7f, 0x7f]
227 } else {
228 [
229 (x >> 21) as u8,
230 (x >> 14) as u8 & 0b01111111,
231 (x >> 7) as u8 & 0b01111111,
232 x as u8 & 0b01111111,
233 ]
234 }
235 }
236
237 #[inline]
238 pub fn to_u35(x: u64) -> [u8; 5] {
239 if x > 34359738367 {
240 [0x7f, 0x7f, 0x7f, 0x7f, 0x7f]
241 } else {
242 [
243 (x >> 28) as u8,
244 (x >> 21) as u8 & 0b01111111,
245 (x >> 14) as u8 & 0b01111111,
246 (x >> 7) as u8 & 0b01111111,
247 x as u8 & 0b01111111,
248 ]
249 }
250 }
251}
252
253#[cfg(feature = "sysex")]
254pub use sysex_util::*;
255
256#[cfg(feature = "file")]
257mod file_util {
258 use super::ParseError;
259 use alloc::vec::Vec;
260 use core::convert::TryInto;
261
262 #[inline]
263 pub fn push_u16(x: u16, v: &mut Vec<u8>) {
264 let [b1, b2] = x.to_be_bytes();
265 v.push(b1);
266 v.push(b2);
267 }
268
269 #[inline]
270 pub fn push_u32(x: u32, v: &mut Vec<u8>) {
271 let [b1, b2, b3, b4] = x.to_be_bytes();
272 v.push(b1);
273 v.push(b2);
274 v.push(b3);
275 v.push(b4);
276 }
277
278 pub fn push_vlq(x: u32, v: &mut Vec<u8>) {
280 if x < 0x00000080 {
281 v.push(x as u8 & 0b01111111);
282 } else if x < 0x00004000 {
283 v.push(((x >> 7) as u8 & 0b01111111) + 0b10000000);
284 v.push(x as u8 & 0b01111111);
285 } else if x < 0x00200000 {
286 v.push(((x >> 14) as u8 & 0b01111111) + 0b10000000);
287 v.push(((x >> 7) as u8 & 0b01111111) + 0b10000000);
288 v.push(x as u8 & 0b01111111);
289 } else if x <= 0x0FFFFFFF {
290 v.push(((x >> 21) as u8 & 0b01111111) + 0b10000000);
291 v.push(((x >> 14) as u8 & 0b01111111) + 0b10000000);
292 v.push(((x >> 7) as u8 & 0b01111111) + 0b10000000);
293 v.push(x as u8 & 0b01111111);
294 } else {
295 panic!("Cannot use such a large number as a variable quantity")
296 }
297 }
298
299 #[inline]
311 pub fn u32_from_midi(m: &[u8]) -> Result<u32, ParseError> {
312 if m.len() < 4 {
313 Err(crate::ParseError::UnexpectedEnd)
314 } else {
315 Ok(u32::from_be_bytes(m[0..4].try_into().unwrap()))
316 }
317 }
318
319 pub fn read_vlq(data: &[u8]) -> Result<(u32, usize), ParseError> {
320 let mut result: u32 = 0;
321 let mut bytes_read = 0;
322
323 for &byte in data {
324 result = (result << 7) | (byte & 0b01111111) as u32;
325 bytes_read += 1;
326
327 if byte & 0b10000000 == 0 {
328 return Ok((result, bytes_read));
330 }
331
332 if bytes_read >= 4 {
334 return Err(ParseError::VlqOverflow);
335 }
336 }
337
338 Err(ParseError::UnexpectedEnd)
340 }
341}
342
343#[cfg(feature = "file")]
344pub use file_util::*;
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn test_to_u7() {
352 assert_eq!(to_u7(0xff), 127); assert_eq!(to_u7(0x77), 0x77);
354 assert_eq!(to_u7(0x00), 0x00);
355 assert_eq!(to_u7(0x7f), 127);
356 }
357
358 #[test]
359 fn test_to_u14() {
360 assert_eq!(to_u14(0xff), [1, 127]);
361 assert_eq!(to_u14(0xff00), [127, 127]); assert_eq!(to_u14(0x00), [0, 0]);
363 assert_eq!(to_u14(0xfff), [0x1f, 127]);
364 assert_eq!(to_u14(1000), [0x07, 0x68]);
365 }
366
367 #[test]
368 fn test_i_to_u() {
369 assert_eq!(i_to_u7(63), 127);
370 assert_eq!(i_to_u7(0), 64);
371 assert_eq!(i_to_u7(-64), 0);
372
373 assert_eq!(i_to_u14(0), to_u14(8192));
374 assert_eq!(i_to_u14(-8192), to_u14(0));
375 assert_eq!(i_to_u14(8191), to_u14(16383));
376 }
377
378 #[test]
379 fn test_u_to_i() {
380 assert_eq!(u7_to_i(127), 63);
381 assert_eq!(u7_to_i(64), 0);
382 assert_eq!(u7_to_i(0), -64);
383
384 assert_eq!(i14_from_u7s(to_u14(8192)[0], to_u14(8192)[1]), 0);
385 assert_eq!(i14_from_u7s(0, 0), -8192);
386 assert_eq!(i14_from_u7s(to_u14(16383)[0], to_u14(16383)[1]), 8191);
387 }
388
389 #[test]
390 fn test_midi_note_float_to_freq() {
391 assert!((midi_note_float_to_freq(67.0) - 392.0).abs() <= 0.01);
392 }
393
394 #[test]
395 #[cfg(feature = "sysex")]
396 fn test_to_i14() {
397 assert_eq!(to_i14(0xff), [0x01, 0x7f]);
398 assert_eq!(to_i14(0x6f00), [0x3f, 0x7f]); assert_eq!(to_i14(0x00), [0, 0]);
400 assert_eq!(to_i14(0xfff), [0x1f, 0x7f]);
401 assert_eq!(to_i14(1000), [0x07, 0x68]);
402 assert_eq!(to_i14(-10000), [0x40, 0x00]); assert_eq!(to_i14(-8192), [0x40, 0x00]);
404 assert_eq!(to_i14(-8191), [0x40, 0x01]);
405 assert_eq!(to_i14(-1), [0x7f, 0x7f]);
406 }
407
408 #[test]
409 #[cfg(feature = "sysex")]
410 fn test_to_u21() {
411 assert_eq!(to_u21(0xff), [0, 1, 127]);
412 assert_eq!(to_u21(0xff00), [3, 126, 0]);
413 assert_eq!(to_u21(0xffff00), [127, 127, 127]); assert_eq!(to_u21(0x00), [0, 0, 0]);
415 assert_eq!(to_u21(0xfff), [0, 0x1f, 127]);
416 assert_eq!(
417 to_u21(0b1000011010100000),
418 [0b00000010, 0b00001101, 0b00100000]
419 );
420 }
421
422 #[test]
423 #[cfg(feature = "sysex")]
424 fn text_checksum() {
425 assert_eq!(checksum(&[0b11110000, 0b00001111, 0b10101010]), 0b01010101);
426 assert_eq!(
427 checksum(&[0x41, 0x4D, 0x02, 0x41, 0x21, 0x04, 0x02, 0x02]),
428 0x6A
429 )
430 }
431
432 #[cfg(feature = "sysex")]
433 fn freq_to_midi_note_u14(freq: f32) -> (u8, u16) {
434 let (n, c) = crate::freq_to_midi_note_cents(freq);
435 (n, cents_to_u14(c))
436 }
437
438 #[test]
439 #[cfg(feature = "sysex")]
440 fn test_freq_to_midi_note() {
441 assert_eq!(freq_to_midi_note_u14(8.1758), (0x00, 0x0f));
453
454 assert_eq!(freq_to_midi_note_u14(8.662), (0x01, 0x11));
459
460 assert_eq!(freq_to_midi_note_u14(261.6256), (0x3C, 0x0f));
465
466 assert_eq!(freq_to_midi_note_u14(440.0000), (0x45, 0x00));
470
471 assert_eq!(freq_to_midi_note_u14(8_372.019), (0x78, 0x01));
476
477 assert_eq!(freq_to_midi_note_u14(12_543.88), (0x7F, 0x02));
482 }
483
484 #[test]
485 #[cfg(feature = "file")]
486 fn test_vlq() {
487 fn test(x: u32, expected_len: usize) {
488 let mut v = Vec::new();
489 push_vlq(x, &mut v);
490 let (y, len) = read_vlq(&v).unwrap();
491 assert_eq!(
492 x, y,
493 "Got {} after converting {} to and from a variable-length quantity",
494 y, x
495 );
496 assert_eq!(
497 len, expected_len,
498 "Expected a variable-length quantity of length {} but got {}",
499 expected_len, len
500 );
501 }
502 test(0, 1);
503 test(0x40, 1);
504 test(0x7F, 1);
505 test(0x80, 2);
506 test(0x2000, 2);
507 test(0x3FFF, 2);
508 test(0x4000, 3);
509 test(0x100000, 3);
510 test(0x1FFFFF, 3);
511 test(0x200000, 4);
512 test(0x8000000, 4);
513 test(0xFFFFFFF, 4);
514
515 assert_eq!(
516 read_vlq(&[0x80, 0x80, 0x80, 0x80]),
517 Err(ParseError::VlqOverflow)
518 );
519 }
520}