From 86317ac85c236925043aca217b8c1bb39e1a8aad Mon Sep 17 00:00:00 2001 From: MyBlackMIDIScore Date: Thu, 17 Oct 2024 21:12:17 +0300 Subject: [PATCH 1/5] Add NPS & Polyphony stats --- src/gui/window.rs | 3 + src/gui/window/scene.rs | 1 + src/gui/window/scene/cake_system/mod.rs | 1 + src/gui/window/scene/note_list_system/mod.rs | 101 ++++++++++--------- src/gui/window/stats.rs | 65 ++++++++++++ src/settings/enums.rs | 12 ++- src/settings/mod.rs | 9 +- 7 files changed, 141 insertions(+), 51 deletions(-) diff --git a/src/gui/window.rs b/src/gui/window.rs index 2eee04f..30dc9b7 100644 --- a/src/gui/window.rs +++ b/src/gui/window.rs @@ -41,6 +41,7 @@ pub struct GuiWasabiWindow { keyboard: GuiKeyboard, midi_file: Option, fps: fps::Fps, + nps: stats::NpsCounter, settings_win: SettingsWindow, midi_picker: Option>, @@ -73,6 +74,7 @@ impl GuiWasabiWindow { keyboard: GuiKeyboard::new(), midi_file: None, fps: fps::Fps::new(), + nps: Default::default(), settings_win, midi_picker: None, @@ -307,6 +309,7 @@ impl GuiWasabiWindow { settings.scene.note_speed, ); stats.set_rendered_note_count(result.notes_rendered); + stats.set_polyphony(result.polyphony); render_result_data = Some(result); } }); diff --git a/src/gui/window/scene.rs b/src/gui/window/scene.rs index 9a35c4a..b145939 100644 --- a/src/gui/window/scene.rs +++ b/src/gui/window/scene.rs @@ -55,6 +55,7 @@ pub struct GuiRenderScene { pub struct RenderResultData { pub notes_rendered: u64, + pub polyphony: u64, pub key_colors: Vec>, } diff --git a/src/gui/window/scene/cake_system/mod.rs b/src/gui/window/scene/cake_system/mod.rs index 3cbe861..71ad9f5 100644 --- a/src/gui/window/scene/cake_system/mod.rs +++ b/src/gui/window/scene/cake_system/mod.rs @@ -469,6 +469,7 @@ impl CakeRenderer { RenderResultData { notes_rendered: rendered_notes, + polyphony: 0, key_colors: colors, } } diff --git a/src/gui/window/scene/note_list_system/mod.rs b/src/gui/window/scene/note_list_system/mod.rs index 3dec5f8..172fb3c 100644 --- a/src/gui/window/scene/note_list_system/mod.rs +++ b/src/gui/window/scene/note_list_system/mod.rs @@ -108,6 +108,7 @@ impl NoteRenderer { } let mut notes_pushed = 0; + let mut polyphony = 0; let mut cycle = 0; @@ -120,64 +121,69 @@ impl NoteRenderer { let buffer_writer = UnsafeSyncCell::new(buffer.write().unwrap()); // A system to write multiple note columns into 1 large allocated array in parallel - let written_notes = self.thrad_pool.install(|| { + let (written_notes, poly) = self.thrad_pool.install(|| { // For each note column, write it into the buffer - let written_notes_per_key = - columns_view_info.par_iter_mut().rev().map(|column| { - if column.remaining == 0 { - return 0; - } - - let offset = - (column.offset as i64 - notes_pushed as i64).max(0) as usize; - - if offset >= buffer_length { - return 0; - } - - let remaining_buffer_space = buffer_length - offset; - let iter_length = column.remaining; - - let allowed_to_write = if iter_length > remaining_buffer_space { - remaining_buffer_space - } else { - iter_length - }; - - unsafe { - let buffer = buffer_writer.get_mut(); - - for i in 0..allowed_to_write { - let next_note = column.iter.next(); - if let Some(note) = next_note { - buffer[i + offset] = NoteVertex::new( - note.start, - note.len, - column.key, - note.color.as_u32(), - column.border_width as u32, - ); - - if note.start <= 0.0 - && column.color.is_none() - && note.start + note.len > 0.0 - { + let out_data = columns_view_info.par_iter_mut().rev().map(|column| { + if column.remaining == 0 { + return (0, 0); + } + + let offset = (column.offset as i64 - notes_pushed as i64).max(0) as usize; + + if offset >= buffer_length { + return (0, 0); + } + + let remaining_buffer_space = buffer_length - offset; + let iter_length = column.remaining; + + let allowed_to_write = if iter_length > remaining_buffer_space { + remaining_buffer_space + } else { + iter_length + }; + + let mut poly = 0; + + unsafe { + let buffer = buffer_writer.get_mut(); + + for i in 0..allowed_to_write { + let next_note = column.iter.next(); + if let Some(note) = next_note { + buffer[i + offset] = NoteVertex::new( + note.start, + note.len, + column.key, + note.color.as_u32(), + column.border_width as u32, + ); + + if note.start <= 0.0 && note.start + note.len > 0.0 { + poly += 1; + if column.color.is_none() { column.color = Some(note.color); } - } else { - panic!("Invalid iterator length"); } + } else { + panic!("Invalid iterator length"); } } + } - column.remaining -= allowed_to_write; + column.remaining -= allowed_to_write; - allowed_to_write - }); + (allowed_to_write, poly) + }); - written_notes_per_key.sum::() + let temp = out_data.collect::>(); + ( + temp.iter().map(|v| v.0.clone()).sum::().clone(), + temp.iter().map(|v| v.1.clone()).sum::().clone(), + ) }); + polyphony += poly; notes_pushed += written_notes; cycle += 1; @@ -196,6 +202,7 @@ impl NoteRenderer { RenderResultData { notes_rendered: notes_pushed as u64, + polyphony: polyphony as u64, key_colors: columns_view_info .iter() .map(|column| column.color) diff --git a/src/gui/window/stats.rs b/src/gui/window/stats.rs index 2467d60..dd8948a 100644 --- a/src/gui/window/stats.rs +++ b/src/gui/window/stats.rs @@ -1,3 +1,5 @@ +use std::{collections::VecDeque, time::Instant}; + use egui::{Context, Frame, Pos2}; use crate::{ @@ -11,6 +13,7 @@ pub struct GuiMidiStats { time_passed: f64, time_total: f64, notes_on_screen: u64, + polyphony: u64, voice_count: Option, } @@ -20,6 +23,7 @@ impl GuiMidiStats { time_passed: 0.0, time_total: 0.0, notes_on_screen: 0, + polyphony: 0, voice_count: None, } } @@ -31,6 +35,10 @@ impl GuiMidiStats { pub fn set_rendered_note_count(&mut self, notes: u64) { self.notes_on_screen = notes; } + + pub fn set_polyphony(&mut self, polyphony: u64) { + self.polyphony = polyphony; + } } fn num_or_q(num: Option) -> String { @@ -163,8 +171,65 @@ impl GuiWasabiWindow { )); }); } + Statistics::Nps => { + ui.horizontal(|ui| { + ui.monospace("NPS:"); + ui.with_layout( + egui::Layout::right_to_left(egui::Align::Center), + |ui| { + self.nps.tick(note_stats.passed_notes.unwrap_or(0) as i64); + ui.monospace(format!("{}", self.nps.read())); + }, + ); + }); + } + Statistics::Polyphony => { + ui.horizontal(|ui| { + ui.monospace("Polyphony:"); + ui.with_layout( + egui::Layout::right_to_left(egui::Align::Center), + |ui| { + ui.monospace(format!("{}", stats.polyphony)); + }, + ); + }); + } }; } }); } } + +#[derive(Default)] +pub struct NpsCounter(VecDeque<(Instant, i64)>); + +impl NpsCounter { + const NPS_WINDOW: f64 = 0.5; + + pub fn tick(&mut self, passed: i64) { + self.0.push_back((Instant::now(), passed)); + while let Some(front) = self.0.front() { + if front.0.elapsed().as_secs_f64() > Self::NPS_WINDOW { + self.0.pop_front(); + } else { + break; + } + } + } + + pub fn read(&self) -> u32 { + let old = if let Some(front) = self.0.front() { + front.1 as f64 + } else { + 0.0 + }; + + let last = if let Some(back) = self.0.back() { + back.1 as f64 + } else { + 0.0 + }; + + ((last - old).max(0.0) / Self::NPS_WINDOW).round() as u32 + } +} diff --git a/src/settings/enums.rs b/src/settings/enums.rs index b795581..8f7c956 100644 --- a/src/settings/enums.rs +++ b/src/settings/enums.rs @@ -89,6 +89,8 @@ pub enum Statistics { VoiceCount = 2, Rendered = 3, NoteCount = 4, + Polyphony = 5, + Nps = 6, } impl Statistics { @@ -100,15 +102,19 @@ impl Statistics { Statistics::VoiceCount => "Voice Count", Statistics::Rendered => "Rendered", Statistics::NoteCount => "Note Count", + Statistics::Polyphony => "Polyphony", + Statistics::Nps => "NPS", } } pub fn iter() -> Iter<'static, Statistics> { - static STATISTICS: [Statistics; 5] = [ + static STATISTICS: [Statistics; 7] = [ Statistics::Time, Statistics::Fps, - Statistics::VoiceCount, Statistics::Rendered, + Statistics::Nps, + Statistics::Polyphony, + Statistics::VoiceCount, Statistics::NoteCount, ]; STATISTICS.iter() @@ -125,6 +131,8 @@ impl FromStr for Statistics { "voicecount" => Ok(Statistics::VoiceCount), "rendered" => Ok(Statistics::Rendered), "notecount" => Ok(Statistics::NoteCount), + "polyphony" => Ok(Statistics::Polyphony), + "nps" => Ok(Statistics::Nps), s => Err(format!("{} was not expected.", s)), } } diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 1fda028..58ec7a7 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -198,8 +198,13 @@ impl WasabiSettings { } else if let Ok(config) = fs::read_to_string(&config_path) { if config.starts_with(Self::VERSION_TEXT) { let offset = Self::VERSION_TEXT.len(); - match serde_json::from_str(&config[offset..]) { - Ok(config) => return Ok(config), + match serde_json::from_str::(&config[offset..]) { + Ok(mut config) => { + if config.scene.statistics.order.len() != Statistics::iter().len() { + config.scene.statistics.order = StatisticsSettings::default().order; + } + return Ok(config); + } Err(e) => err = WasabiError::SettingsError(e.to_string()), } } else if config.starts_with("# DON'T EDIT THIS LINE; Version: 1") { From 14e2575c8fd7acc993a6d6a6353fc61e3a272190 Mon Sep 17 00:00:00 2001 From: MyBlackMIDIScore Date: Thu, 17 Oct 2024 21:12:33 +0300 Subject: [PATCH 2/5] Misc fixes --- build.rs | 2 +- src/gui/window/fps.rs | 20 ++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/build.rs b/build.rs index d6f8beb..c57ef28 100644 --- a/build.rs +++ b/build.rs @@ -57,5 +57,5 @@ fn main() { icon_dir.write(File::create(icon_path).unwrap()).unwrap(); #[cfg(not(windows))] - println!("cargo:rerun-if-changed=logo.svg") + println!("cargo:rerun-if-changed=assets/logo.svg") } diff --git a/src/gui/window/fps.rs b/src/gui/window/fps.rs index 022fc38..5963b1e 100644 --- a/src/gui/window/fps.rs +++ b/src/gui/window/fps.rs @@ -3,33 +3,25 @@ use std::{ time::{Duration, Instant}, }; -pub struct Fps { - frames: VecDeque, - current: Instant, -} +pub struct Fps(VecDeque); impl Fps { pub fn new() -> Self { - Self { - frames: VecDeque::new(), - current: Instant::now(), - } + Self(VecDeque::new()) } pub fn update(&mut self) { - self.frames.push_back(Instant::now()); - while let Some(front) = self.frames.front() { + self.0.push_back(Instant::now()); + while let Some(front) = self.0.front() { if front.elapsed() > Duration::from_secs(1) { - self.frames.pop_front(); + self.0.pop_front(); } else { break; } } - - self.current = Instant::now(); } pub fn get_fps(&self) -> usize { - self.frames.len() + self.0.len() } } From b856d02c0fb202a2fde3b1109175b04e15c98add Mon Sep 17 00:00:00 2001 From: MyBlackMIDIScore Date: Thu, 17 Oct 2024 23:06:20 +0300 Subject: [PATCH 3/5] Clippy --- src/gui/window/scene/note_list_system/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/window/scene/note_list_system/mod.rs b/src/gui/window/scene/note_list_system/mod.rs index 172fb3c..c8e7fef 100644 --- a/src/gui/window/scene/note_list_system/mod.rs +++ b/src/gui/window/scene/note_list_system/mod.rs @@ -178,8 +178,8 @@ impl NoteRenderer { let temp = out_data.collect::>(); ( - temp.iter().map(|v| v.0.clone()).sum::().clone(), - temp.iter().map(|v| v.1.clone()).sum::().clone(), + temp.iter().map(|v| v.0).sum::(), + temp.iter().map(|v| v.1).sum::(), ) }); From bebaf97ed2b8b62ee118a50aca2ec703a645fe23 Mon Sep 17 00:00:00 2001 From: MyBlackMIDIScore Date: Fri, 18 Oct 2024 16:59:56 +0300 Subject: [PATCH 4/5] Disable polyphony for cake --- src/gui/window/scene.rs | 2 +- src/gui/window/scene/cake_system/mod.rs | 2 +- src/gui/window/scene/note_list_system/mod.rs | 2 +- src/gui/window/settings/midi.rs | 3 ++- src/gui/window/stats.rs | 26 +++++++++++--------- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/gui/window/scene.rs b/src/gui/window/scene.rs index b145939..cc8a28f 100644 --- a/src/gui/window/scene.rs +++ b/src/gui/window/scene.rs @@ -55,7 +55,7 @@ pub struct GuiRenderScene { pub struct RenderResultData { pub notes_rendered: u64, - pub polyphony: u64, + pub polyphony: Option, pub key_colors: Vec>, } diff --git a/src/gui/window/scene/cake_system/mod.rs b/src/gui/window/scene/cake_system/mod.rs index 71ad9f5..d135db4 100644 --- a/src/gui/window/scene/cake_system/mod.rs +++ b/src/gui/window/scene/cake_system/mod.rs @@ -469,7 +469,7 @@ impl CakeRenderer { RenderResultData { notes_rendered: rendered_notes, - polyphony: 0, + polyphony: None, key_colors: colors, } } diff --git a/src/gui/window/scene/note_list_system/mod.rs b/src/gui/window/scene/note_list_system/mod.rs index c8e7fef..edd4538 100644 --- a/src/gui/window/scene/note_list_system/mod.rs +++ b/src/gui/window/scene/note_list_system/mod.rs @@ -202,7 +202,7 @@ impl NoteRenderer { RenderResultData { notes_rendered: notes_pushed as u64, - polyphony: polyphony as u64, + polyphony: Some(polyphony as u64), key_colors: columns_view_info .iter() .map(|column| column.color) diff --git a/src/gui/window/settings/midi.rs b/src/gui/window/settings/midi.rs index 67eef09..cb24290 100644 --- a/src/gui/window/settings/midi.rs +++ b/src/gui/window/settings/midi.rs @@ -33,7 +33,8 @@ impl SettingsWindow { - Cake\n\ \0 The most efficient loading and displaying algorithm.\n\ \0 The notes will be stored in binary trees and will be\n\ - \0 displayed dynamically.\n\ + \0 displayed dynamically. This mode does not support\n\ + \0 polyphony statistics.\n\ - Standard (RAM)\n\ \0 The MIDI will be loaded in the RAM and all the notes\n\ \0 will be rendered normally by the GPU.\n\ diff --git a/src/gui/window/stats.rs b/src/gui/window/stats.rs index dd8948a..fc530c0 100644 --- a/src/gui/window/stats.rs +++ b/src/gui/window/stats.rs @@ -13,7 +13,7 @@ pub struct GuiMidiStats { time_passed: f64, time_total: f64, notes_on_screen: u64, - polyphony: u64, + polyphony: Option, voice_count: Option, } @@ -23,7 +23,7 @@ impl GuiMidiStats { time_passed: 0.0, time_total: 0.0, notes_on_screen: 0, - polyphony: 0, + polyphony: None, voice_count: None, } } @@ -36,7 +36,7 @@ impl GuiMidiStats { self.notes_on_screen = notes; } - pub fn set_polyphony(&mut self, polyphony: u64) { + pub fn set_polyphony(&mut self, polyphony: Option) { self.polyphony = polyphony; } } @@ -184,15 +184,17 @@ impl GuiWasabiWindow { }); } Statistics::Polyphony => { - ui.horizontal(|ui| { - ui.monospace("Polyphony:"); - ui.with_layout( - egui::Layout::right_to_left(egui::Align::Center), - |ui| { - ui.monospace(format!("{}", stats.polyphony)); - }, - ); - }); + if let Some(poly) = stats.polyphony { + ui.horizontal(|ui| { + ui.monospace("Polyphony:"); + ui.with_layout( + egui::Layout::right_to_left(egui::Align::Center), + |ui| { + ui.monospace(format!("{}", poly)); + }, + ); + }); + } } }; } From d3a5075c1251f6df3e3bb62bdc2b57d98702bfd2 Mon Sep 17 00:00:00 2001 From: MyBlackMIDIScore Date: Tue, 22 Oct 2024 16:46:33 +0300 Subject: [PATCH 5/5] Requested changes --- src/gui/window/fps.rs | 16 ++++++---- src/gui/window/scene/note_list_system/mod.rs | 31 +++++++++++++------- src/gui/window/stats.rs | 20 +++++++------ 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/gui/window/fps.rs b/src/gui/window/fps.rs index 5963b1e..d36356b 100644 --- a/src/gui/window/fps.rs +++ b/src/gui/window/fps.rs @@ -3,18 +3,22 @@ use std::{ time::{Duration, Instant}, }; -pub struct Fps(VecDeque); +pub struct Fps { + ticks: VecDeque, +} impl Fps { pub fn new() -> Self { - Self(VecDeque::new()) + Self { + ticks: VecDeque::new(), + } } pub fn update(&mut self) { - self.0.push_back(Instant::now()); - while let Some(front) = self.0.front() { + self.ticks.push_back(Instant::now()); + while let Some(front) = self.ticks.front() { if front.elapsed() > Duration::from_secs(1) { - self.0.pop_front(); + self.ticks.pop_front(); } else { break; } @@ -22,6 +26,6 @@ impl Fps { } pub fn get_fps(&self) -> usize { - self.0.len() + self.ticks.len() } } diff --git a/src/gui/window/scene/note_list_system/mod.rs b/src/gui/window/scene/note_list_system/mod.rs index edd4538..ddddc59 100644 --- a/src/gui/window/scene/note_list_system/mod.rs +++ b/src/gui/window/scene/note_list_system/mod.rs @@ -15,6 +15,12 @@ use self::notes_render_pass::{NotePassStatus, NoteRenderPass, NoteVertex}; use super::RenderResultData; +#[derive(Default)] +struct ColumnReturnData { + polyphony: usize, + written_notes: usize, +} + pub struct NoteRenderer { render_pass: NoteRenderPass, thrad_pool: rayon::ThreadPool, @@ -121,17 +127,17 @@ impl NoteRenderer { let buffer_writer = UnsafeSyncCell::new(buffer.write().unwrap()); // A system to write multiple note columns into 1 large allocated array in parallel - let (written_notes, poly) = self.thrad_pool.install(|| { + let column_data = self.thrad_pool.install(|| { // For each note column, write it into the buffer let out_data = columns_view_info.par_iter_mut().rev().map(|column| { if column.remaining == 0 { - return (0, 0); + return Default::default(); } let offset = (column.offset as i64 - notes_pushed as i64).max(0) as usize; if offset >= buffer_length { - return (0, 0); + return Default::default(); } let remaining_buffer_space = buffer_length - offset; @@ -173,24 +179,27 @@ impl NoteRenderer { column.remaining -= allowed_to_write; - (allowed_to_write, poly) + ColumnReturnData { + polyphony: poly, + written_notes: allowed_to_write, + } }); let temp = out_data.collect::>(); - ( - temp.iter().map(|v| v.0).sum::(), - temp.iter().map(|v| v.1).sum::(), - ) + ColumnReturnData { + polyphony: temp.iter().map(|d| d.polyphony).sum::(), + written_notes: temp.iter().map(|d| d.written_notes).sum::(), + } }); - polyphony += poly; - notes_pushed += written_notes; + polyphony += column_data.polyphony; + notes_pushed += column_data.written_notes; cycle += 1; if notes_pushed >= total_notes { NotePassStatus::Finished { - remaining: written_notes as u32, + remaining: column_data.written_notes as u32, } } else { NotePassStatus::HasMoreNotes diff --git a/src/gui/window/stats.rs b/src/gui/window/stats.rs index fc530c0..26a6c29 100644 --- a/src/gui/window/stats.rs +++ b/src/gui/window/stats.rs @@ -203,16 +203,18 @@ impl GuiWasabiWindow { } #[derive(Default)] -pub struct NpsCounter(VecDeque<(Instant, i64)>); +pub struct NpsCounter { + ticks: VecDeque<(Instant, i64)>, +} impl NpsCounter { const NPS_WINDOW: f64 = 0.5; pub fn tick(&mut self, passed: i64) { - self.0.push_back((Instant::now(), passed)); - while let Some(front) = self.0.front() { - if front.0.elapsed().as_secs_f64() > Self::NPS_WINDOW { - self.0.pop_front(); + self.ticks.push_back((Instant::now(), passed)); + while let Some((front_time, _passed)) = self.ticks.front() { + if front_time.elapsed().as_secs_f64() > Self::NPS_WINDOW { + self.ticks.pop_front(); } else { break; } @@ -220,14 +222,14 @@ impl NpsCounter { } pub fn read(&self) -> u32 { - let old = if let Some(front) = self.0.front() { - front.1 as f64 + let old = if let Some((_time, front_passed)) = self.ticks.front() { + *front_passed as f64 } else { 0.0 }; - let last = if let Some(back) = self.0.back() { - back.1 as f64 + let last = if let Some((_time, back_passed)) = self.ticks.back() { + *back_passed as f64 } else { 0.0 };