play_files/
lib.rs

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    // TODO
68    pub x20: Vec<u8>, // Unknown 5 bytes
69    pub xa8: Vec<u8>, // Unknown 2 bytes
70    pub xb0: Vec<u8>, // Unknown 2 bytes
71    pub x90: Vec<u8>, // Unknown 11? bytes
72}
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            // Elements in the CCMapping begin with 0xC2
94            match tag {
95                // name
96                0x12 => settings.name = reader.read_string(reader.read() as usize),
97                // directory
98                0x62 => settings.directory = reader.read_string(reader.read() as usize),
99                // bpm
100                0x85 => {
101                    reader.read(); // TODO Unknown byte (always 01?)
102                    settings.bpm = LittleEndian::read_f32(reader.read_bytes(4));
103                }
104                // unknowns TODO
105                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(); // Replace the last 0xC2
122            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            // .field("x20", &self.x20)
140            // .field("xa8", &self.xa8)
141            // .field("xb0", &self.xb0)
142            // .field("x90", &self.x90)
143            .finish()
144    }
145}
146
147#[derive(PartialEq, Clone, Debug)]
148pub struct CCMapping {
149    pub u_first_bytes: [u8; 4], // TODO
150    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); // First byte probably tag (0xC2)
163        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>, // TODO
180}
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            // .field(
200            //     "rest",
201            //     &format!(
202            //         "{} bytes: {:?}...",
203            //         self.rest.len(),
204            //         &&self.rest[0..10.min(self.rest.len())]
205            //     ),
206            // )
207            .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>, // TODO
220}
221impl Pattern {
222    /// Read a pattern directory
223    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    /// Read a particular pattern file. Will also read any track files that match the pattern number
258    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        // dbg!(path);
269        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    /// Get the first variation of a track
342    pub fn audio_track(&self, n: usize) -> &Track<Step> {
343        self.audio_tracks[n][0].as_ref().unwrap()
344    }
345
346    /// Get the first variation of a track
347    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            // .field(
359            //     "rest",
360            //     &format!(
361            //         "{} bytes: {:?}...",
362            //         self.rest.len(),
363            //         &&self.rest[0..10.min(self.rest.len())]
364            //     ),
365            // )
366            .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    // Percentage 25-75
376    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); // First tag (0x0A)
395                reader.read_variable_quantity()
396            }
397        };
398        // println!("Reading track {:?} {} with len {}", ty, number, track_len);
399
400        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            // .field("attrs", &self.attrs)
448            .finish()
449    }
450}
451
452#[derive(PartialEq, Clone, Default, Debug)]
453pub struct TrackAttrs {
454    num_steps: u8,
455    // Percentage 25-75
456    swing: u8,
457    play_mode: u8,
458    track_speed: TrackSpeed,
459    // This is the default variation when the track was saved
460    variation: u8,
461    // This is a map of what variations existed when this track was saved. Not sure why it exists.
462    variations: Vec<bool>,
463    // TODO, unknown value:
464    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(); // discard
495                    }
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    /// Numerator, Denominator
524    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    /// Step number, 0 indexed
543    pub number: usize,
544    /// Sample number
545    pub sample: u16,
546    /// Midi note number
547    pub note: u8,
548    /// 0db at 7600; 200 = 1db
549    pub volume: u16,
550    /// -10000 is hard L, 10000 is hard right; 100 = 1%
551    pub pan: i16,
552    /// -10000 is LP100; 10000 is HP100; 100 = 1%
553    pub filter_cutoff: i16,
554    /// 10000 is 100%; 100 = 1%
555    pub filter_resonance: u16,
556    /// 10000 is 100%; 100 = 1%
557    pub overdrive: u16,
558    /// 4-16
559    pub bit_depth: u8,
560    /// -10000 is -11/24; 10000 is +11/24
561    pub micro_move: i16,
562    /// 10000 is 100%; 100 = 1%
563    pub reverb: i16,
564    pub delay: i16,
565    /// 0: start of sample; 32767: end of sample
566    pub sample_start: i16,
567    pub sample_end: i16,
568    /// 10000 is 100%; 100 = 1%
569    pub sample_attack: u16,
570    pub sample_decay: u16,
571    /// Used for display/randomize only; 0xFFFF = All samples
572    pub sample_folder: u16,
573    /// 0 = Off
574    pub repeat_type: u16,
575    pub repeat_grid: u16,
576    /// 0 = Always
577    pub chance_type: u16,
578    /// 0 = Play Step
579    pub chance_action: u16,
580    /// -10000 is -100 cents; 10000 is +100 cents; 100 = 1 cent
581    pub micro_tune: i16,
582
583    pub rest: Vec<u8>, // TODO
584}
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); // first byte tag (0x0A)
589        let len = reader.read_variable_quantity(); // Length of step data
590
591        let start_pos = reader.pos();
592        // println!("{}nth step, length {} ({:02x})", number, len, len);
593        assert_eq!(reader.read(), 0x0A); // Second tag (0x0A)
594        let num_elements = reader.read_variable_quantity(); // Length of step data
595        assert_eq!(num_elements, 44); // I've never seen a value that's not 44
596
597        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        // Rest appears to be two empty bytes for empty notes and 8 bytes otherwise
621        let rest = reader.read_bytes(len - bytes_advanced); // Unknown data
622
623        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        // Alternate, compact format
678        // write!(f, "Step {}: volume({}) note({}) sample({}) start/end({}-{}) attack/decay({}-{}) pan({}) filter_cutoff({}) resonance({}) micromove({}) microtune({}) repeat/type-grid({}-{}) chance/type-action({}-{}) reverb/delay({}-{}) overdrive({}) bit-depth({})", //  rest: {:?} (len: {})
679        //        self.number,
680        //        self.volume,
681        //        self.note,
682        //        self.sample,
683        //        self.sample_start,
684        //        self.sample_end,
685        //        self.sample_attack,
686        //        self.sample_decay,
687        //        self.pan,
688        //        self.filter_cutoff,
689        //        self.filter_resonance,
690        //        self.micro_move,
691        //        self.micro_tune,
692        //        self.repeat_type,
693        //        self.repeat_grid,
694        //        self.chance_type,
695        //        self.chance_action,
696        //        self.reverb,
697        //        self.delay,
698        //        self.overdrive,
699        //        self.bit_depth,
700        //        // &self.rest, self.rest.len()
701        // )
702    }
703}
704
705#[derive(PartialEq, Clone)]
706pub struct MidiStep {
707    /// Step number, 0 indexed
708    pub number: usize,
709    /// Sample number
710    pub channel: MidiChannel,
711    pub program: Option<u8>,
712    /// Midi note number
713    pub note: u8,
714    pub velocity: u8,
715    /// Note length in 60ths of a quarter note.
716    pub note_length: u16,
717    // Chord enum value
718    pub chord: i16,
719    /// -10000 is -11/24; 10000 is +11/24
720    pub micro_move: i16,
721    /// -10000 is -100 cents; 10000 is +100 cents; 100 = 1 cent
722    pub pitch_bend: Option<i16>,
723
724    /// Midi CC values
725    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    /// Used for display/randomize only; 0xFFFF = All samples
735    /// 0 = Off
736    pub repeat_type: u16,
737    pub repeat_grid: u16,
738    /// 0 = Always
739    pub chance_type: u16,
740    /// 0 = Play Step
741    pub chance_action: u16,
742
743    pub rest: Vec<u8>, // TODO
744}
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); // first byte tag (0x0A)
749        let len = reader.read_variable_quantity(); // Length of step data
750
751        let start_pos = reader.pos();
752        // println!("{}nth step, length {} ({:02x})", number, len, len);
753        assert_eq!(reader.read(), 0x0A); // Second tag (0x0A)
754        let num_elements = reader.read_variable_quantity(); // Length of step data
755        assert_eq!(num_elements, 44); // I've never seen a value that's not 44
756
757        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)); // unused
769        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        // First five bytes are unknown. Last 3 are a bitmask when the note exists
781        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            // This is madness :S
789            // And also not really ideal. We probably shouldn't default to 0?
790            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            // This is "Off", so I don't think None is necessary
817            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            // There are 10 bytes that can't be unset, and thus can't be inferred
831        } 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        // Alternate, compact format
897        // write!(f, "MidiStep {}: note({}) velocity({}) channel({:?}) program({:?}) note_length({}) micromove({}) pitch_bend({:?}) CC(12:{:?}|13:{:?}|17:{:?}|19:{:?}|22:{:?}|71:{:?}|74:{:?}|75:{:?})  repeat/type-grid({}-{}) chance/type-action({}-{})", // rest: {:?} (len: {}) \n{:b} {:b} {:b}",
898        //        self.number,
899        //        self.note,
900        //        self.velocity,
901        //        self.channel,
902        //        self.program,
903        //        self.note_length,
904        //        self.micro_move,
905        //        self.pitch_bend,
906        //        self.cc12,
907        //        self.cc13,
908        //        self.cc17,
909        //        self.cc19,
910        //        self.cc22,
911        //        self.cc71,
912        //        self.cc74,
913        //        self.cc75,
914        //        self.repeat_type,
915        //        self.repeat_grid,
916        //        self.chance_type,
917        //        self.chance_action,
918        //        // &self.rest, self.rest.len(),
919        //        // self.rest[5.min(self.rest.len()-1)],
920        //        // self.rest[6.min(self.rest.len()-1)],
921        //        // self.rest[7.min(self.rest.len()-1)],
922        // )
923    }
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}