This repository has no description
0

Configure Feed

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

1use super::animation::{AnimationUpdateFunction, LayerAnimationUpdateFunction}; 2use super::hooks::{LaterHook, LaterRenderFunction}; 3use super::Animation; 4use crate::synchronization::audio::{Note, StemAtInstant}; 5use crate::synchronization::sync::SyncData; 6use itertools::Itertools; 7use nanoid::nanoid; 8use std::fs::{self}; 9use std::path::PathBuf; 10 11pub struct Context<'a, AdditionalContext = ()> { 12 pub frame: usize, 13 pub beat: usize, 14 pub beat_fractional: f32, 15 pub timestamp: String, 16 pub ms: usize, 17 pub bpm: usize, 18 pub syncdata: &'a SyncData, 19 pub audiofile: PathBuf, 20 pub later_hooks: Vec<LaterHook<AdditionalContext>>, 21 pub extra: AdditionalContext, 22 pub duration_override: Option<usize>, 23} 24 25impl<C> Context<'_, C> { 26 pub fn stem(&self, name: &str) -> StemAtInstant { 27 let stems = &self.syncdata.stems; 28 if !stems.contains_key(name) { 29 panic!( 30 "No stem named {:?} found. Available stems:\n{}\n", 31 name, 32 stems 33 .keys() 34 .sorted() 35 .fold(String::new(), |acc, k| format!("{acc}\n\t{k}")) 36 ); 37 } 38 StemAtInstant { 39 amplitude: *stems[name].amplitude_db.get(self.ms).unwrap_or(&0.0), 40 amplitude_max: stems[name].amplitude_max, 41 velocity_max: stems[name] 42 .notes 43 .get(&self.ms) 44 .iter() 45 .map(|notes| { 46 notes.iter().map(|note| note.velocity).max().unwrap_or(0) 47 }) 48 .max() 49 .unwrap_or(0), 50 duration: stems[name].duration_ms, 51 notes: stems[name].notes.get(&self.ms).cloned().unwrap_or(vec![]), 52 } 53 } 54 55 pub fn notes_of_stem(&self, name: &str) -> impl Iterator<Item = Note> + '_ { 56 let stem = &self.syncdata.stems[name]; 57 stem.notes 58 .get(&self.ms) 59 .into_iter() 60 .flat_map(|notes| notes.iter().cloned()) 61 } 62 63 pub fn dump_syncdata(&self, to: PathBuf) -> anyhow::Result<()> { 64 Ok(serde_cbor::to_writer(fs::File::create(to)?, self.syncdata)?) 65 } 66 67 pub fn marker(&self) -> String { 68 self.syncdata 69 .markers 70 .get(&self.ms) 71 .unwrap_or(&"".to_string()) 72 .to_string() 73 } 74 75 pub fn duration_ms(&self) -> usize { 76 match self.duration_override { 77 Some(duration) => duration, 78 None => self 79 .syncdata 80 .stems 81 .values() 82 .map(|stem| stem.duration_ms) 83 .max() 84 .unwrap(), 85 } 86 } 87 88 pub fn later_frames( 89 &mut self, 90 delay: usize, 91 render_function: &'static LaterRenderFunction, 92 ) { 93 let current_frame = self.frame; 94 95 self.later_hooks.insert( 96 0, 97 LaterHook { 98 once: true, 99 when: Box::new(move |_, context, _previous_beat| { 100 context.frame >= current_frame + delay 101 }), 102 render_function: Box::new(render_function), 103 }, 104 ); 105 } 106 107 pub fn later_ms( 108 &mut self, 109 delay: usize, 110 render_function: &'static LaterRenderFunction, 111 ) { 112 let current_ms = self.ms; 113 114 self.later_hooks.insert( 115 0, 116 LaterHook { 117 once: true, 118 when: Box::new(move |_, context, _previous_beat| { 119 context.ms >= current_ms + delay 120 }), 121 render_function: Box::new(render_function), 122 }, 123 ); 124 } 125 126 pub fn later_beats( 127 &mut self, 128 delay: f32, 129 render_function: &'static LaterRenderFunction, 130 ) { 131 let current_beat = self.beat; 132 133 self.later_hooks.insert( 134 0, 135 LaterHook { 136 once: true, 137 when: Box::new(move |_, context, _previous_beat| { 138 context.beat_fractional >= current_beat as f32 + delay 139 }), 140 render_function: Box::new(render_function), 141 }, 142 ); 143 } 144 145 /// duration is in milliseconds 146 pub fn start_animation(&mut self, duration: usize, animation: Animation) { 147 let start_ms = self.ms; 148 let ms_range = start_ms..(start_ms + duration); 149 150 self.later_hooks.push(LaterHook { 151 once: false, 152 when: Box::new(move |_, ctx, _| ms_range.contains(&ctx.ms)), 153 render_function: Box::new(move |canvas, ms| { 154 let t = (ms - start_ms) as f32 / duration as f32; 155 (animation.update)(t, canvas, ms) 156 }), 157 }) 158 } 159 160 /// duration is in milliseconds 161 pub fn animate( 162 &mut self, 163 duration: usize, 164 f: &'static AnimationUpdateFunction, 165 ) { 166 self.start_animation( 167 duration, 168 Animation::new(format!("unnamed animation {}", nanoid!()), f), 169 ); 170 } 171 172 pub fn animate_layer( 173 &mut self, 174 layer: &'static str, 175 duration: usize, 176 f: &'static LayerAnimationUpdateFunction, 177 ) { 178 let animation = Animation { 179 name: format!("unnamed animation {}", nanoid!()), 180 update: Box::new(move |progress, canvas, ms| { 181 (f)(progress, canvas.layer(layer), ms)?; 182 canvas.layer(layer).flush(); 183 Ok(()) 184 }), 185 }; 186 187 self.start_animation(duration, animation); 188 } 189}