summaryrefslogtreecommitdiff
path: root/src/audio.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio.rs')
-rw-r--r--src/audio.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/src/audio.rs b/src/audio.rs
new file mode 100644
index 0000000..2b190de
--- /dev/null
+++ b/src/audio.rs
@@ -0,0 +1,96 @@
+use std::{cell::RefCell, collections::HashMap};
+
+pub struct Context {
+ pub audio: web_sys::AudioContext,
+}
+
+impl Context {
+ pub fn new() -> Self {
+ let audio = web_sys::AudioContext::new()
+ .expect("failed to create audio context");
+ Self {
+ audio,
+ }
+ }
+}
+
+pub struct Audio {
+ pub buffer: &'static RefCell<Option<web_sys::AudioBuffer>>,
+ //pub source: &'static web_sys::AudioBufferSourceNode,
+}
+
+impl Audio {
+ pub fn new(ctx: &Context, bytes: &[u8]) -> Self {
+ let sbuffer: &_ = Box::leak(Box::new(RefCell::new(None)));
+ let sclone: &'static RefCell<Option<web_sys::AudioBuffer>> =
+ <&_>::clone(&sbuffer);
+ let ret = Audio {
+ buffer: sclone,
+ };
+ let jsp = ctx.audio.decode_audio_data(&js_sys::Uint8Array::from(bytes).buffer()).expect("failed to decode audio");
+ let promise = wasm_bindgen_futures::JsFuture::from(jsp);
+ wasm_bindgen_futures::spawn_local(async {
+ if let Some(data) = promise.await.ok() {
+ *sbuffer.borrow_mut() = Some(web_sys::AudioBuffer::from(data));
+ }
+ ()
+ });
+ ret
+ }
+
+ pub fn play(&self, ctx: &Context, looping: Option<(Option<f64>, Option<f64>)>) -> Option<web_sys::AudioBufferSourceNode> {
+ let source = ctx.audio.create_buffer_source().ok()?;
+ source.set_buffer((&*self.buffer.borrow()).as_ref());
+ if let Some((ms, me)) = looping {
+ source.set_loop(true);
+ if let Some(s) = ms { source.set_loop_start(s) }
+ if let Some(e) = me { source.set_loop_end(e) }
+ }
+ source.connect_with_audio_node(&ctx.audio.destination()).ok()?;
+ source.start().ok()?;
+ Some(source)
+ }
+}
+
+pub struct Assets {
+ pub ctx: Context,
+
+ pub audio: HashMap<String, Audio>,
+
+ pub music_node: Option<web_sys::AudioBufferSourceNode>,
+}
+
+impl Assets {
+ pub fn new<F>(f : F) -> Self where F: Fn(&Context) -> HashMap<String, Audio> {
+ let ctx = Context::new();
+
+ let audio = f(&ctx);
+
+ Self {
+ ctx,
+ audio,
+ music_node: None,
+ }
+ }
+
+ pub fn play_sfx(&mut self, name: &str) {
+ if let Some(a) = self.audio.get(name) {
+ a.play(&self.ctx, None);
+ }
+ }
+
+ pub fn is_music_playing(&self) -> bool {
+ if let Some(ms) = &self.music_node {
+ ms.buffer().is_some()
+ } else { false }
+ }
+
+ pub fn play_music(&mut self, name: &str, start: Option<f64>, end: Option<f64>) {
+ if let Some(s) = &self.music_node {
+ let _ = s.stop();
+ }
+ if let Some(a) = self.audio.get(name) {
+ self.music_node = a.play(&self.ctx, Some((start, end)));
+ }
+ }
+}