Skip to content
Snippets Groups Projects
Verified Commit 143a8c0f authored by Louis's avatar Louis :fire:
Browse files

Write more documentation

parent be3119ab
No related branches found
No related tags found
No related merge requests found
...@@ -8,7 +8,7 @@ repository = "https://lab.lcr.gr/microhacks/micro_bevy_musicbox" ...@@ -8,7 +8,7 @@ repository = "https://lab.lcr.gr/microhacks/micro_bevy_musicbox"
description = "Opinionated service interface for bevy_kira_audio" description = "Opinionated service interface for bevy_kira_audio"
[features] [features]
default-features = [] default = []
serde = ["dep:serde"] serde = ["dep:serde"]
[dependencies] [dependencies]
......
//! micro_musicbox provides a convenience wrapper around bevy_kira_audio, handling all the
//! setup for the common game audio scenario. This includes channel management, giving you
//! control of the audio levels for your music, ambiance, sound effects and UI separately
//! from the start.
//!
//! ## Quickstart
//!
//! - Implement `SuppliesAudio` for a resource (or use the built-in impl on `AssetServer`)
//! - Include the MusixBocPlugin plugin, or the CombinedAudioPlugins plugin group in your app, providing your `SuppliesAudio` impl as the generic parameter
//! - Use `MusicBox<T: SuppliesAudio>` as a parameter on a system
//! - Call one of the `MusicBox::play_*` methods to play sounds
//!
//! ```rust
//! # use bevy::prelude::*;
//! # use micro_musicbox::prelude::*;
//! # use micro_musicbox::CombinedAudioPlugins;
//! fn main() {
//! App::new()
//! .add_plugins(CombinedAudioPlugins::<AssetServer>::new())
//! .add_startup_system(|mut music_box: MusicBox<AssetServer>| {
//! music_box.play_music("music/bing_bong.mp3");
//! });
//! }
//! ```
use std::marker::PhantomData; use std::marker::PhantomData;
use bevy::app::{App, CoreStage, Plugin, PluginGroup, PluginGroupBuilder}; use bevy::app::{App, CoreStage, Plugin, PluginGroup, PluginGroupBuilder};
...@@ -9,8 +34,7 @@ use crate::channels::{ ...@@ -9,8 +34,7 @@ use crate::channels::{
use crate::music_box::MusicBoxState; use crate::music_box::MusicBoxState;
use crate::utilities::{AudioSettings, SuppliesAudio}; use crate::utilities::{AudioSettings, SuppliesAudio};
/// Musicbox encapsulates the concept of different sound types in a number of preset channels, that /// The available channels that you can play audio on
/// can be used in certain ways
pub mod channels; pub mod channels;
pub mod music_box; pub mod music_box;
pub mod utilities; pub mod utilities;
...@@ -26,6 +50,10 @@ pub mod prelude { ...@@ -26,6 +50,10 @@ pub mod prelude {
pub use super::utilities::AudioSettings; pub use super::utilities::AudioSettings;
} }
/// A Bevy plugin that sets up all of the audio channels,
/// creates the required settings resources, and configures
/// syncing volume levels for a `MusicBox` that uses the supplied
/// `T` parameter for fetching audio
pub struct MusicBoxPlugin<T: SuppliesAudio> { pub struct MusicBoxPlugin<T: SuppliesAudio> {
_t: PhantomData<T>, _t: PhantomData<T>,
} }
...@@ -39,6 +67,7 @@ impl<T: SuppliesAudio> Default for MusicBoxPlugin<T> { ...@@ -39,6 +67,7 @@ impl<T: SuppliesAudio> Default for MusicBoxPlugin<T> {
} }
impl<T: SuppliesAudio> MusicBoxPlugin<T> { impl<T: SuppliesAudio> MusicBoxPlugin<T> {
/// Create a new MusicBoxPlugin
pub fn new() -> MusicBoxPlugin<T> { pub fn new() -> MusicBoxPlugin<T> {
Default::default() Default::default()
} }
...@@ -56,6 +85,8 @@ impl<T: SuppliesAudio> Plugin for MusicBoxPlugin<T> { ...@@ -56,6 +85,8 @@ impl<T: SuppliesAudio> Plugin for MusicBoxPlugin<T> {
} }
} }
/// A Bevy plugin group that adds `bevy_kira_audio` as well as the
/// plugin required to be able to use a `MusicBox`
pub struct CombinedAudioPlugins<T: SuppliesAudio> { pub struct CombinedAudioPlugins<T: SuppliesAudio> {
_t: PhantomData<T>, _t: PhantomData<T>,
} }
......
...@@ -7,6 +7,7 @@ use bevy_kira_audio::{AudioChannel, AudioControl, AudioInstance, AudioSource, Au ...@@ -7,6 +7,7 @@ use bevy_kira_audio::{AudioChannel, AudioControl, AudioInstance, AudioSource, Au
use crate::utilities::{AudioSettings, SuppliesAudio, TrackType}; use crate::utilities::{AudioSettings, SuppliesAudio, TrackType};
use crate::{AmbianceAudioChannel, MusicAudioChannel, SfxAudioChannel, UiSfxAudioChannel}; use crate::{AmbianceAudioChannel, MusicAudioChannel, SfxAudioChannel, UiSfxAudioChannel};
/// A wrapper for each of the audio channels created and controlled by MusicBox
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct AudioChannels<'w, 's> { pub struct AudioChannels<'w, 's> {
pub music_channel: Res<'w, AudioChannel<MusicAudioChannel>>, pub music_channel: Res<'w, AudioChannel<MusicAudioChannel>>,
...@@ -18,6 +19,12 @@ pub struct AudioChannels<'w, 's> { ...@@ -18,6 +19,12 @@ pub struct AudioChannels<'w, 's> {
_p: PhantomData<&'s ()>, _p: PhantomData<&'s ()>,
} }
/// The service object used to control your game's audio
///
/// ## `T: SuppliesAudio`
///
/// The particular implementation of `SuppliesAudio` will be used to verify that a music track exists,
/// and then to retrieve the associated `AudioSource`.
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct MusicBox<'w, 's, T: SuppliesAudio> { pub struct MusicBox<'w, 's, T: SuppliesAudio> {
channels: AudioChannels<'w, 's>, channels: AudioChannels<'w, 's>,
...@@ -36,6 +43,12 @@ pub struct MusicBoxState { ...@@ -36,6 +43,12 @@ pub struct MusicBoxState {
} }
impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
/// Start playing a new audio track on the Music channel. The provided tween will be used
/// to fade in the new track, and to fade out the old track
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn cross_fade_music<Name: ToString>( pub fn cross_fade_music<Name: ToString>(
&mut self, &mut self,
name: Name, name: Name,
...@@ -45,6 +58,13 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -45,6 +58,13 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
self.fade_in_music(name, fade) self.fade_in_music(name, fade)
} }
/// Start playing a new audio track on the Music channel. The "in_tween" will be used to fade
/// in the new audio track, while the "out_tween" will be used to fade out the old audio
/// track
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn in_out_fade_music<Name: ToString>( pub fn in_out_fade_music<Name: ToString>(
&mut self, &mut self,
name: Name, name: Name,
...@@ -55,15 +75,24 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -55,15 +75,24 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
self.fade_in_music(name, in_tween) self.fade_in_music(name, in_tween)
} }
/// Start playing a new audio track on the Music channel. If another track is playing, it will
/// be immediately stopped
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn play_music<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> { pub fn play_music<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> {
self.stop_music(); self.stop_music();
self.fade_in_music(name, AudioTween::default()) self.fade_in_music(name, AudioTween::default())
} }
/// Stop playing music on the Music channel
pub fn stop_music(&mut self) { pub fn stop_music(&mut self) {
self.fade_out_music(AudioTween::default()); self.fade_out_music(AudioTween::default());
} }
/// Stop playing music on the music channel. The supplied tween will be used to fade out the track
/// before it ends
pub fn fade_out_music(&mut self, fade: AudioTween) { pub fn fade_out_music(&mut self, fade: AudioTween) {
let handle = std::mem::replace(&mut self.state.active_music, None) let handle = std::mem::replace(&mut self.state.active_music, None)
.and_then(|handle| self.audio_instances.get_mut(&handle)); .and_then(|handle| self.audio_instances.get_mut(&handle));
...@@ -72,6 +101,12 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -72,6 +101,12 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
} }
} }
/// Start playing a new track on the music channel. If another track is playing, it will be
/// immediately stopped. The provided tween will be used to fade in the new track
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn fade_in_music<Name: ToString>( pub fn fade_in_music<Name: ToString>(
&mut self, &mut self,
name: Name, name: Name,
...@@ -94,6 +129,12 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -94,6 +129,12 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
} }
} }
/// Start playing a new audio track on the Music channel. The provided tween will be used
/// to fade in the new track, and to fade out the old track
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn cross_fade_ambiance<Name: ToString>( pub fn cross_fade_ambiance<Name: ToString>(
&mut self, &mut self,
name: Name, name: Name,
...@@ -103,6 +144,13 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -103,6 +144,13 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
self.fade_in_ambiance(name, fade) self.fade_in_ambiance(name, fade)
} }
/// Start playing a new audio track on the Music channel. The "in_tween" will be used to fade
/// in the new audio track, while the "out_tween" will be used to fade out the old audio
/// track
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn in_out_fade_ambiance<Name: ToString>( pub fn in_out_fade_ambiance<Name: ToString>(
&mut self, &mut self,
name: Name, name: Name,
...@@ -113,15 +161,24 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -113,15 +161,24 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
self.fade_in_ambiance(name, in_tween) self.fade_in_ambiance(name, in_tween)
} }
/// Start playing a new audio track on the Music channel. If another track is playing, it will
/// be immediately stopped
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn play_ambiance<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> { pub fn play_ambiance<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> {
self.stop_ambiance(); self.stop_ambiance();
self.fade_in_ambiance(name, AudioTween::default()) self.fade_in_ambiance(name, AudioTween::default())
} }
/// Stop playing ambiance on the Music channel
pub fn stop_ambiance(&mut self) { pub fn stop_ambiance(&mut self) {
self.fade_out_ambiance(AudioTween::default()); self.fade_out_ambiance(AudioTween::default());
} }
/// Stop playing ambiance on the ambiance channel. The supplied tween will be used to fade out the track
/// before it ends
pub fn fade_out_ambiance(&mut self, fade: AudioTween) { pub fn fade_out_ambiance(&mut self, fade: AudioTween) {
let handle = std::mem::replace(&mut self.state.active_ambiance, None) let handle = std::mem::replace(&mut self.state.active_ambiance, None)
.and_then(|handle| self.audio_instances.get_mut(&handle)); .and_then(|handle| self.audio_instances.get_mut(&handle));
...@@ -130,6 +187,12 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -130,6 +187,12 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
} }
} }
/// Start playing a new track on the ambiance channel. If another track is playing, it will be
/// immediately stopped. The provided tween will be used to fade in the new track
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn fade_in_ambiance<Name: ToString>( pub fn fade_in_ambiance<Name: ToString>(
&mut self, &mut self,
name: Name, name: Name,
...@@ -152,6 +215,11 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -152,6 +215,11 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
} }
} }
/// Play a new sound effect on the SFX channel
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn play_sfx<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> { pub fn play_sfx<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> {
match self.map_tracks(name) { match self.map_tracks(name) {
TrackType::WithIntro(_, track) | TrackType::Single(track) => { TrackType::WithIntro(_, track) | TrackType::Single(track) => {
...@@ -161,7 +229,11 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -161,7 +229,11 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
TrackType::Missing => None, TrackType::Missing => None,
} }
} }
/// Play a new sound effect on the UI SFX channel
///
/// # Returns
///
/// A handle for the newly started audio instance, or `None` if the track was not found
pub fn play_ui_sfx<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> { pub fn play_ui_sfx<Name: ToString>(&mut self, name: Name) -> Option<Handle<AudioInstance>> {
match self.map_tracks(name) { match self.map_tracks(name) {
TrackType::WithIntro(_, track) | TrackType::Single(track) => { TrackType::WithIntro(_, track) | TrackType::Single(track) => {
...@@ -172,6 +244,8 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -172,6 +244,8 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
} }
} }
/// Sync the actual volumes of each track to their values defined in the `AudioSettings` resource,
/// modulated by the master volume setting
pub fn sync_settings(&self) { pub fn sync_settings(&self) {
self.channels self.channels
.music_channel .music_channel
...@@ -187,26 +261,38 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { ...@@ -187,26 +261,38 @@ impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
.set_volume((self.settings.ui_volume * self.settings.master_volume) as f64); .set_volume((self.settings.ui_volume * self.settings.master_volume) as f64);
} }
/// Get a reference to the settings object
pub fn settings(&self) -> &AudioSettings { pub fn settings(&self) -> &AudioSettings {
&self.settings &self.settings
} }
/// Get a mutable reference to the settings object
pub fn settings_mut(&mut self) -> &mut AudioSettings { pub fn settings_mut(&mut self) -> &mut AudioSettings {
&mut self.settings &mut self.settings
} }
/// Sets the master volume level, as a percentage between 0-1.
/// Master volume is used to adjust all of the other volume levels
pub fn set_master_volume(&mut self, level: f32) { pub fn set_master_volume(&mut self, level: f32) {
self.settings.master_volume = level; self.settings.master_volume = level;
} }
/// Sets the music volume level, as a percentage between 0-1.
pub fn set_music_volume(&mut self, level: f32) { pub fn set_music_volume(&mut self, level: f32) {
self.settings.music_volume = level; self.settings.music_volume = level;
} }
/// Sets the ambiance volume level, as a percentage between 0-1.
pub fn set_ambiance_volume(&mut self, level: f32) { pub fn set_ambiance_volume(&mut self, level: f32) {
self.settings.ambiance_volume = level; self.settings.ambiance_volume = level;
} }
/// Sets the sfx volume level, as a percentage between 0-1.
pub fn set_sfx_volume(&mut self, level: f32) { pub fn set_sfx_volume(&mut self, level: f32) {
self.settings.sfx_volume = level; self.settings.sfx_volume = level;
} }
/// Sets the ui sfx volume level, as a percentage between 0-1.
pub fn set_ui_sfx_volume(&mut self, level: f32) { pub fn set_ui_sfx_volume(&mut self, level: f32) {
self.settings.ui_volume = level; self.settings.ui_volume = level;
} }
......
...@@ -4,6 +4,29 @@ use bevy_kira_audio::AudioSource; ...@@ -4,6 +4,29 @@ use bevy_kira_audio::AudioSource;
use crate::music_box::MusicBox; 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 micro_musicbox::utilities::{TrackType, SuppliesAudio};
/// # use bevy::prelude::*;
///
/// 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()))
/// }
/// }
/// ```
pub trait SuppliesAudio: Resource { pub trait SuppliesAudio: Resource {
fn resolve_track_name<T: ToString>(&self, name: T) -> TrackType<String>; fn resolve_track_name<T: ToString>(&self, name: T) -> TrackType<String>;
fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>>; fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>>;
...@@ -31,9 +54,14 @@ impl Default for AudioSettings { ...@@ -31,9 +54,14 @@ impl Default for AudioSettings {
} }
} }
/// Defines the type of track that a given name represents
pub enum TrackType<T> { pub enum TrackType<T> {
/// A single audio track that should be played as-is
Single(T), 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), WithIntro(T, T),
/// The requested track could not be found
Missing, Missing,
} }
...@@ -47,6 +75,9 @@ impl SuppliesAudio for AssetServer { ...@@ -47,6 +75,9 @@ impl SuppliesAudio for AssetServer {
} }
} }
/// 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>) { pub fn sync_music_volume<T: SuppliesAudio>(music: MusicBox<T>) {
music.sync_settings(); music.sync_settings();
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment