micro_musicbox 0.10.0

Opinionated service interface for bevy_kira_audio
Documentation
use bevy::prelude::*;
use bevy_kira_audio::AudioSource;

use crate::music_box::MusicBox;

/// This trait provides a `MusicBox` with a way of resolving a track name
/// into usable audio resources that is generic over however you implement your
/// asset loading
///
/// # Example
///
/// The canonical example is also included in the crate; using the `AssetServer`
/// as a `SuppliesAudio` extension:
///
/// ```rust
/// # use bevy::ecs::system::SystemParam;
/// use micro_musicbox::prelude::AudioSource;
/// use micro_musicbox::utilities::{TrackType, SuppliesAudio};
/// # use bevy::prelude::*;
/// use bevy::utils::HashMap;
///
/// #[derive(Resource)]
/// struct MyAudioMap(pub HashMap<String, Handle<AudioSource>>);
///
/// impl SuppliesAudio for MyAudioMap {
///     fn resolve_track_name<T: ToString>(&self, name: T) -> TrackType<String> {
///         TrackType::Single(name.to_string())
///     }
///
///     fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>> {
///         let key = name.to_string();
///         self.0.get(&key).map(|h| h.clone_weak())
///     }
/// }
/// ```
pub trait SuppliesAudio: Resource {
	fn resolve_track_name<T: ToString>(&self, name: T) -> TrackType<String>;
	fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>>;
}

#[derive(Copy, Clone, Debug, Resource)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AudioSettings {
	pub master_volume: f32,
	pub music_volume: f32,
	pub ambiance_volume: f32,
	pub sfx_volume: f32,
	pub ui_volume: f32,
}

impl Default for AudioSettings {
	fn default() -> Self {
		Self {
			master_volume: 1.0,
			music_volume: 1.0,
			ambiance_volume: 1.0,
			sfx_volume: 1.0,
			ui_volume: 1.0,
		}
	}
}

/// Defines the type of track that a given name represents
pub enum TrackType<T> {
	/// A single audio track that should be played as-is
	Single(T),
	/// Represents two tracks; the first is played once as the intro, and the second track will then be looped
	#[deprecated = "bevy_kira_audio no longer supports this functionality; the first track in the tuple will be ignored"]
	WithIntro(T, T),
	/// The requested track could not be found
	Missing,
}

impl SuppliesAudio for AssetServer {
	fn resolve_track_name<T: ToString>(&self, name: T) -> TrackType<String> {
		TrackType::Single(name.to_string())
	}

	fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>> {
		Some(self.load(name.to_string()))
	}
}

/// A bevy system that triggers the MusicBox to sync its internal channels with
/// the AudioSettings resource. This is automatically added when you use `MusicBoxPlugin` or
/// `CombinedAudioPlugins`
pub fn sync_music_volume<T: SuppliesAudio>(music: MusicBox<T>) {
	music.sync_settings();
}