This repository has no description
0

Configure Feed

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

♻️ Convert many Context fields to methods

Since they were mostly derived from Context.ms and the BPM

+79 -68
+2 -2
src/main.rs
··· 130 130 .set("feur", Object::Dot(center).colored(Color::Red)); 131 131 canvas.root().set( 132 132 "text", 133 - Object::CenteredText(center, ctx.timestamp.to_string(), 30.0) 133 + Object::CenteredText(center, ctx.timestamp(), 30.0) 134 134 .colored(Color::White), 135 135 ); 136 136 canvas.root().set( 137 137 "beat", 138 138 Object::CenteredText( 139 139 center.translated(0, 3), 140 - format!("beat {}", ctx.beat), 140 + format!("beat {}", ctx.beat()), 141 141 30.0, 142 142 ) 143 143 .colored(Color::Cyan),
+26
src/ui.rs
··· 1 1 use crate::video::engine::EngineProgression; 2 + use chrono::DateTime; 2 3 use console::Style; 3 4 use indicatif::{ProgressBar, ProgressStyle}; 4 5 use itertools::Itertools; ··· 153 154 }) 154 155 .join(", ") 155 156 } 157 + 158 + pub fn format_duration(duration: impl IntoTimestamp) -> String { 159 + format!( 160 + "{}", 161 + DateTime::from_timestamp_millis(duration.as_millis() as i64) 162 + .unwrap() 163 + .format("%H:%M:%S%.3f") 164 + ) 165 + } 166 + 167 + trait IntoTimestamp { 168 + fn as_millis(&self) -> usize; 169 + } 170 + 171 + impl IntoTimestamp for usize { 172 + fn as_millis(&self) -> usize { 173 + *self 174 + } 175 + } 176 + 177 + // impl IntoTimestamp for std::time::Duration { 178 + // fn as_millis(&self) -> usize { 179 + // self.as_millis() as usize 180 + // } 181 + // }
+31 -9
src/video/context.rs
··· 3 3 use super::Animation; 4 4 use crate::synchronization::audio::{Note, StemAtInstant}; 5 5 use crate::synchronization::sync::SyncData; 6 + use crate::ui; 6 7 use itertools::Itertools; 7 8 use nanoid::nanoid; 8 9 use std::fmt::Display; ··· 11 12 use std::time::Duration; 12 13 13 14 pub struct Context<'a, AdditionalContext = ()> { 14 - pub frame: usize, 15 - pub beat: usize, 16 - pub beat_fractional: f32, 17 - pub timestamp: String, 18 15 pub ms: usize, 16 + pub fps: usize, 19 17 pub bpm: usize, 20 18 pub syncdata: &'a SyncData, 21 19 pub audiofile: PathBuf, ··· 23 21 pub extra: AdditionalContext, 24 22 pub duration_override: Option<usize>, 25 23 pub current_scene: Option<String>, 26 - pub scene_frame: Option<usize>, 27 24 pub scene_started_at_ms: Option<usize>, 28 25 } 29 26 30 27 impl<C> Context<'_, C> { 28 + pub fn timestamp(&self) -> String { 29 + ui::format_duration(self.ms).to_string() 30 + } 31 + 32 + pub fn beat_fractional(&self) -> f32 { 33 + (self.bpm * self.ms) as f32 / (1000.0 * 60.0) 34 + } 35 + 36 + pub fn beat(&self) -> usize { 37 + self.beat_fractional() as usize 38 + } 39 + 40 + pub fn frame(&self) -> usize { 41 + self.ms_to_frame(self.ms) 42 + } 43 + 44 + pub fn scene_frame(&self) -> Option<usize> { 45 + self.scene_started_at_ms 46 + .map(|start_ms| self.ms_to_frame(self.ms - start_ms)) 47 + } 48 + 49 + pub fn ms_to_frame(&self, ms: usize) -> usize { 50 + self.fps * ms / 1000 51 + } 52 + 31 53 pub fn stem(&self, name: &str) -> StemAtInstant { 32 54 let stems = &self.syncdata.stems; 33 55 if !stems.contains_key(name) { ··· 99 121 delay: usize, 100 122 render_function: &'static LaterRenderFunction, 101 123 ) { 102 - let current_frame = self.frame; 124 + let current_frame = self.frame(); 103 125 104 126 self.later_hooks.insert( 105 127 0, 106 128 LaterHook { 107 129 once: true, 108 130 when: Box::new(move |_, context, _previous_beat| { 109 - context.frame >= current_frame + delay 131 + context.frame() >= current_frame + delay 110 132 }), 111 133 render_function: Box::new(render_function), 112 134 }, ··· 137 159 delay: f32, 138 160 render_function: &'static LaterRenderFunction, 139 161 ) { 140 - let current_beat = self.beat; 162 + let current_beat = self.beat(); 141 163 142 164 self.later_hooks.insert( 143 165 0, 144 166 LaterHook { 145 167 once: true, 146 168 when: Box::new(move |_, context, _previous_beat| { 147 - context.beat_fractional >= current_beat as f32 + delay 169 + context.beat_fractional() >= current_beat as f32 + delay 148 170 }), 149 171 render_function: Box::new(render_function), 150 172 },
+10 -22
src/video/engine.rs
··· 1 - use super::{context::Context, hooks::format_duration, Video}; 1 + use super::{context::Context, Video}; 2 2 use crate::rendering::svg; 3 3 use crate::{Canvas, SVGRenderable}; 4 4 use anyhow::Result; ··· 21 21 pub fn engine_progression(&self) -> EngineProgression { 22 22 EngineProgression { 23 23 ms: self.ms, 24 - timestamp: self.timestamp.clone(), 24 + timestamp: self.timestamp(), 25 25 scene_name: self.current_scene.clone(), 26 26 } 27 27 } ··· 37 37 38 38 let mut rendered_frames_count: usize = 0; 39 39 let mut context = Context { 40 - frame: 0, 41 - scene_frame: None, 40 + ms: self.start_rendering_at, 42 41 current_scene: None, 43 - beat: 0, 44 - beat_fractional: 0.0, 45 - timestamp: "00:00:00.000".to_string(), 46 - ms: 0, 42 + fps: self.fps, 47 43 syncdata: &self.syncdata, 48 44 extra: AdditionalContext::default(), 49 45 later_hooks: vec![], ··· 67 63 68 64 for _ in render_ms_range { 69 65 context.ms += 1_usize; 70 - context.timestamp = format_duration(context.ms).to_string(); 71 - context.beat_fractional = 72 - (context.bpm * context.ms) as f32 / (1000.0 * 60.0); 73 - context.beat = context.beat_fractional as usize; 74 - context.frame = self.fps * context.ms / 1000; 75 - context.scene_frame = context 76 - .scene_started_at_ms 77 - .map(|start_ms| self.fps * (context.ms - start_ms) / 1000); 78 66 79 67 let control = controller(&context); 80 68 ··· 145 133 } 146 134 } 147 135 148 - if !skip_rendering && context.frame != previous_rendered_frame { 136 + if !skip_rendering && context.frame() != previous_rendered_frame { 149 137 output.send(EngineOutput::Frame( 150 138 context.engine_progression(), 151 139 canvas.render_to_svg( ··· 158 146 159 147 rendered_frames_count += 1; 160 148 161 - previous_rendered_beat = context.beat; 162 - previous_rendered_frame = context.frame; 149 + previous_rendered_beat = context.beat(); 150 + previous_rendered_frame = context.frame(); 163 151 } 164 152 165 153 if stop_after { 166 154 println!( 167 155 "Stopping rendering as requested after frame {}", 168 - context.frame 156 + context.frame() 169 157 ); 170 158 break; 171 159 } ··· 184 172 let (tx, rx) = std::sync::mpsc::sync_channel::<EngineOutput>(2); 185 173 186 174 self.render(tx, |ctx| { 187 - if ctx.frame == frame_no { 175 + if ctx.frame() == frame_no { 188 176 EngineControl::Finish 189 - } else if ctx.frame < frame_no { 177 + } else if ctx.frame() < frame_no { 190 178 EngineControl::Skip 191 179 } else { 192 180 EngineControl::Stop
+8 -33
src/video/hooks.rs
··· 3 3 use crate::synchronization::audio::MusicalDurationUnit; 4 4 use crate::{Canvas, ColoredObject}; 5 5 use anyhow::Result; 6 - use chrono::{DateTime, NaiveDateTime}; 6 + use chrono::NaiveDateTime; 7 7 use std::{fmt::Formatter, panic}; 8 8 9 9 pub type BeatNumber = usize; ··· 58 58 render_function: &'static RenderFunction<AdditionalContext>, 59 59 ) -> Self { 60 60 self.with_hook(Hook { 61 - when: Box::new(move |_, context, _, _| context.frame == 0), 61 + when: Box::new(move |_, context, _, _| context.frame() == 0), 62 62 render_function: Box::new(render_function), 63 63 }) 64 64 } ··· 87 87 context, 88 88 previous_rendered_beat, 89 89 previous_rendered_frame| { 90 - previous_rendered_frame != context.frame 90 + previous_rendered_frame != context.frame() 91 91 && (context.ms == 0 92 - || previous_rendered_beat != context.beat) 92 + || previous_rendered_beat != context.beat()) 93 93 }, 94 94 ), 95 95 render_function: Box::new(render_function), ··· 113 113 114 114 self.with_hook(Hook { 115 115 when: Box::new(move |_, context, _, _| { 116 - context.beat_fractional % beats < 0.01 116 + context.beat_fractional() % beats < 0.01 117 117 }), 118 118 render_function: Box::new(render_function), 119 119 }) ··· 133 133 ) -> Self { 134 134 self.with_hook(Hook { 135 135 when: Box::new(move |_, context, _, previous_rendered_frame| { 136 - context.frame != previous_rendered_frame && context.frame % n == 0 136 + context.frame() != previous_rendered_frame && context.frame() % n == 0 137 137 }), 138 138 render_function: Box::new(render_function), 139 139 }) ··· 245 245 render_function: &'static RenderFunction<AdditionalContext>, 246 246 ) -> Self { 247 247 self.with_hook(Hook { 248 - when: Box::new(move |_, context, _, _| context.frame == frame), 248 + when: Box::new(move |_, context, _, _| context.frame() == frame), 249 249 render_function: Box::new(render_function), 250 250 }) 251 251 } ··· 270 270 ) -> Self { 271 271 let hook = Hook { 272 272 when: Box::new(move |_, context, _, previous_rendered_frame| { 273 - if previous_rendered_frame == context.frame { 273 + if previous_rendered_frame == context.frame() { 274 274 return false; 275 275 } 276 276 let (precision, criteria_time): (&str, NaiveDateTime) = ··· 341 341 }) 342 342 } 343 343 } 344 - 345 - pub fn format_duration(duration: impl IntoTimestamp) -> String { 346 - format!( 347 - "{}", 348 - DateTime::from_timestamp_millis(duration.as_millis() as i64) 349 - .unwrap() 350 - .format("%H:%M:%S%.3f") 351 - ) 352 - } 353 - 354 - trait IntoTimestamp { 355 - fn as_millis(&self) -> usize; 356 - } 357 - 358 - impl IntoTimestamp for usize { 359 - fn as_millis(&self) -> usize { 360 - *self 361 - } 362 - } 363 - 364 - // impl IntoTimestamp for std::time::Duration { 365 - // fn as_millis(&self) -> usize { 366 - // self.as_millis() as usize 367 - // } 368 - // }
+1 -1
src/video/scene.rs
··· 39 39 ) -> Self { 40 40 self.with_hook(Hook { 41 41 render_function: Box::new(render_function), 42 - when: Box::new(move |_, ctx, _, _| ctx.scene_frame == Some(0)), 42 + when: Box::new(move |_, ctx, _, _| ctx.scene_frame() == Some(0)), 43 43 }) 44 44 } 45 45 }
+1 -1
src/video/video.rs
··· 153 153 pub fn with_init_scene(self, scene: Scene<C>) -> Self { 154 154 let scene_name = scene.name.clone(); 155 155 self.with_scene(scene).with_hook(Hook { 156 - when: Box::new(|_, ctx, _, _| ctx.frame == 0), 156 + when: Box::new(|_, ctx, _, _| ctx.frame() == 0), 157 157 render_function: Box::new(move |_, ctx| { 158 158 ctx.switch_scene(&scene_name); 159 159 Ok(())