Skip to content

Commit

Permalink
Merge pull request #147 from white-axe/editors
Browse files Browse the repository at this point in the history
Animation editor
  • Loading branch information
somedevfox authored Aug 11, 2024
2 parents 22e2085 + 5dbf1ea commit 7d1889a
Show file tree
Hide file tree
Showing 79 changed files with 8,167 additions and 740 deletions.
359 changes: 212 additions & 147 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ parking_lot = { version = "0.12.3", features = [
"nightly", # This is required for parking_lot to work properly in WebAssembly builds with atomics support
"deadlock_detection",
] }
parking_lot_core = "0.9.10"
once_cell = "1.18.0"
crossbeam = "0.8.2"
dashmap = "5.5.3"
Expand Down Expand Up @@ -154,6 +153,8 @@ wasm-bindgen-futures = "0.4.42"
web-sys = "0.3.67"
js-sys = "0.3"

lexical-sort = "0.3.1"

luminol-audio = { version = "0.4.0", path = "crates/audio/" }
luminol-components = { version = "0.4.0", path = "crates/components/" }
luminol-config = { version = "0.4.0", path = "crates/config/" }
Expand Down
2 changes: 1 addition & 1 deletion assets/js/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ if (typeof window === 'undefined') {
event.respondWith(
self.caches
.match(url)
.then((cached) => cached || fetch(request)) // Respond with cached response if one exists for this request
.then((cached) => cached || fetch(request, { cache: "no-store" })) // Respond with cached response if one exists for this request
.then((response) => {
if (response.status === 0) {
return new Response();
Expand Down
6 changes: 4 additions & 2 deletions crates/audio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ once_cell.workspace = true
color-eyre.workspace = true
thiserror.workspace = true

luminol-config.workspace = true
luminol-filesystem.workspace = true
fragile.workspace = true

Expand All @@ -35,11 +36,12 @@ rodio = "0.19.0"

[target.'cfg(target_arch = "wasm32")'.dependencies]
rodio = { version = "0.19.0", features = ["wasm-bindgen"] }
web-sys = { version = "0.3", features = ["Window"] }

web-sys.workspace = true
wasm-bindgen-futures.workspace = true

flume.workspace = true
oneshot.workspace = true

once_cell.workspace = true
poll-promise.workspace = true
slab.workspace = true
151 changes: 9 additions & 142 deletions crates/audio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,23 @@
// terms of the Steamworks API by Valve Corporation, the licensors of this
// Program grant you additional permission to convey the resulting work.

mod midi;

mod error;
mod midi;
pub use error::{Error, Result};

pub use luminol_config::VolumeScale;

mod native;
#[cfg(target_arch = "wasm32")]
mod wrapper;
#[cfg(target_arch = "wasm32")]
pub use wrapper::*;

use strum::Display;
use strum::EnumIter;

/// A struct for playing Audio.
pub struct Audio {
inner: parking_lot::Mutex<Inner>,
}

struct Inner {
output_stream_handle: rodio::OutputStreamHandle,
sinks: std::collections::HashMap<Source, rodio::Sink>,
}
#[cfg(not(target_arch = "wasm32"))]
pub use native::Audio;
#[cfg(target_arch = "wasm32")]
pub use wrapper::Audio;

/// Different sound sources.
#[derive(EnumIter, Display, PartialEq, Eq, Clone, Copy, Hash)]
#[derive(strum::EnumIter, strum::Display, PartialEq, Eq, Clone, Copy, Hash)]
#[allow(clippy::upper_case_acronyms)]
#[allow(missing_docs)]
pub enum Source {
Expand All @@ -56,131 +48,6 @@ pub enum Source {
SE,
}

impl Default for Audio {
fn default() -> Self {
#[cfg(target_arch = "wasm32")]
if web_sys::window().is_none() {
panic!("in web builds, `Audio` can only be created on the main thread");
}

let (output_stream, output_stream_handle) = rodio::OutputStream::try_default().unwrap();
std::mem::forget(output_stream); // Prevent the stream from being dropped
Self {
inner: parking_lot::Mutex::new(Inner {
output_stream_handle,
sinks: std::collections::HashMap::default(),
}),
}
}
}

impl Audio {
/// Play a sound on a source.
pub fn play<T>(
&self,
path: impl AsRef<camino::Utf8Path>,
filesystem: &T,
volume: u8,
pitch: u8,
source: Source,
) -> Result<()>
where
T: luminol_filesystem::FileSystem,
T::File: 'static,
{
let path = path.as_ref();
let file = filesystem.open_file(path, luminol_filesystem::OpenFlags::Read)?;

let is_midi = path
.extension()
.is_some_and(|e| matches!(e, "mid" | "midi"));

self.play_from_file(file, is_midi, volume, pitch, source)
}

pub fn play_from_file(
&self,
file: impl std::io::Read + std::io::Seek + Send + Sync + 'static,
is_midi: bool,
volume: u8,
pitch: u8,
source: Source,
) -> Result<()> {
let mut inner = self.inner.lock();
// Create a sink
let sink = rodio::Sink::try_new(&inner.output_stream_handle)?;

// Select decoder type based on sound source
match source {
Source::SE | Source::ME => {
// Non looping
if is_midi {
sink.append(midi::MidiSource::new(file, false)?);
} else {
sink.append(rodio::Decoder::new(file)?);
}
}
_ => {
// Looping
if is_midi {
sink.append(midi::MidiSource::new(file, true)?);
} else {
sink.append(rodio::Decoder::new_looped(file)?);
}
}
}

// Set pitch and volume
sink.set_speed(f32::from(pitch) / 100.);
sink.set_volume(f32::from(volume) / 100.);
// Play sound.
sink.play();
// Add sink to hash, stop the current one if it's there.
if let Some(s) = inner.sinks.insert(source, sink) {
s.stop();
#[cfg(not(target_arch = "wasm32"))]
s.sleep_until_end(); // wait for the sink to stop, there is a ~5ms delay where it will not
};

Ok(())
}

/// Set the pitch of a source.
pub fn set_pitch(&self, pitch: u8, source: &Source) {
let mut inner = self.inner.lock();
if let Some(s) = inner.sinks.get_mut(source) {
s.set_speed(f32::from(pitch) / 100.);
}
}

/// Set the volume of a source.
pub fn set_volume(&self, volume: u8, source: &Source) {
let mut inner = self.inner.lock();
if let Some(s) = inner.sinks.get_mut(source) {
s.set_volume(f32::from(volume) / 100.);
}
}

pub fn clear_sinks(&self) {
let mut inner = self.inner.lock();
for (_, sink) in inner.sinks.iter_mut() {
sink.stop();
#[cfg(not(target_arch = "wasm32"))]
// Sleeping ensures that the inner file is dropped. There is a delay of ~5ms where it is not dropped and this could lead to a panic
sink.sleep_until_end();
}
inner.sinks.clear();
}

/// Stop a source.
pub fn stop(&self, source: &Source) {
let mut inner = self.inner.lock();
if let Some(s) = inner.sinks.get_mut(source) {
s.stop();
}
}
}

impl Source {
pub fn as_path(&self) -> &camino::Utf8Path {
camino::Utf8Path::new(match self {
Expand Down
Loading

0 comments on commit 7d1889a

Please sign in to comment.