Skip to content

Commit

Permalink
Measures/bar guidelines (#131)
Browse files Browse the repository at this point in the history
* Move GuidelineRenderer out of KeyboardRenderer
* Introduce Horizontal guidelines
* Settings & Config for horizontal guidelines
  • Loading branch information
PolyMeilex authored Jan 14, 2024
1 parent 531dc61 commit 6b7d072
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 61 deletions.
25 changes: 25 additions & 0 deletions midi-file/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct MidiFile {
pub tracks: Arc<[MidiTrack]>,
pub program_track: ProgramTrack,
pub tempo_track: TempoTrack,
pub measures: Arc<[std::time::Duration]>,
}

impl MidiFile {
Expand Down Expand Up @@ -59,6 +60,29 @@ impl MidiFile {
})
.collect();

let measures = {
let last_note_end = tracks
.iter()
.fold(std::time::Duration::ZERO, |last, track| {
if let Some(note) = track.notes.last() {
last.max(note.start + note.duration)
} else {
last
}
});

let mut masures = Vec::new();
let mut time = std::time::Duration::ZERO;
let mut id = 0;
while time <= last_note_end {
time = tempo_track.pulses_to_duration(id * u_per_quarter_note as u64 * 4);
masures.push(time);
id += 1;
}

masures
};

let program_track = ProgramTrack::new(&tracks);

Ok(Self {
Expand All @@ -67,6 +91,7 @@ impl MidiFile {
tracks: tracks.into(),
program_track,
tempo_track,
measures: measures.into(),
})
}
}
34 changes: 28 additions & 6 deletions neothesia-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{default::Default, time::Duration};

use neothesia_core::{
config::Config,
render::{KeyboardRenderer, QuadPipeline, TextRenderer, WaterfallRenderer},
render::{GuidelineRenderer, KeyboardRenderer, QuadPipeline, TextRenderer, WaterfallRenderer},
};
use wgpu_jumpstart::{wgpu, Gpu, TransformUniform, Uniform};

Expand All @@ -12,10 +12,12 @@ struct Recorder {

playback: midi_file::PlaybackState,

bg_quad_pipeline: QuadPipeline,
quad_pipeline: QuadPipeline,
keyboard: KeyboardRenderer,
waterfall: WaterfallRenderer,
text: TextRenderer,
guidelines: GuidelineRenderer,

config: Config,
width: u32,
Expand Down Expand Up @@ -74,6 +76,7 @@ impl Recorder {
wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
);

let bg_quad_pipeline = QuadPipeline::new(&gpu, &transform_uniform);
let quad_pipeline = QuadPipeline::new(&gpu, &transform_uniform);

let keyboard_layout = get_layout(
Expand All @@ -82,11 +85,17 @@ impl Recorder {
piano_math::KeyboardRange::new(config.piano_range()),
);

let mut keyboard =
KeyboardRenderer::new(keyboard_layout.clone(), config.vertical_guidelines);

let mut keyboard = KeyboardRenderer::new(keyboard_layout.clone());
keyboard.position_on_bottom_of_parent(height as f32);

let guidelines = GuidelineRenderer::new(
keyboard.layout().clone(),
*keyboard.pos(),
config.vertical_guidelines,
config.horizontal_guidelines,
midi.measures.clone(),
);

let mut waterfall = WaterfallRenderer::new(
&gpu,
&midi.tracks,
Expand All @@ -108,10 +117,12 @@ impl Recorder {

playback,

bg_quad_pipeline,
quad_pipeline,
keyboard,
waterfall,
text,
guidelines,

config,
width,
Expand All @@ -123,8 +134,17 @@ impl Recorder {
let events = self.playback.update(delta);
file_midi_events(&mut self.keyboard, &self.config, &events);

self.waterfall
.update(&self.gpu.queue, time_without_lead_in(&self.playback));
let time = time_without_lead_in(&self.playback);

self.bg_quad_pipeline.clear();
self.guidelines.update(
&mut self.bg_quad_pipeline,
self.config.animation_speed,
time,
);
self.bg_quad_pipeline.prepare(&self.gpu.queue);

self.waterfall.update(&self.gpu.queue, time);

self.quad_pipeline.clear();
self.keyboard
Expand Down Expand Up @@ -163,6 +183,8 @@ impl Recorder {
occlusion_query_set: None,
});

self.bg_quad_pipeline
.render(&self.transform_uniform, &mut rpass);
self.waterfall.render(&self.transform_uniform, &mut rpass);
self.quad_pipeline
.render(&self.transform_uniform, &mut rpass);
Expand Down
8 changes: 8 additions & 0 deletions neothesia-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub struct Config {
#[serde(default = "default_vertical_guidelines")]
pub vertical_guidelines: bool,

#[serde(default = "default_horizontal_guidelines")]
pub horizontal_guidelines: bool,

#[serde(default = "default_color_schema")]
pub color_schema: Vec<ColorSchema>,

Expand Down Expand Up @@ -68,6 +71,7 @@ impl Config {
animation_speed: default_animation_speed(),
playback_offset: default_playback_offset(),
vertical_guidelines: default_vertical_guidelines(),
horizontal_guidelines: default_horizontal_guidelines(),
color_schema: default_color_schema(),
background_color: Default::default(),
output: default_output(),
Expand Down Expand Up @@ -122,6 +126,10 @@ fn default_vertical_guidelines() -> bool {
false
}

fn default_horizontal_guidelines() -> bool {
false
}

fn default_color_schema() -> Vec<ColorSchema> {
vec![
ColorSchema {
Expand Down
123 changes: 123 additions & 0 deletions neothesia-core/src/render/guidelines.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use std::{sync::Arc, time::Duration};

use crate::{
render::{QuadInstance, QuadPipeline},
utils::Point,
};

pub struct GuidelineRenderer {
pos: Point<f32>,

layout: piano_math::KeyboardLayout,
vertical_guidelines: bool,
horizontal_guidelines: bool,

cache: Vec<QuadInstance>,
measures: Arc<[Duration]>,
}

impl GuidelineRenderer {
pub fn new(
layout: piano_math::KeyboardLayout,
pos: Point<f32>,
vertical_guidelines: bool,
horizontal_guidelines: bool,
measures: Arc<[Duration]>,
) -> Self {
Self {
pos,
layout,
vertical_guidelines,
horizontal_guidelines,
cache: Vec::new(),
measures,
}
}

pub fn set_pos(&mut self, pos: Point<f32>) {
self.pos = pos;
self.cache.clear();
}

pub fn set_layout(&mut self, layout: piano_math::KeyboardLayout) {
self.layout = layout;
self.cache.clear();
}

/// Reupload instances to GPU
fn reupload(&mut self) {
if !self.vertical_guidelines {
return;
}

for key in self
.layout
.keys
.iter()
.filter(|key| key.note_id() == 0 || key.note_id() == 5)
{
let x = self.pos.x + key.x();
let y = 0.0;

let w = 1.0;
let h = f32::MAX;

let color = if key.note_id() == 0 {
[0.2, 0.2, 0.2, 1.0]
} else {
[0.05, 0.05, 0.05, 1.0]
};

self.cache.push(QuadInstance {
position: [x, y],
size: [w, h],
color,
border_radius: [0.0, 0.0, 0.0, 0.0],
});
}
}

fn update_horizontal_guidelines(
&mut self,
quads: &mut QuadPipeline,
animation_speed: f32,
time: f32,
) {
for masure in self
.measures
.iter()
.skip_while(|bar| bar.as_secs_f32() < time)
{
let x = 0.0;
let y = self.pos.y - (masure.as_secs_f32() - time) * animation_speed;

let w = f32::MAX;
let h = 1.0;

if y < 0.0 {
break;
}

quads.instances().push(QuadInstance {
position: [x, y],
size: [w, h],
color: [0.05, 0.05, 0.05, 1.0],
border_radius: [0.0, 0.0, 0.0, 0.0],
});
}
}

pub fn update(&mut self, quads: &mut QuadPipeline, animation_speed: f32, time: f32) {
if self.cache.is_empty() {
self.reupload();
}

if self.horizontal_guidelines {
self.update_horizontal_guidelines(quads, animation_speed, time);
}

for quad in self.cache.iter() {
quads.instances().push(*quad);
}
}
}
29 changes: 1 addition & 28 deletions neothesia-core/src/render/keyboard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ pub struct KeyboardRenderer {
key_states: Vec<KeyState>,

layout: piano_math::KeyboardLayout,
vertical_guidelines: bool,

cache: Vec<QuadInstance>,
}

impl KeyboardRenderer {
pub fn new(layout: piano_math::KeyboardLayout, vertical_guidelines: bool) -> Self {
pub fn new(layout: piano_math::KeyboardLayout) -> Self {
let key_states: Vec<KeyState> = layout
.range
.iter()
Expand All @@ -37,7 +36,6 @@ impl KeyboardRenderer {
key_states,

layout,
vertical_guidelines,
cache,
}
}
Expand Down Expand Up @@ -107,31 +105,6 @@ impl KeyboardRenderer {
let id = key.id();
let color = self.key_states[id].color();

if self.vertical_guidelines {
// Horizontal guides
// TODO: Does not really fit in keyboard renderer
if key.note_id() == 0 || key.note_id() == 5 {
let x = self.pos.x + key.x();
let y = 0.0;

let w = 1.0;
let h = f32::MAX;

let color = if key.note_id() == 0 {
[0.2, 0.2, 0.2, 1.0]
} else {
[0.05, 0.05, 0.05, 1.0]
};

instances.push(QuadInstance {
position: [x, y],
size: [w, h],
color,
border_radius: [0.0, 0.0, 0.0, 0.0],
});
}
}

instances.push(key_state::to_quad(key, color, self.pos));
}

Expand Down
2 changes: 2 additions & 0 deletions neothesia-core/src/render/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod background_animation;
mod guidelines;
mod keyboard;
mod quad;
mod text;
mod waterfall;

pub use background_animation::BgPipeline;
pub use guidelines::GuidelineRenderer;
pub use keyboard::{KeyState as KeyboardKeyState, KeyboardRenderer};
pub use quad::{QuadInstance, QuadPipeline};
pub use text::TextRenderer;
Expand Down
Loading

0 comments on commit 6b7d072

Please sign in to comment.