This repository has no description
1use super::sync::SyncData;
2use serde::{Deserialize, Serialize};
3use std::{
4 collections::HashMap,
5 fmt::Display,
6 fs::File,
7 io::{BufReader, Write},
8 path::{Path, PathBuf},
9};
10
11#[derive(Debug, Deserialize, Serialize)]
12pub struct Stem {
13 pub amplitude_db: Vec<f32>,
14 /// max amplitude of this stem
15 pub amplitude_max: f32,
16 /// in milliseconds
17 pub duration_ms: usize,
18
19 #[serde(default)]
20 pub notes: HashMap<usize, Vec<Note>>,
21
22 #[serde(default)]
23 pub name: String,
24}
25
26impl Stem {
27 pub fn load_from_cbor(path: &str) -> Stem {
28 let file = File::open(path).unwrap();
29 let reader = BufReader::new(file);
30 let stem: Stem = serde_cbor::from_reader(reader).unwrap();
31 stem
32 }
33
34 pub fn save_to_cbor(&self, path: &str) {
35 let mut file = File::create(path).unwrap();
36 let bytes = serde_cbor::to_vec(&self).unwrap();
37 file.write_all(&bytes).unwrap();
38 }
39
40 pub fn cbor_path(path: PathBuf, name: String) -> String {
41 format!(
42 "{}/{}.cbor",
43 path.parent().unwrap_or(Path::new("./")).to_string_lossy(),
44 name,
45 )
46 }
47}
48
49#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
50pub struct Note {
51 pub pitch: u8,
52 pub velocity: u8,
53 pub tick: u32,
54}
55
56impl Note {
57 pub fn symbol(&self) -> String {
58 let scale = vec![
59 "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "B",
60 ];
61 let (octave, scale_index) = (
62 self.pitch as usize / scale.len(),
63 self.pitch as usize % scale.len(),
64 );
65 format!("{}{}", scale[scale_index], octave)
66 }
67
68 pub fn is_off(&self) -> bool {
69 self.velocity == 0
70 }
71
72 pub fn is_on(&self) -> bool {
73 !self.is_off()
74 }
75}
76
77impl Display for SyncData {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 write!(f, "SyncData @ {} bpm, {} stems", self.bpm, self.stems.len())
80 }
81}
82
83#[derive(Debug, Clone, Default)]
84pub struct AudioSyncPaths {
85 pub stems: String,
86 pub landmarks: String,
87 pub complete: String,
88 pub bpm: String,
89 pub midi: String,
90}
91
92pub type AudioStemToMIDITrack<'a> = HashMap<&'a str, &'a str>;
93
94pub enum MusicalDurationUnit {
95 Beats,
96 Halfs,
97 Thirds,
98 Quarters,
99 Eighths,
100 Sixteenths,
101}
102
103#[derive(Debug)]
104pub struct StemAtInstant {
105 pub amplitude: f32,
106 pub amplitude_max: f32,
107 pub duration: usize,
108 pub velocity_max: u8,
109 pub notes: Vec<Note>,
110}
111impl StemAtInstant {
112 pub fn amplitude_relative(&self) -> f32 {
113 self.amplitude / self.amplitude_max
114 }
115
116 pub fn velocity_relative(&self) -> f32 {
117 self.notes.iter().map(|n| n.velocity).sum::<u8>() as f32
118 / self.notes.len() as f32
119 / self.velocity_max as f32
120 }
121}