experimental SVG-based video rendering engine made for music videos. React to MIDI or arbitrary signals from your DAW through "probe" VSTs
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 130 lines 3.1 kB view raw
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!( 80 f, 81 "SyncData @ {} bpm, {} stems", 82 self.bpm.map_or("?".to_string(), |bpm| bpm.to_string()), 83 self.stems.len() 84 ) 85 } 86} 87 88#[derive(Debug, Clone, Default)] 89pub struct AudioSyncPaths { 90 pub stems: String, 91 pub landmarks: String, 92 pub complete: String, 93 pub bpm: String, 94 pub midi: String, 95} 96 97pub type AudioStemToMIDITrack<'a> = HashMap<&'a str, &'a str>; 98 99pub enum MusicalDurationUnit { 100 Beats, 101 Halves, 102 Thirds, 103 Quarters, 104 Eighths, 105 Sixteenths, 106} 107 108#[derive(Debug)] 109pub struct StemAtInstant { 110 pub amplitude: f32, 111 pub amplitude_max: f32, 112 pub duration: usize, 113 pub velocity_max: u8, 114 pub notes: Vec<Note>, 115 /// How many instants (individual ms values) 116 /// have occurred where this stem played notes 117 /// before this instant (not counting the current instant) 118 pub playcount: usize, 119} 120impl StemAtInstant { 121 pub fn amplitude_relative(&self) -> f32 { 122 self.amplitude / self.amplitude_max 123 } 124 125 pub fn velocity_relative(&self) -> f32 { 126 self.notes.iter().map(|n| n.velocity).sum::<u8>() as f32 127 / self.notes.len() as f32 128 / self.velocity_max as f32 129 } 130}