From e2f9a1afcb6e0ebd075d7e6127ccdc15ce97e256 Mon Sep 17 00:00:00 2001 From: Daniel Olczyk Date: Thu, 10 Jul 2025 15:12:43 +0200 Subject: [PATCH 1/3] Implement sound system --- assets/beep.ogg | Bin 0 -> 6490 bytes src/config/mod.rs | 7 +++++++ src/ui/options.rs | 10 +++++++++- src/ui/state.rs | 29 ++++++++++++++++++++++++++--- 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 assets/beep.ogg diff --git a/assets/beep.ogg b/assets/beep.ogg new file mode 100644 index 0000000000000000000000000000000000000000..3cc5b78aa455d11c843f3c66847f8d23dd12e7ef GIT binary patch literal 6490 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 XvG=+f>m2;86Q2F@cggm?H;ecmh@f2q literal 0 HcmV?d00001 diff --git a/src/config/mod.rs b/src/config/mod.rs index fd9eabb..d2c4ef2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -11,6 +11,7 @@ use std::path::PathBuf; pub struct Configuration { pub vm: VmOptions, pub debug: DebugOptions, + pub sound: SoundOptions, } #[derive(Clone, Deserialize, Serialize)] @@ -23,11 +24,17 @@ pub struct DebugOptions { pub enable_debug_menu: bool, } +#[derive(Clone, Deserialize, Serialize)] +pub struct SoundOptions { + pub volume: f32, +} + impl Default for Configuration { fn default() -> Self { Self { vm: VmOptions { cycles_per_frame: 10 }, debug: DebugOptions { enable_debug_menu: false }, + sound: SoundOptions { volume: 1.0 }, } } } diff --git a/src/ui/options.rs b/src/ui/options.rs index b672da5..b4b1055 100644 --- a/src/ui/options.rs +++ b/src/ui/options.rs @@ -1,6 +1,6 @@ use crate::ui::state::State; use notan::egui; -use notan::egui::Window; +use notan::egui::{Slider, Window}; pub fn option_dialog(state: &mut State, ctx: &egui::Context) { Window::new("Options") @@ -24,6 +24,14 @@ pub fn option_dialog(state: &mut State, ctx: &egui::Context) { } }); + ui.horizontal(|ui| { + ui.label("Sound volume"); + ui.add(Slider::new( + &mut state.configuration.sound.volume, + 0.0..=1.0, + )); + }); + ui.horizontal(|ui| { ui.checkbox( &mut state.configuration.debug.enable_debug_menu, diff --git a/src/ui/state.rs b/src/ui/state.rs index 1578e34..1a99a6f 100644 --- a/src/ui/state.rs +++ b/src/ui/state.rs @@ -24,6 +24,9 @@ pub struct State { pub timer: f32, pub show_configuration_window: bool, pub cycles_per_frame: u32, + beep_audio_source: AudioSource, + sound: Option, + is_beeping: bool, } #[derive(Parser)] @@ -32,7 +35,7 @@ struct Args { file: OsString, } -pub fn setup(gfx: &mut Graphics) -> State { +pub fn setup(app: &mut App, gfx: &mut Graphics) -> State { let args = Args::parse(); let file_path = if args.file.is_empty() { @@ -78,6 +81,11 @@ pub fn setup(gfx: &mut Graphics) -> State { let config = Configuration::load().unwrap(); + let audio_source = app + .audio + .create_source(include_bytes!("../../assets/beep.ogg")) + .expect("Failed to create audio source"); + State { last_dir, configuration: config.clone(), @@ -92,6 +100,9 @@ pub fn setup(gfx: &mut Graphics) -> State { timer: 0.0, show_configuration_window: false, cycles_per_frame: config.vm.cycles_per_frame, + beep_audio_source: audio_source, + sound: None, + is_beeping: false, } } @@ -123,9 +134,21 @@ pub fn update(app: &mut App, state: &mut State) { if state.vm.delay_timer != 0 { state.vm.delay_timer -= 1; } - if state.vm.sound_timer != 0 { - // TODO: play sound here + + if state.vm.sound_timer > 0 { + if !state.is_beeping { + state.sound = Option::from(app.audio.play_sound( + &state.beep_audio_source, + state.configuration.sound.volume, + true, + )); + state.is_beeping = true; + } + state.vm.sound_timer -= 1; + } else if state.is_beeping { + app.audio.stop(&state.sound.clone().unwrap()); + state.is_beeping = false; } } From 8ee290769e31148cff815962cb2caed3cca37c24 Mon Sep 17 00:00:00 2001 From: Daniel Olczyk Date: Mon, 14 Jul 2025 10:29:12 +0200 Subject: [PATCH 2/3] Change default volume to 0.85 --- src/config/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index d2c4ef2..4821756 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -34,7 +34,7 @@ impl Default for Configuration { Self { vm: VmOptions { cycles_per_frame: 10 }, debug: DebugOptions { enable_debug_menu: false }, - sound: SoundOptions { volume: 1.0 }, + sound: SoundOptions { volume: 0.85 }, } } } From 695caa3d04b8e3d627d8f57a317ade3ab33fc176 Mon Sep 17 00:00:00 2001 From: Daniel Olczyk Date: Mon, 14 Jul 2025 10:45:44 +0200 Subject: [PATCH 3/3] Simplify code --- src/ui/state.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ui/state.rs b/src/ui/state.rs index 1a99a6f..8dacad9 100644 --- a/src/ui/state.rs +++ b/src/ui/state.rs @@ -24,8 +24,8 @@ pub struct State { pub timer: f32, pub show_configuration_window: bool, pub cycles_per_frame: u32, - beep_audio_source: AudioSource, sound: Option, + beep_audio_source: AudioSource, is_beeping: bool, } @@ -100,8 +100,8 @@ pub fn setup(app: &mut App, gfx: &mut Graphics) -> State { timer: 0.0, show_configuration_window: false, cycles_per_frame: config.vm.cycles_per_frame, - beep_audio_source: audio_source, sound: None, + beep_audio_source: audio_source, is_beeping: false, } } @@ -137,18 +137,21 @@ pub fn update(app: &mut App, state: &mut State) { if state.vm.sound_timer > 0 { if !state.is_beeping { - state.sound = Option::from(app.audio.play_sound( + state.sound = Some(app.audio.play_sound( &state.beep_audio_source, state.configuration.sound.volume, true, )); + state.is_beeping = true; } state.vm.sound_timer -= 1; } else if state.is_beeping { - app.audio.stop(&state.sound.clone().unwrap()); - state.is_beeping = false; + if let Some(sound) = &state.sound { + app.audio.stop(sound); + state.is_beeping = false; + } } }