Skip to content

Commit

Permalink
Count passed notes properly
Browse files Browse the repository at this point in the history
  • Loading branch information
arduano committed Oct 19, 2023
1 parent 6255c3a commit 030573d
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 88 deletions.
40 changes: 15 additions & 25 deletions src/gui/window/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::{gui::window::GuiWasabiWindow, midi::MIDIFileBase};
pub struct GuiMidiStats {
time_passed: f64,
time_total: f64,
notes_total: u64,
notes_on_screen: u64,
voice_count: u64,
}
Expand All @@ -15,7 +14,6 @@ impl GuiMidiStats {
GuiMidiStats {
time_passed: 0.0,
time_total: 0.0,
notes_total: 0,
notes_on_screen: 0,
voice_count: 0,
}
Expand Down Expand Up @@ -59,7 +57,7 @@ pub fn draw_stats(win: &mut GuiWasabiWindow, ctx: &Context, pos: Pos2, mut stats
let mut length_sec: u64 = 0;
let mut length_min: u64 = 0;

let mut load_type = -1; // 0=RAM, 1=Live
let mut note_stats = Default::default();

if let Some(midi_file) = win.midi_file.as_mut() {
stats.time_total = if let Some(length) = midi_file.midi_length() {
Expand All @@ -83,14 +81,7 @@ pub fn draw_stats(win: &mut GuiWasabiWindow, ctx: &Context, pos: Pos2, mut stats
time_sec = stats.time_passed as u64 % 60;
time_min = stats.time_passed as u64 / 60;

stats.notes_total = midi_file.stats().total_notes;

// FIXME: Use an enum instead lmao
match midi_file {
crate::midi::MIDIFileUnion::InRam(..) => load_type = 0,
crate::midi::MIDIFileUnion::Cake(..) => load_type = 0,
crate::midi::MIDIFileUnion::Live(..) => load_type = 1,
}
note_stats = midi_file.stats();
}

ui.horizontal(|ui| {
Expand Down Expand Up @@ -130,21 +121,20 @@ pub fn draw_stats(win: &mut GuiWasabiWindow, ctx: &Context, pos: Pos2, mut stats
});
});

match load_type {
1 => {
ui.horizontal(|ui| {
ui.monospace("Notes:");
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.monospace(format!("{}", 0));
});
});
}
0 => {
ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
ui.monospace(format!("0 / {}", stats.notes_total));
});
fn num_or_q(num: Option<impl ToString>) -> String {
if let Some(num) = num {
num.to_string()
} else {
"?".to_string()
}
_ => {}
}

ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
ui.monospace(format!(
"{} / {}",
num_or_q(note_stats.passed_notes),
num_or_q(note_stats.total_notes)
));
});
});
}
14 changes: 13 additions & 1 deletion src/midi/cake/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,19 @@ impl MIDIFileBase for CakeMIDIFile {
}

fn stats(&self) -> MIDIFileStats {
MIDIFileStats::new(self.note_count)
let time = self.timer.get_time().as_secs_f64();
let time_int = (time * self.ticks_per_second as f64) as u32;

let passed_notes = self
.key_blocks()
.iter()
.map(|b| b.get_notes_passed_at(time_int) as u64)
.sum();

MIDIFileStats {
total_notes: Some(self.note_count),
passed_notes: Some(passed_notes),
}
}

fn signature(&self) -> &MIDIFileUniqueSignature {
Expand Down
7 changes: 7 additions & 0 deletions src/midi/live/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@ pub struct InRamNoteColumnViewData {
/// Exclusive end block for when notes go outside of view.
/// We iterate over notes backwards, so we start at the block before this one and iterate to 0.
pub end_block: usize,

/// The number of blocks that have passed the keyboard in the current blocks vec
pub blocks_passed_keyboard_index: usize,
/// The number of notes that have passed the keyboard overall
pub notes_passed_keyboard: u64,
}

impl InRamNoteColumnViewData {
pub fn new() -> Self {
InRamNoteColumnViewData {
rendered_notes: 0,
end_block: 0,
blocks_passed_keyboard_index: 0,
notes_passed_keyboard: 0,
}
}
}
Expand Down
40 changes: 23 additions & 17 deletions src/midi/live/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::{
sync::{atomic::Ordering, Arc, RwLock},
sync::{Arc, RwLock},
thread,
};

use atomic_float::AtomicF64;
use midi_toolkit::{io::MIDIFile as TKMIDIFile, sequence::event::get_channels_array_statistics};

use crate::audio_playback::SimpleTemporaryPlayer;
Expand All @@ -23,10 +22,15 @@ pub mod column;
mod parse;
pub mod view;

struct ParseStats {
length: f64,
note_count: u64,
}

pub struct LiveLoadMIDIFile {
view_data: LiveNoteViewData,
timer: TimeKeeper,
length: Arc<AtomicF64>,
stats: Arc<RwLock<Option<ParseStats>>>,
signature: MIDIFileUniqueSignature,
}

Expand All @@ -40,18 +44,19 @@ impl LiveLoadMIDIFile {

let midi = TKMIDIFile::open_from_stream(file, None).unwrap();

let parse_length_outer = Arc::new(AtomicF64::new(f64::NAN));
let parse_length = parse_length_outer.clone();
let stats_outer = Arc::new(RwLock::new(None));
let stats = stats_outer.clone();

let ppq = midi.ppq();
let tracks = midi.iter_all_tracks().collect();
thread::spawn(move || {
let stats = get_channels_array_statistics(tracks);
if let Ok(stats) = stats {
parse_length.store(
stats.calculate_total_duration(ppq).as_secs_f64(),
Ordering::Relaxed,
);
let mut parser_stats = stats_outer.write().unwrap();
*parser_stats = Some(ParseStats {
length: stats.calculate_total_duration(ppq).as_secs_f64(),
note_count: stats.note_count(),
});
}
});

Expand All @@ -63,20 +68,16 @@ impl LiveLoadMIDIFile {
LiveLoadMIDIFile {
view_data: file,
timer,
length: parse_length_outer,
stats,
signature,
}
}
}

impl MIDIFileBase for LiveLoadMIDIFile {
fn midi_length(&self) -> Option<f64> {
let value = self.length.load(Ordering::Relaxed);
if value.is_nan() {
None
} else {
Some(value)
}
let data = self.stats.read().unwrap();
data.as_ref().map(|data| data.length)
}

fn parsed_up_to(&self) -> Option<f64> {
Expand All @@ -96,7 +97,12 @@ impl MIDIFileBase for LiveLoadMIDIFile {
}

fn stats(&self) -> MIDIFileStats {
MIDIFileStats::new(0)
let stats = self.stats.read().unwrap();

MIDIFileStats {
passed_notes: Some(self.view_data.passed_notes()),
total_notes: stats.as_ref().map(|stats| stats.note_count),
}
}

fn signature(&self) -> &MIDIFileUniqueSignature {
Expand Down
17 changes: 17 additions & 0 deletions src/midi/live/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,19 @@ impl LiveNoteViewData {
data.end_block += 1;
}

while data.blocks_passed_keyboard_index < blocks.len() {
if blocks[data.blocks_passed_keyboard_index].start > new_view_range.start {
break;
}
data.notes_passed_keyboard +=
blocks[data.blocks_passed_keyboard_index].notes.len() as u64;
data.blocks_passed_keyboard_index += 1;
}

while let Some(block) = blocks.front() {
if block.max_end() < new_view_range.start {
data.rendered_notes -= block.notes.len();
data.blocks_passed_keyboard_index -= 1;
blocks.pop_front();

// Unconditionally reduce this value because blocks that have an
Expand All @@ -93,6 +103,13 @@ impl LiveNoteViewData {
pub fn parse_time(&self) -> f64 {
self.parser.parse_time()
}

pub fn passed_notes(&self) -> u64 {
self.columns
.iter()
.map(|column| column.data.notes_passed_keyboard)
.sum()
}
}

pub struct LiveNoteColumnView<'a> {
Expand Down
8 changes: 7 additions & 1 deletion src/midi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ use rand::Rng;

pub use cake::{blocks::CakeBlock, intvec4::IntVector4, CakeMIDIFile, CakeSignature};
pub use live::LiveLoadMIDIFile;
pub use ram::{InRamMIDIFile, MIDIFileStats};
pub use ram::InRamMIDIFile;

use self::shared::timer::TimeKeeper;

#[derive(Debug, Clone, Copy, Default)]
pub struct MIDIFileStats {
pub total_notes: Option<u64>,
pub passed_notes: Option<u64>,
}

/// A struct that represents the view range of a midi screen render
#[derive(Debug, Clone, Copy, Default)]
pub struct MIDIViewRange {
Expand Down
18 changes: 14 additions & 4 deletions src/midi/ram/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,27 @@ use std::ops::Range;
use super::block::InRamNoteBlock;

pub struct InRamNoteColumnViewData {
pub notes_to_end: usize,
pub notes_to_start: usize,
/// Number of notes from the beginning of the midi to the start of the render view
pub notes_to_render_end: u64,
/// Number of notes from the beginning of the midi to the end of the render view
pub notes_to_render_start: u64,
/// The range of blocks that are in the view
pub block_range: Range<usize>,

/// Number of notes that have passed the keyboard
pub notes_to_keyboard: u64,
/// Number of blocks that have passed the keyboard
pub blocks_to_keyboard: usize,
}

impl InRamNoteColumnViewData {
pub fn new() -> Self {
InRamNoteColumnViewData {
notes_to_end: 0,
notes_to_start: 0,
notes_to_render_end: 0,
notes_to_render_start: 0,
block_range: 0..0,
notes_to_keyboard: 0,
blocks_to_keyboard: 0,
}
}
}
Expand Down
22 changes: 6 additions & 16 deletions src/midi/ram/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
use self::view::{InRamCurrentNoteViews, InRamNoteViewData};

use super::{
shared::timer::TimeKeeper, MIDIFile, MIDIFileBase, MIDIFileUniqueSignature, MIDIViewRange,
shared::timer::TimeKeeper, MIDIFile, MIDIFileBase, MIDIFileStats, MIDIFileUniqueSignature,
MIDIViewRange,
};

pub mod block;
pub mod column;
mod parse;
pub mod view;

pub struct MIDIFileStats {
pub total_notes: u64,
pub passed_notes: u64,
}

impl MIDIFileStats {
pub fn new(notes: u64) -> Self {
Self {
total_notes: notes,
passed_notes: 0,
}
}
}

pub struct InRamMIDIFile {
view_data: InRamNoteViewData,
timer: TimeKeeper,
Expand Down Expand Up @@ -55,7 +42,10 @@ impl MIDIFileBase for InRamMIDIFile {
}

fn stats(&self) -> MIDIFileStats {
MIDIFileStats::new(self.note_count)
MIDIFileStats {
total_notes: Some(self.note_count),
passed_notes: Some(self.view_data.passed_notes()),
}
}

fn signature(&self) -> &MIDIFileUniqueSignature {
Expand Down
Loading

0 comments on commit 030573d

Please sign in to comment.