Created
January 2, 2024 10:08
-
-
Save gak/1dcc8b8f53ca5e8980311da6c4a56e6e to your computer and use it in GitHub Desktop.
rust bevy audio via bindgen/websys
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::MainSettings; | |
use bevy::asset::Handle; | |
use bevy::prelude::*; | |
use bevy_kira_audio::{Audio, AudioChannel, AudioControl, AudioSource, MainTrack}; | |
use crate::core::assets::GameAssets; | |
#[cfg(target_arch = "wasm32")] | |
use wasm_bindgen::{JsCast, JsValue}; | |
#[cfg(target_arch = "wasm32")] | |
use web_sys::Document; | |
#[cfg(target_arch = "wasm32")] | |
fn get_document() -> Option<Document> { | |
let Some(window) = web_sys::window() else { | |
error!("Failed to get window"); | |
return None; | |
}; | |
let document = window.document() else { | |
error!("Failed to get document"); | |
return None; | |
}; | |
document | |
} | |
pub fn stop_all_sounds(audio: &Res<Audio>) { | |
// Delete all audio elements | |
// document.querySelectorAll("audio").forEach((elem) => elem.remove()); | |
#[cfg(target_arch = "wasm32")] | |
{ | |
let Some(document) = get_document() else { | |
error!("Failed to get document"); | |
return; | |
}; | |
let Ok(audio_elements) = document.query_selector_all("audio") else { | |
error!("Failed to get audio elements"); | |
return; | |
}; | |
for i in 0..audio_elements.length() { | |
let Some(audio_element) = audio_elements.get(i) else { | |
error!("Failed to get audio element"); | |
continue; | |
}; | |
let Some(parent) = audio_element.parent_node() else { | |
error!("Failed to get audio element parent"); | |
continue; | |
}; | |
let _ = parent.remove_child(&audio_element); | |
} | |
} | |
#[cfg(not(target_arch = "wasm32"))] | |
audio.stop(); | |
} | |
pub fn play_sound( | |
kira_audio: &Audio, | |
audio_source: Handle<AudioSource>, | |
path: &str, | |
looping: bool, | |
audio_on: bool, | |
) { | |
#[cfg(target_arch = "wasm32")] | |
{ | |
let Some(document) = get_document() else { | |
return; | |
}; | |
let Ok(audio_element) = document.create_element("audio") else { | |
return; | |
}; | |
let r = audio_element.set_attribute("src", path); | |
if let Err(e) = r { | |
error!("Failed to set audio src: {:?}", e); | |
} | |
// let autoplay_if_audio_on = format!("{}", audio_on).to_ascii_lowercase(); | |
if audio_on { | |
let r = audio_element.set_attribute("autoplay", "true"); | |
if let Err(e) = r { | |
error!("Failed to set audio autoplay: {:?}", e); | |
} | |
} | |
if looping { | |
let r = audio_element.set_attribute("loop", "true"); | |
if let Err(e) = r { | |
error!("Failed to set audio loop: {:?}", e); | |
} | |
} | |
// let r = | |
// audio_element.set_attribute("muted", &format!("{}", !audio_on).to_ascii_lowercase()); | |
// if let Err(e) = r { | |
// error!("Failed to set audio muted: {:?}", e); | |
// } | |
let r = audio_element.set_attribute("volume", "1.0"); | |
if let Err(e) = r { | |
error!("Failed to set audio volume: {:?}", e); | |
} | |
let r = audio_element.set_attribute("preload", "auto"); | |
if let Err(e) = r { | |
error!("Failed to set audio preload: {:?}", e); | |
} | |
let Some(body) = document.body() else { | |
error!("Failed to get document body"); | |
return; | |
}; | |
let Ok(_) = body.append_child(&audio_element) else { | |
error!("Failed to append audio element to body"); | |
return; | |
}; | |
} | |
#[cfg(not(target_arch = "wasm32"))] | |
{ | |
info!("Playing audio native: {}", path); | |
let mut audio_command = kira_audio.play(audio_source); | |
if looping { | |
audio_command.looped(); | |
} | |
} | |
} | |
pub fn set_audio_active(mut audio_control: &mut ResMut<AudioChannel<MainTrack>>, audio_on: bool) { | |
#[cfg(target_arch = "wasm32")] | |
{ | |
// document.querySelectorAll("audio").forEach((elem) => elem.muted = true); | |
let Some(document) = get_document() else { | |
return; | |
}; | |
let Ok(audio_elements) = document.query_selector_all("audio") else { | |
error!("Failed to get audio elements"); | |
return; | |
}; | |
for i in 0..audio_elements.length() { | |
let Some(audio_node) = audio_elements.get(i) else { | |
continue; | |
}; | |
let audio_element = JsCast::dyn_into::<web_sys::HtmlAudioElement>(audio_node).unwrap(); | |
if audio_on { | |
audio_element.play(); | |
} else { | |
audio_element.pause(); | |
} | |
} | |
} | |
#[cfg(not(target_arch = "wasm32"))] | |
{ | |
audio_control.set_volume(if audio_on { 1. } else { 0. }); | |
} | |
} | |
// Running this on the load screen really goes chunky. Run it after the audio has loaded. | |
pub fn start_background_audio( | |
// mut audio_control: ResMut<AudioChannel<MainTrack>>, | |
settings: Res<MainSettings>, | |
audio: Res<Audio>, | |
game_assets: Res<GameAssets>, | |
) { | |
stop_all_sounds(&audio); | |
play_sound( | |
&audio, | |
game_assets.game_music.clone(), | |
"assets/audio/Ogg/Music/Outbreak_TemaCompleto.ogg", | |
true, | |
settings.audio_on, | |
); | |
} | |
#[derive(Event, Deref)] | |
pub struct AudioSetActive(pub bool); | |
pub fn toggle_audio( | |
mut settings: ResMut<MainSettings>, | |
mut audio_control: ResMut<AudioChannel<MainTrack>>, | |
mut event_reader: EventReader<AudioSetActive>, | |
) { | |
for a in event_reader.read() { | |
settings.audio_on = **a; | |
// audio_control.set_volume(if settings.audio { 1. } else { 0. }); | |
set_audio_active(&mut audio_control, settings.audio_on); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment