From 7059a85742f8fcf1c9da964e59610aa97bc3cdbf Mon Sep 17 00:00:00 2001 From: Jay <157681441+cubee-cb@users.noreply.github.com> Date: Mon, 12 Jan 2026 23:42:03 +1100 Subject: [PATCH] Re-implement custom audio files support. (#379) * reimplement custom audio loading for `toast` and `key_click` using `from_mp3` * run cargo fmt * `try_bytes_from_config`: output with `log::trace` when file cannot be opened * rewrite `try_bytes_from_config` * use file `read_to_end`, log categories * edit `register_wgui_samples` * rework audio functions for loading custom wgui sounds oh hey, it works! * clean up * allow custom `startup` and `app_start` sounds these sounds are loaded on-demand and never registered; this behaviour is unchanged * edit `bytes_from_config` outputs * use return value of `read_to_end` instead of `len()` for reported file size * implement suggested changes - remove now-unused `register_mp3_sample_from_assets` function - replace implementation of `try_bytes_from_config` - missing the `real_path` context * swap out `context`s for `inspect_err`s with closures to output `real_path` * clean up `audio.rs` - remove unused import - unify capitalisation + quotes in output messages. --- dash-frontend/src/frontend.rs | 13 ++++++-- wayvr/src/state.rs | 14 ++++++--- wlx-common/src/audio.rs | 57 ++++++++++++++++++++++++----------- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/dash-frontend/src/frontend.rs b/dash-frontend/src/frontend.rs index f7a616c..0f4c21f 100644 --- a/dash-frontend/src/frontend.rs +++ b/dash-frontend/src/frontend.rs @@ -183,10 +183,19 @@ impl Frontend { fn play_sound(&mut self, audio_system: &mut audio::AudioSystem, sound_type: SoundType) -> anyhow::Result<()> { let mut assets = self.globals.assets_builtin(); - let sample = audio::AudioSample::from_mp3(&assets.load_from_path(match sound_type { + + let path = match sound_type { SoundType::Startup => "sound/startup.mp3", SoundType::Launch => "sound/app_start.mp3", - })?)?; + }; + + // try loading a custom sound; if one doesn't exist (or it failed to load), use the built-in asset + let sound_bytes = match audio::AudioSample::try_bytes_from_config(path) { + Ok(bytes) => bytes, + Err(_) => assets.load_from_path(path)?.into(), + }; + + let sample = audio::AudioSample::from_mp3(&*sound_bytes)?; audio_system.play_sample(&sample); Ok(()) } diff --git a/wayvr/src/state.rs b/wayvr/src/state.rs index 0556dff..f1c62a8 100644 --- a/wayvr/src/state.rs +++ b/wayvr/src/state.rs @@ -94,13 +94,19 @@ impl AppState { let mut audio_sample_player = audio::SamplePlayer::new(); audio_sample_player.register_sample( "key_click", - audio::AudioSample::from_mp3(include_bytes!("res/key_click.mp3"))?, - ); + audio::AudioSample::from_mp3(&*audio::AudioSample::bytes_from_config_or_default( + "sound/key_click.mp3", + include_bytes!("res/key_click.mp3"), + ))?, + )?; audio_sample_player.register_sample( "toast", - audio::AudioSample::from_mp3(include_bytes!("res/toast.mp3"))?, - ); + audio::AudioSample::from_mp3(&*audio::AudioSample::bytes_from_config_or_default( + "sound/toast.mp3", + include_bytes!("res/toast.mp3"), + ))?, + )?; let mut assets = Box::new(gui::asset::GuiAsset {}); audio_sample_player.register_wgui_samples(assets.as_mut())?; diff --git a/wlx-common/src/audio.rs b/wlx-common/src/audio.rs index 7a4d5df..4d5138e 100644 --- a/wlx-common/src/audio.rs +++ b/wlx-common/src/audio.rs @@ -1,8 +1,10 @@ -use std::{collections::HashMap, io::Cursor}; +use std::{collections::HashMap, io::Cursor, rc::Rc}; use rodio::Source; use wgui::{assets::AssetProvider, sound::WguiSoundType}; +use std::io::Read; + pub struct AudioSystem { audio_stream: Option, first_try: bool, @@ -33,32 +35,31 @@ impl SamplePlayer { } } - pub fn register_sample(&mut self, sample_name: &str, sample: AudioSample) { - log::debug!("registering audio sample \"{sample_name}\""); - self.samples.insert(String::from(sample_name), sample); - } - - pub fn register_mp3_sample_from_assets( - &mut self, - sample_name: &str, - assets: &mut dyn AssetProvider, - path: &str, - ) -> anyhow::Result<()> { + pub fn register_sample(&mut self, sample_name: &str, sample: AudioSample) -> anyhow::Result<()> { // load only once if self.samples.contains_key(sample_name) { + log::debug!("Audio sample '{sample_name}' already exists."); return Ok(()); } - let data = assets.load_from_path(path)?; - self.register_sample(sample_name, AudioSample::from_mp3(&data)?); - + log::debug!("Registering audio sample '{sample_name}'"); + self.samples.insert(String::from(sample_name), sample); Ok(()) } pub fn register_wgui_samples(&mut self, assets: &mut dyn AssetProvider) -> anyhow::Result<()> { let mut load = |sound: WguiSoundType| -> anyhow::Result<()> { let sample_name = get_sample_name_from_wgui_sound_type(sound); - self.register_mp3_sample_from_assets(sample_name, assets, &format!("sound/{}.mp3", sample_name)) + let path = &format!("sound/{}.mp3", sample_name); + + // try loading a custom sound; if one doesn't exist (or it failed to load), use the built-in asset + let sound_bytes = match AudioSample::try_bytes_from_config(path) { + Ok(bytes) => bytes, + Err(_) => assets.load_from_path(path)?.into(), + }; + + self.register_sample(sample_name, AudioSample::from_mp3(&*sound_bytes)?)?; + Ok(()) }; load(WguiSoundType::ButtonPress)?; @@ -71,7 +72,7 @@ impl SamplePlayer { pub fn play_sample(&mut self, system: &mut AudioSystem, sample_name: &str) { let Some(sample) = self.samples.get(sample_name) else { - log::error!("failed to play sample by name {}", sample_name); + log::error!("Failed to play sample by name '{}'", sample_name); return; }; @@ -143,4 +144,26 @@ impl AudioSample { ), }) } + + pub fn try_bytes_from_config(path: &str) -> anyhow::Result> { + let real_path = crate::config_io::get_config_root().join(&*path); + + let mut file = std::fs::File::open(&real_path) + .inspect_err(|e| log::debug!("Could not open file '{}': {e:?}", real_path.display()))?; + let mut file_buffer = vec![]; + file + .read_to_end(&mut file_buffer) + .inspect_err(|e| log::debug!("Could not read file '{}': {e:?}", real_path.display()))?; + Ok(file_buffer.into()) + } + + pub fn bytes_from_config_or_default(path: &str, default: &'static [u8]) -> Rc<[u8]> { + match AudioSample::try_bytes_from_config(path) { + Ok(value) => value, + Err(_) => { + log::trace!("File '{}' not found, using default.", path); + default.into() + } + } + } }