Skip to content

Instantly share code, notes, and snippets.

@gak
Created January 2, 2024 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gak/1dcc8b8f53ca5e8980311da6c4a56e6e to your computer and use it in GitHub Desktop.
Save gak/1dcc8b8f53ca5e8980311da6c4a56e6e to your computer and use it in GitHub Desktop.
rust bevy audio via bindgen/websys
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