1use std::fmt;
2use std::fs::File;
3use std::io::Read;
4use std::path::Path;
5
6use arr_macro::arr;
7use byteorder::{ByteOrder, LittleEndian};
8use glob::glob;
9use regex::Regex;
10
11mod reader;
12use reader::Reader;
13
14#[derive(PartialEq)]
15pub struct ParseError(String);
16
17impl fmt::Debug for ParseError {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 write!(f, "ParseError: {}", &self.0)
20 }
21}
22
23impl fmt::Display for ParseError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "ParseError: {}", &self.0)
26 }
27}
28
29impl std::error::Error for ParseError {}
30
31type Result<T> = std::result::Result<T, ParseError>;
32
33#[derive(PartialEq, Clone, Debug)]
34pub struct Project {
35 pub settings: Settings,
36 pub samples: Samples,
37 pub patterns: Vec<Pattern>,
38}
39
40impl Project {
41 pub fn read(path: &Path) -> Result<Self> {
42 if !path.is_dir() {
43 return Err(ParseError(format!(
44 "Provided project dir {:?} is not a directory",
45 &path
46 )));
47 }
48 let settings = Settings::read(&path.join("settings"))?;
49 let samples = Samples::read(&path.join("samples").join("samplesMetadata"))?;
50 let patterns = Pattern::read_patterns(&path.join("patterns"))?;
51
52 Ok(Self {
53 settings,
54 samples,
55 patterns,
56 })
57 }
58}
59
60#[derive(PartialEq, Clone, Default)]
61pub struct Settings {
62 pub name: String,
63 pub directory: String,
64 pub bpm: f32,
65 pub jack_cc_mapping: Vec<CCMapping>,
66 pub usb_cc_mapping: Vec<CCMapping>,
67 pub x20: Vec<u8>, pub xa8: Vec<u8>, pub xb0: Vec<u8>, pub x90: Vec<u8>, }
73
74impl Settings {
75 pub fn read(path: &Path) -> Result<Self> {
76 let mut file =
77 File::open(path).map_err(|_| ParseError(format!("No settings file present")))?;
78
79 let mut buf: Vec<u8> = vec![];
80 file.read_to_end(&mut buf).unwrap();
81 let reader = Reader::new(buf);
82
83 let mut attrs = Self::default();
84 Self::attrs_from_reader(&reader, &mut attrs)?;
85
86 Ok(attrs)
87 }
88
89 fn attrs_from_reader(reader: &Reader, settings: &mut Self) -> Result<()> {
90 let mut tag = reader.read();
91 let mut abort = false;
92 while tag != 0xc2 {
93 match tag {
95 0x12 => settings.name = reader.read_string(reader.read() as usize),
97 0x62 => settings.directory = reader.read_string(reader.read() as usize),
99 0x85 => {
101 reader.read(); settings.bpm = LittleEndian::read_f32(reader.read_bytes(4));
103 }
104 0x20 => settings.x20 = reader.read_bytes(5).to_vec(),
106 0x90 => settings.x90 = reader.read_bytes(11).to_vec(),
107 0xA8 => settings.xa8 = reader.read_bytes(2).to_vec(),
108 0xB0 => settings.xb0 = reader.read_bytes(2).to_vec(),
109 t => {
110 println!(
111 "Error: Unknown tag ({}). Aborting parsing project settings.",
112 t
113 );
114 abort = true;
115 break;
116 }
117 }
118 tag = reader.read();
119 }
120 if !abort {
121 reader.step_back(); settings.jack_cc_mapping = (0..16)
123 .map(|_| CCMapping::from_reader(&reader))
124 .collect::<Result<Vec<CCMapping>>>()?;
125 settings.usb_cc_mapping = (0..16)
126 .map(|_| CCMapping::from_reader(&reader))
127 .collect::<Result<Vec<CCMapping>>>()?;
128 }
129 Ok(())
130 }
131}
132
133impl fmt::Debug for Settings {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 f.debug_struct("Settings")
136 .field("name", &self.name)
137 .field("directory", &self.directory)
138 .field("bpm", &self.bpm)
139 .finish()
144 }
145}
146
147#[derive(PartialEq, Clone, Debug)]
148pub struct CCMapping {
149 pub u_first_bytes: [u8; 4], pub cutoff: u8,
151 pub resonance: u8,
152 pub sample_attack: u8,
153 pub sample_decay: u8,
154 pub reverb_send: u8,
155 pub delay_send: u8,
156 pub overdrive: u8,
157 pub bit_depth: u8,
158}
159
160impl CCMapping {
161 fn from_reader(reader: &Reader) -> Result<Self> {
162 assert_eq!(reader.read(), 0xC2); Ok(Self {
164 u_first_bytes: reader.read_bytes(4).try_into().unwrap(),
165 cutoff: reader.read(),
166 resonance: reader.read(),
167 sample_attack: reader.read(),
168 sample_decay: reader.read(),
169 reverb_send: reader.read(),
170 delay_send: reader.read(),
171 overdrive: reader.read(),
172 bit_depth: reader.read(),
173 })
174 }
175}
176
177#[derive(PartialEq, Clone)]
178pub struct Samples {
179 pub rest: Vec<u8>, }
181impl Samples {
182 pub fn read(path: &Path) -> Result<Self> {
183 let mut file = File::open(path)
184 .map_err(|_| ParseError(format!("Cannot read sample file: {:?}", &path)))?;
185
186 let mut buf: Vec<u8> = vec![];
187 file.read_to_end(&mut buf).unwrap();
188 let reader = Reader::new(buf);
189
190 let rest = reader.rest();
191
192 Ok(Self { rest })
193 }
194}
195
196impl fmt::Debug for Samples {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 f.debug_struct("Samples")
199 .finish()
208 }
209}
210
211type AudioTrackVariations = [Option<Track<Step>>; 16];
212type MidiTrackVariations = [Option<Track<MidiStep>>; 16];
213
214#[derive(PartialEq, Clone)]
215pub struct Pattern {
216 pub number: u8,
217 pub audio_tracks: [AudioTrackVariations; 8],
218 pub midi_tracks: [MidiTrackVariations; 8],
219 pub rest: Vec<u8>, }
221impl Pattern {
222 pub fn read_patterns(path: &Path) -> Result<Vec<Self>> {
224 if !path.is_dir() {
225 return Err(ParseError(format!(
226 "Provided patterns dir {:?} is not a directory",
227 &path
228 )));
229 }
230
231 let mut patterns = vec![];
232 for entry in glob(&format!("{}/*.pattern", path.to_str().unwrap()))
233 .map_err(|_| ParseError(format!("Could not read pattern dir")))?
234 {
235 match entry {
236 Ok(path) => {
237 let re = Regex::new(r"(\d+).pattern$").unwrap();
238 let pattern_number = if let Some(n) = re.captures(path.to_str().unwrap()) {
239 n.get(1).unwrap().as_str().parse().map_err(|_| {
240 ParseError(format!("Invalid pattern file name: {:?}", &path))
241 })?
242 } else {
243 return Err(ParseError(format!(
244 "Invalid pattern file name: {:?}",
245 &path
246 )));
247 };
248 patterns.push(Self::read(&path, pattern_number)?);
249 }
250 _ => return Err(ParseError(format!("Could not read pattern dir"))),
251 }
252 }
253
254 Ok(patterns)
255 }
256
257 pub fn read(path: &Path, number: u8) -> Result<Self> {
259 let mut file = File::open(path)
260 .map_err(|_| ParseError(format!("Cannot read pattern file: {:?}", &path)))?;
261
262 let mut buf: Vec<u8> = vec![];
263 file.read_to_end(&mut buf).unwrap();
264 let reader = Reader::new(buf);
265
266 let mut audio_tracks = arr![arr![None; 16]; 8];
267 let mut midi_tracks = arr![arr![None; 16]; 8];
268 for track in 0..8 {
270 let t = Track::from_reader(&reader, track, 0, false)?;
271 let v = t.variation;
272 audio_tracks[track][v] = Some(t);
273 }
274 for track in 0..8 {
275 let t = Track::from_reader(&reader, track, 0, false)?;
276 let v = t.variation;
277 midi_tracks[track][v] = Some(t);
278 }
279
280 let rest = reader.rest();
281
282 let (audio_variation, midi_variation) =
283 Self::read_variations(path.parent().unwrap(), number)?;
284 for variation in audio_variation {
285 let track = variation.number;
286 let v = variation.variation;
287 if audio_tracks[track][v].is_some() {
288 continue;
289 }
290 audio_tracks[track][v] = Some(variation);
291 }
292 for variation in midi_variation {
293 let track = variation.number;
294 let v = variation.variation;
295 if midi_tracks[track][v].is_some() {
296 continue;
297 }
298 midi_tracks[track][v] = Some(variation);
299 }
300
301 Ok(Self {
302 number,
303 audio_tracks,
304 midi_tracks,
305 rest,
306 })
307 }
308
309 fn read_variations(
310 path: &Path,
311 pattern_number: u8,
312 ) -> Result<(Vec<Track<Step>>, Vec<Track<MidiStep>>)> {
313 let mut audio: Vec<Track<Step>> = vec![];
314 let mut midi: Vec<Track<MidiStep>> = vec![];
315 for track in 0..16 {
316 let mut track_files = glob(&format!(
317 "{}/{}-{}-*.track",
318 path.to_str().unwrap(),
319 pattern_number,
320 track
321 ))
322 .map_err(|_| ParseError(format!("Could not read track dir")))?;
323
324 if track_files.next().is_some() {
325 for variation in 0..16 {
326 let track_path =
327 path.join(&format!("{}-{}-{}.track", pattern_number, track, variation));
328 if track_path.is_file() {
329 if track < 8 {
330 audio.push(Track::read(&track_path, track, variation)?);
331 } else {
332 midi.push(Track::read(&track_path, track - 8, variation)?);
333 }
334 }
335 }
336 }
337 }
338 Ok((audio, midi))
339 }
340
341 pub fn audio_track(&self, n: usize) -> &Track<Step> {
343 self.audio_tracks[n][0].as_ref().unwrap()
344 }
345
346 pub fn midi_track(&self, n: usize) -> &Track<MidiStep> {
348 self.midi_tracks[n][0].as_ref().unwrap()
349 }
350}
351
352impl fmt::Debug for Pattern {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 f.debug_struct("Pattern")
355 .field("number", &self.number)
356 .field("audio_tracks", &self.audio_tracks)
357 .field("midi_tracks", &self.midi_tracks)
358 .finish()
367 }
368}
369
370#[derive(PartialEq, Clone)]
371pub struct Track<S: TrackStep + Clone> {
372 pub number: usize,
373 pub variation: usize,
374 pub steps: Vec<S>,
375 pub swing: u8,
377 pub play_mode: u8,
378 pub track_speed: TrackSpeed,
379 pub is_default: bool,
380 attrs: TrackAttrs,
381}
382
383impl<S: TrackStep + Clone> Track<S> {
384 fn from_reader(
385 reader: &Reader,
386 number: usize,
387 variation: usize,
388 from_file: bool,
389 ) -> Result<Self> {
390 let track_len = {
391 if from_file {
392 reader.buffer_len()
393 } else {
394 assert_eq!(reader.read(), 0x0A); reader.read_variable_quantity()
396 }
397 };
398 let start_pos = reader.pos();
401 let steps = (0..64)
402 .map(|step| S::from_reader(reader, step))
403 .collect::<Result<Vec<S>>>()?;
404
405 let attrs = TrackAttrs::from_reader(reader, track_len + start_pos)?;
406 assert!(attrs.num_steps > 0 && attrs.num_steps < 65);
407
408 let bytes_advanced = reader.pos() - start_pos;
409 assert_eq!(bytes_advanced, track_len);
410 Ok(Self {
411 number,
412 variation: if from_file {
413 variation
414 } else {
415 attrs.variation as usize
416 },
417 steps: steps[0..(attrs.num_steps as usize)].try_into().unwrap(),
418 swing: attrs.swing,
419 play_mode: attrs.play_mode,
420 track_speed: attrs.track_speed,
421 is_default: !from_file,
422 attrs,
423 })
424 }
425
426 pub fn read(path: &Path, track_number: usize, variation_number: usize) -> Result<Self> {
427 let mut file = File::open(path)
428 .map_err(|_| ParseError(format!("Cannot read track file: {:?}", &path)))?;
429
430 let mut buf: Vec<u8> = vec![];
431 file.read_to_end(&mut buf).unwrap();
432 let reader = Reader::new(buf);
433
434 Self::from_reader(&reader, track_number, variation_number, true)
435 }
436}
437
438impl<S: TrackStep + Clone + fmt::Debug> fmt::Debug for Track<S> {
439 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
440 f.debug_struct("Track")
441 .field("number", &self.number)
442 .field("variation", &self.variation)
443 .field("steps", &self.steps)
444 .field("swing", &self.swing)
445 .field("track_speed", &self.track_speed)
446 .field("play_mode", &self.play_mode)
447 .finish()
449 }
450}
451
452#[derive(PartialEq, Clone, Default, Debug)]
453pub struct TrackAttrs {
454 num_steps: u8,
455 swing: u8,
457 play_mode: u8,
458 track_speed: TrackSpeed,
459 variation: u8,
461 variations: Vec<bool>,
463 ux18: u8,
465}
466
467impl TrackAttrs {
468 fn from_reader(reader: &Reader, max_pos: usize) -> Result<Self> {
469 let mut attrs = TrackAttrs::default();
470
471 while reader.pos() < max_pos {
472 let val = reader.read();
473 match val {
474 0x10 => attrs.num_steps = reader.read(),
475 0x38 => attrs.swing = reader.read(),
476 0x40 => attrs.play_mode = reader.read(),
477 0x20 => {
478 if let TrackSpeed::Fraction(_, d) = attrs.track_speed {
479 attrs.track_speed = match reader.read() {
480 0 => TrackSpeed::Paused,
481 n => TrackSpeed::Fraction(n, d),
482 };
483 } else {
484 attrs.track_speed = TrackSpeed::Fraction(reader.read(), 1)
485 }
486 }
487 0x28 => {
488 if let TrackSpeed::Fraction(n, _) = attrs.track_speed {
489 attrs.track_speed = match reader.read() {
490 0 => TrackSpeed::Paused,
491 d => TrackSpeed::Fraction(n, d),
492 };
493 } else {
494 reader.read(); }
496 }
497 0x30 => attrs.variation = reader.read(),
498 0x4a => {
499 let len = reader.read();
500 attrs.variations = reader
501 .read_bytes(len as usize)
502 .iter()
503 .map(|&x| x != 0)
504 .collect();
505 }
506 0x18 => attrs.ux18 = reader.read(),
507 x => {
508 println!(
509 "Warning: encountered unknown track tag {:02X} with value {}",
510 x,
511 reader.read()
512 );
513 }
514 }
515 }
516
517 Ok(attrs)
518 }
519}
520
521#[derive(PartialEq, Clone, Debug, Copy)]
522pub enum TrackSpeed {
523 Fraction(u8, u8),
525 Paused,
526}
527
528impl Default for TrackSpeed {
529 fn default() -> Self {
530 Self::Paused
531 }
532}
533
534pub trait TrackStep {
535 fn from_reader(reader: &Reader, number: usize) -> Result<Self>
536 where
537 Self: Sized;
538}
539
540#[derive(PartialEq, Clone)]
541pub struct Step {
542 pub number: usize,
544 pub sample: u16,
546 pub note: u8,
548 pub volume: u16,
550 pub pan: i16,
552 pub filter_cutoff: i16,
554 pub filter_resonance: u16,
556 pub overdrive: u16,
558 pub bit_depth: u8,
560 pub micro_move: i16,
562 pub reverb: i16,
564 pub delay: i16,
565 pub sample_start: i16,
567 pub sample_end: i16,
568 pub sample_attack: u16,
570 pub sample_decay: u16,
571 pub sample_folder: u16,
573 pub repeat_type: u16,
575 pub repeat_grid: u16,
576 pub chance_type: u16,
578 pub chance_action: u16,
580 pub micro_tune: i16,
582
583 pub rest: Vec<u8>, }
585
586impl TrackStep for Step {
587 fn from_reader(reader: &Reader, number: usize) -> Result<Self> {
588 assert_eq!(reader.read(), 0x0A, "Error reading {}nth step", number); let len = reader.read_variable_quantity(); let start_pos = reader.pos();
592 assert_eq!(reader.read(), 0x0A); let num_elements = reader.read_variable_quantity(); assert_eq!(num_elements, 44); let volume = LittleEndian::read_u16(reader.read_bytes(2));
598 let pan = LittleEndian::read_i16(reader.read_bytes(2));
599 let filter_cutoff = LittleEndian::read_i16(reader.read_bytes(2));
600 let filter_resonance = LittleEndian::read_u16(reader.read_bytes(2));
601 let bit_depth = LittleEndian::read_u16(reader.read_bytes(2)) as u8;
602 let overdrive = LittleEndian::read_u16(reader.read_bytes(2));
603 let note = LittleEndian::read_u16(reader.read_bytes(2)) as u8;
604 let delay = LittleEndian::read_i16(reader.read_bytes(2));
605 let reverb = LittleEndian::read_i16(reader.read_bytes(2));
606 let sample = LittleEndian::read_u16(reader.read_bytes(2));
607 let sample_start = LittleEndian::read_i16(reader.read_bytes(2));
608 let sample_end = LittleEndian::read_i16(reader.read_bytes(2));
609 let micro_tune = LittleEndian::read_i16(reader.read_bytes(2));
610 let sample_attack = LittleEndian::read_u16(reader.read_bytes(2));
611 let sample_decay = LittleEndian::read_u16(reader.read_bytes(2));
612 let sample_folder = LittleEndian::read_u16(reader.read_bytes(2));
613 let repeat_type = LittleEndian::read_u16(reader.read_bytes(2));
614 let repeat_grid = LittleEndian::read_u16(reader.read_bytes(2));
615 let chance_type = LittleEndian::read_u16(reader.read_bytes(2));
616 let chance_action = LittleEndian::read_u16(reader.read_bytes(2));
617 let micro_move = LittleEndian::read_i16(reader.read_bytes(2));
618
619 let bytes_advanced = reader.pos() - start_pos;
620 let rest = reader.read_bytes(len - bytes_advanced); Ok(Self {
624 number,
625 sample,
626 note,
627 volume,
628 pan,
629 filter_cutoff,
630 filter_resonance,
631 micro_move,
632 micro_tune,
633 sample_start,
634 sample_end,
635 sample_attack,
636 sample_decay,
637 sample_folder,
638 repeat_type,
639 repeat_grid,
640 chance_type,
641 chance_action,
642 reverb,
643 delay,
644 overdrive,
645 bit_depth,
646 rest: rest.to_vec(),
647 })
648 }
649}
650
651impl fmt::Debug for Step {
652 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
653 f.debug_struct("Step")
654 .field("number", &self.number)
655 .field("volume", &self.volume)
656 .field("note", &self.note)
657 .field("sample", &self.sample)
658 .field("sample_start", &self.sample_start)
659 .field("sample_end", &self.sample_end)
660 .field("sample_attack", &self.sample_attack)
661 .field("sample_decay", &self.sample_decay)
662 .field("pan", &self.pan)
663 .field("filter_cutoff", &self.filter_cutoff)
664 .field("filter_resonance", &self.filter_resonance)
665 .field("micro_move", &self.micro_move)
666 .field("micro_tune", &self.micro_tune)
667 .field("repeat_type", &self.repeat_type)
668 .field("repeat_grid", &self.repeat_grid)
669 .field("chance_type", &self.chance_type)
670 .field("chance_action", &self.chance_action)
671 .field("reverb", &self.reverb)
672 .field("delay", &self.delay)
673 .field("overdrive", &self.overdrive)
674 .field("bit_depth", &self.bit_depth)
675 .finish()
676
677 }
703}
704
705#[derive(PartialEq, Clone)]
706pub struct MidiStep {
707 pub number: usize,
709 pub channel: MidiChannel,
711 pub program: Option<u8>,
712 pub note: u8,
714 pub velocity: u8,
715 pub note_length: u16,
717 pub chord: i16,
719 pub micro_move: i16,
721 pub pitch_bend: Option<i16>,
723
724 pub cc12: Option<u8>,
726 pub cc13: Option<u8>,
727 pub cc17: Option<u8>,
728 pub cc19: Option<u8>,
729 pub cc22: Option<u8>,
730 pub cc71: Option<u8>,
731 pub cc74: Option<u8>,
732 pub cc75: Option<u8>,
733
734 pub repeat_type: u16,
737 pub repeat_grid: u16,
738 pub chance_type: u16,
740 pub chance_action: u16,
742
743 pub rest: Vec<u8>, }
745
746impl TrackStep for MidiStep {
747 fn from_reader(reader: &Reader, number: usize) -> Result<Self> {
748 assert_eq!(reader.read(), 0x0A, "Error reading {}nth step", number); let len = reader.read_variable_quantity(); let start_pos = reader.pos();
752 assert_eq!(reader.read(), 0x0A); let num_elements = reader.read_variable_quantity(); assert_eq!(num_elements, 44); let velocity = LittleEndian::read_u16(reader.read_bytes(2)) as u8;
758 let note_length = LittleEndian::read_u16(reader.read_bytes(2));
759 let mut cc74 = Some(LittleEndian::read_i16(reader.read_bytes(2)) as u8);
760 let mut cc71 = Some(LittleEndian::read_u16(reader.read_bytes(2)) as u8);
761 let mut cc13 = Some(LittleEndian::read_u16(reader.read_bytes(2)) as u8);
762 let mut cc12 = Some(LittleEndian::read_u16(reader.read_bytes(2)) as u8);
763 let note = LittleEndian::read_u16(reader.read_bytes(2)) as u8;
764 let mut cc19 = Some(LittleEndian::read_i16(reader.read_bytes(2)) as u8);
765 let mut cc17 = Some(LittleEndian::read_i16(reader.read_bytes(2)) as u8);
766 let channel = MidiChannel::from(LittleEndian::read_u16(reader.read_bytes(2)));
767 let chord = LittleEndian::read_i16(reader.read_bytes(2));
768 let _sample_end = LittleEndian::read_i16(reader.read_bytes(2)); let mut pitch_bend = Some(LittleEndian::read_i16(reader.read_bytes(2)));
770 let mut cc22 = Some(LittleEndian::read_u16(reader.read_bytes(2)) as u8);
771 let mut cc75 = Some(LittleEndian::read_u16(reader.read_bytes(2)) as u8);
772 let mut program = Some(LittleEndian::read_u16(reader.read_bytes(2)) as u8);
773 let mut repeat_type = LittleEndian::read_u16(reader.read_bytes(2));
774 let mut repeat_grid = LittleEndian::read_u16(reader.read_bytes(2));
775 let chance_type = LittleEndian::read_u16(reader.read_bytes(2));
776 let chance_action = LittleEndian::read_u16(reader.read_bytes(2));
777 let micro_move = LittleEndian::read_i16(reader.read_bytes(2));
778
779 let bytes_advanced = reader.pos() - start_pos;
780 let rest = reader.read_bytes(len - bytes_advanced);
782
783 if rest.len() > 2 {
784 let m1 = rest[5];
785 let m2 = rest[6];
786 let m3 = rest[7];
787
788 if ((m1 >> 5) & 1) == 0 {
791 cc12 = None
792 }
793 if ((m1 >> 4) & 1) == 0 {
794 cc13 = None
795 }
796 if ((m1 >> 3) & 1) == 0 {
797 cc71 = None
798 }
799 if ((m1 >> 2) & 1) == 0 {
800 cc74 = None
801 }
802
803 if ((m2 >> 6) & 1) == 0 {
804 cc22 = None
805 }
806 if ((m2 >> 5) & 1) == 0 {
807 pitch_bend = None
808 }
809 if ((m2 >> 1) & 1) == 0 {
810 cc17 = None
811 }
812 if (m2 & 1) == 0 {
813 cc19 = None
814 }
815
816 if ((m3 >> 3) & 1) == 0 {
818 repeat_grid = 0
819 }
820 if ((m3 >> 2) & 1) == 0 {
821 repeat_type = 0
822 }
823 if ((m3 >> 1) & 1) == 0 {
824 program = None
825 }
826 if (m3 & 1) == 0 {
827 cc75 = None
828 }
829
830 } else {
832 cc12 = None;
833 cc13 = None;
834 cc17 = None;
835 cc19 = None;
836 cc22 = None;
837 cc71 = None;
838 cc74 = None;
839 cc75 = None;
840 program = None;
841 pitch_bend = None;
842 }
843
844 Ok(Self {
845 number,
846 channel,
847 program,
848 note,
849 velocity,
850 note_length,
851 micro_move,
852 pitch_bend,
853 chord,
854 cc12,
855 cc13,
856 cc17,
857 cc19,
858 cc22,
859 cc71,
860 cc74,
861 cc75,
862 repeat_type,
863 repeat_grid,
864 chance_type,
865 chance_action,
866 rest: rest.to_vec(),
867 })
868 }
869}
870
871impl fmt::Debug for MidiStep {
872 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
873 f.debug_struct("MidiStep")
874 .field("number", &self.number)
875 .field("note", &self.note)
876 .field("velocity", &self.velocity)
877 .field("channel", &self.channel)
878 .field("program", &self.program)
879 .field("note_length", &self.note_length)
880 .field("micro_move", &self.micro_move)
881 .field("pitch_bend", &self.pitch_bend)
882 .field("cc12", &self.cc12)
883 .field("cc13", &self.cc13)
884 .field("cc17", &self.cc17)
885 .field("cc19", &self.cc19)
886 .field("cc22", &self.cc22)
887 .field("cc71", &self.cc71)
888 .field("cc74", &self.cc74)
889 .field("cc75", &self.cc75)
890 .field("repeat_type", &self.repeat_type)
891 .field("repeat_grid", &self.repeat_grid)
892 .field("chance_type", &self.chance_type)
893 .field("chance_action", &self.chance_action)
894 .finish()
895
896 }
924}
925
926#[derive(PartialEq, Clone, Copy, Debug)]
927pub enum MidiChannel {
928 Jack(u8),
929 Usb(u8),
930}
931
932impl From<u16> for MidiChannel {
933 fn from(x: u16) -> Self {
934 if x < 16 {
935 MidiChannel::Jack(x as u8 + 1)
936 } else {
937 MidiChannel::Usb(x as u8 + 1 - 16)
938 }
939 }
940}