Skip to content

Commit

Permalink
Merge branch 'main' of github.com:NiklasEi/bevy_kira_audio into reexp…
Browse files Browse the repository at this point in the history
…ort_used_kira_types
  • Loading branch information
NiklasEi committed Mar 3, 2023
2 parents b964a4e + 8fa4f76 commit f066253
Show file tree
Hide file tree
Showing 16 changed files with 214 additions and 27 deletions.
12 changes: 8 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ serde = { version = "1.0", features = ["derive"], optional = true }
parking_lot = "0.12"
thiserror = "1.0"

[dev-dependencies.bevy]
version = "0.9"
default-features = false
features = ["bevy_asset", "bevy_winit", "render", "x11"]
[dev-dependencies]
bevy = { version = "0.9", default-features = false, features = ["bevy_asset", "bevy_winit", "render", "x11", "bevy_gltf", "bevy_scene"] }
bevy_flycam = "0.9"

[[example]]
name = "basic"
Expand Down Expand Up @@ -79,3 +78,8 @@ required-features = ["ogg"]
name = "channel_control"
path = "examples/channel_control.rs"
required-features = ["ogg"]

[[example]]
name = "spacial"
path = "examples/spacial.rs"
required-features = ["ogg"]
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ More settings are available. See the [`settings_loader` example](examples/settin

You can either control a whole audio channel and all instances playing in it ([`channel_control` example](examples/channel_control.rs)), or a single audio instance ([`instance_control` example](examples/instance_control.rs)). Both ways offer audio transitions with Tweens supporting multiple easings.

### Spacial audio

There is limited spacial audio support. Currently, only the volume of audio and it's panning can be automatically changed based on emitter and receiver positions. Take a look at the [`spacial` example](examples/spacial.rs) for some code.

## Compatible Bevy versions

The main branch is compatible with the latest Bevy release.
Expand Down
Binary file added assets/models/boxOpen.glb
Binary file not shown.
Binary file added assets/models/panStew.glb
Binary file not shown.
Binary file added assets/sounds/cooking.ogg
Binary file not shown.
Binary file modified assets/sounds/loop.ogg
Binary file not shown.
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ These examples are simple Bevy Apps illustrating the capabilities of `bevy_kira_
| [`multiple_channels.rs`](/examples/multiple_channels.rs) | GUI application with full control over tree different audio channels |
| [`settings.rs`](/examples/settings.rs) | Demonstrate settings supported when playing a sound |
| [`settings_loader.rs`](/examples/settings_loader.rs) | Loading a sound with applied settings |
| [`spacial.rs`](/examples/spacial.rs) | Demonstration of the limited support for spacial audio |
| [`status.rs`](/examples/status.rs) | Continuously get the playback state of a sound |
| [`stress_test.rs`](/examples/stress_test.rs) | Example app playing a high number of sounds every frame |

Expand Down
93 changes: 93 additions & 0 deletions examples/spacial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use bevy::prelude::*;
use bevy_flycam::{FlyCam, NoCameraPlayerPlugin};
use bevy_kira_audio::prelude::*;

fn main() {
App::new()
.insert_resource(Msaa { samples: 1 })
.insert_resource(SpacialAudio { max_distance: 25. })
.add_plugins(DefaultPlugins)
.add_plugin(AudioPlugin)
.add_plugin(NoCameraPlayerPlugin)
.add_startup_system(setup)
.run()
}

fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
audio: Res<Audio>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// Emitter Nr. 1
let cooking = audio
.play(asset_server.load("sounds/cooking.ogg"))
.looped()
.handle();
commands
.spawn(SceneBundle {
scene: asset_server.load("models/panStew.glb#Scene0"),
transform: Transform::from_xyz(-5.0, 0., 0.),
..default()
})
.insert(AudioEmitter {
instances: vec![cooking],
});
// Emitter Nr. 2
let elevator_music = audio
.play(asset_server.load("sounds/loop.ogg"))
.looped()
.handle();
commands
.spawn(SceneBundle {
scene: asset_server.load("models/boxOpen.glb#Scene0"),
transform: Transform::from_xyz(10., 0., 0.),
..default()
})
.insert(AudioEmitter {
instances: vec![elevator_music],
});
// Our camera will be the receiver
commands
.spawn(Camera3dBundle {
transform: Transform::from_xyz(0.0, 0.5, 10.0),
..default()
})
.insert(AudioReceiver)
.insert(FlyCam);

// Other scene setup...
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
commands.spawn( TextBundle {
text: Text {
sections: vec![TextSection {
value: "WASD to move horizontally\nSPACE to ascend\nLSHIFT to descend\nESC to grab/release cursor.".to_string(),
style: TextStyle {
font: asset_server.load("fonts/monogram.ttf"),
font_size: 40.0,
color: Color::rgb(0.9, 0.9, 0.9),
},
}],
alignment: Default::default(),
},
style: Style {
margin: UiRect::all(Val::Px(15.)),
..default()
},
..default()
});
commands.spawn(PbrBundle {
mesh: meshes.add(shape::Plane { size: 50. }.into()),
material: materials.add(Color::DARK_GREEN.into()),
..default()
});
}
14 changes: 7 additions & 7 deletions src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ use bevy::asset::{Handle, HandleId};
use bevy::ecs::system::Resource;
use bevy::prelude::default;
use kira::sound::static_sound::{StaticSoundData, StaticSoundHandle};
use kira::LoopBehavior;
use kira::{LoopBehavior, Volume};
use std::marker::PhantomData;
use std::time::Duration;

pub(crate) enum AudioCommand {
Play(PlayAudioSettings),
SetVolume(f64, Option<AudioTween>),
SetVolume(Volume, Option<AudioTween>),
SetPanning(f64, Option<AudioTween>),
SetPlaybackRate(f64, Option<AudioTween>),
Stop(Option<AudioTween>),
Expand All @@ -28,7 +28,7 @@ pub(crate) enum AudioCommand {
#[derive(Clone, Default)]
pub(crate) struct PartialSoundSettings {
pub(crate) loop_behavior: Option<Option<f64>>,
pub(crate) volume: Option<f64>,
pub(crate) volume: Option<Volume>,
pub(crate) playback_rate: Option<f64>,
pub(crate) start_position: Option<f64>,
pub(crate) panning: Option<f64>,
Expand Down Expand Up @@ -109,7 +109,7 @@ impl PartialSoundSettings {
}
}
if let Some(volume) = self.volume {
sound.settings.volume = volume.into();
sound.settings.volume = volume;
}
if let Some(playback_rate) = self.playback_rate {
sound.settings.playback_rate = playback_rate.into();
Expand Down Expand Up @@ -189,8 +189,8 @@ impl<'a> PlayAudioCommand<'a> {
}

/// Set the volume of the sound.
pub fn with_volume(&mut self, volume: f64) -> &mut Self {
self.settings.volume = Some(volume);
pub fn with_volume(&mut self, volume: impl Into<Volume>) -> &mut Self {
self.settings.volume = Some(volume.into());

self
}
Expand Down Expand Up @@ -250,7 +250,7 @@ impl<'a> PlayAudioCommand<'a> {
}

pub(crate) enum TweenCommandKind {
SetVolume(f64),
SetVolume(Volume),
SetPanning(f64),
SetPlaybackRate(f64),
Stop,
Expand Down
6 changes: 3 additions & 3 deletions src/audio_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ use bevy::ecs::world::{FromWorld, World};
use bevy::log::{error, warn};
use kira::manager::backend::{Backend, DefaultBackend};
use kira::manager::AudioManager;
use kira::{CommandError, PlaybackRate};
use kira::{CommandError, PlaybackRate, Volume};
use std::collections::HashMap;

/// Non-send resource that acts as audio output
///
/// This struct holds the [`kira::manager::AudioManager`] to play audio through. It also
/// This struct holds the [`AudioManager`] to play audio through. It also
/// keeps track of all audio instance handles and which sounds are playing in which channel.
pub(crate) struct AudioOutput<B: Backend = DefaultBackend> {
manager: Option<AudioManager<B>>,
Expand Down Expand Up @@ -135,7 +135,7 @@ impl<B: Backend> AudioOutput<B> {
&mut self,
channel: &Channel,
audio_instances: &mut Assets<AudioInstance>,
volume: f64,
volume: Volume,
tween: &Option<AudioTween>,
) {
if let Some(instances) = self.instances.get_mut(channel) {
Expand Down
8 changes: 5 additions & 3 deletions src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::instance::AudioInstance;
use crate::{AudioSource, PlaybackState};
use bevy::asset::Handle;
use kira::sound::static_sound::StaticSoundData;
use kira::Volume;
use std::any::TypeId;

#[derive(Clone, PartialEq, Eq, Hash)]
Expand All @@ -16,7 +17,7 @@ pub enum Channel {

pub(crate) struct ChannelState {
pub(crate) paused: bool,
pub(crate) volume: f64,
pub(crate) volume: Volume,
pub(crate) playback_rate: f64,
pub(crate) panning: f64,
}
Expand All @@ -25,7 +26,7 @@ impl Default for ChannelState {
fn default() -> Self {
ChannelState {
paused: false,
volume: 1.0,
volume: 1.0.into(),
playback_rate: 1.0,
panning: 0.5,
}
Expand Down Expand Up @@ -93,6 +94,7 @@ pub trait AudioControl {
/// Set the volume
///
/// The default value is 1.
/// This method supports setting the volume in Decibels or as Amplitude.
///
/// ```
/// # use bevy::prelude::*;
Expand All @@ -102,7 +104,7 @@ pub trait AudioControl {
/// audio.set_volume(0.5);
/// }
/// ```
fn set_volume(&self, volume: f64) -> TweenCommand<FadeIn>;
fn set_volume(&self, volume: impl Into<Volume>) -> TweenCommand<FadeIn>;

/// Set panning
///
Expand Down
6 changes: 4 additions & 2 deletions src/channel/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{AudioControl, AudioSource, PlaybackState};
use bevy::asset::{Handle, HandleId};
use bevy::ecs::system::Resource;
use bevy::utils::HashMap;
use kira::Volume;
use parking_lot::RwLock;
use std::collections::VecDeque;

Expand Down Expand Up @@ -82,6 +83,7 @@ impl AudioControl for DynamicAudioChannel {
/// Set the volume
///
/// The default value is 1.
/// This method supports setting the volume in Decibels or as Amplitude.
///
/// ```
/// # use bevy::prelude::*;
Expand All @@ -91,8 +93,8 @@ impl AudioControl for DynamicAudioChannel {
/// audio.set_volume(0.5);
/// }
/// ```
fn set_volume(&self, volume: f64) -> TweenCommand<FadeIn> {
TweenCommand::new(TweenCommandKind::SetVolume(volume), self)
fn set_volume(&self, volume: impl Into<Volume>) -> TweenCommand<FadeIn> {
TweenCommand::new(TweenCommandKind::SetVolume(volume.into()), self)
}
/// Set panning
///
Expand Down
5 changes: 3 additions & 2 deletions src/channel/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{AudioControl, AudioSource, PlaybackState};
use bevy::asset::{Handle, HandleId};
use bevy::ecs::system::Resource;
use bevy::utils::HashMap;
use kira::Volume;
use parking_lot::RwLock;
use std::collections::VecDeque;
use std::marker::PhantomData;
Expand Down Expand Up @@ -108,8 +109,8 @@ impl<T> AudioControl for AudioChannel<T> {
/// audio.set_volume(0.5);
/// }
/// ```
fn set_volume(&self, volume: f64) -> TweenCommand<FadeIn> {
TweenCommand::new(TweenCommandKind::SetVolume(volume), self)
fn set_volume(&self, volume: impl Into<Volume>) -> TweenCommand<FadeIn> {
TweenCommand::new(TweenCommandKind::SetVolume(volume.into()), self)
}

/// Set panning
Expand Down
10 changes: 7 additions & 3 deletions src/instance.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{AudioTween, PlaybackState};
use bevy::asset::{Assets, Handle};
use kira::sound::static_sound::StaticSoundHandle;
use kira::CommandError;
use kira::{CommandError, Volume};
use thiserror::Error;

#[derive(bevy::reflect::TypeUuid)]
Expand Down Expand Up @@ -57,15 +57,19 @@ impl AudioInstance {
.map(|kira_error| kira_error.into())
}

/// Pause the audio instance with the given easing
/// Get the state of the audio instance
pub fn state(&self) -> PlaybackState {
(&self.handle).into()
}

/// Set the volume of the audio instance
///
/// Default is `1.0`
pub fn set_volume(&mut self, volume: f64, tween: AudioTween) -> Option<AudioCommandError> {
pub fn set_volume(
&mut self,
volume: impl Into<Volume>,
tween: AudioTween,
) -> Option<AudioCommandError> {
self.handle
.set_volume(volume, tween.into())
.err()
Expand Down
11 changes: 8 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ mod backend_settings;
mod channel;
mod instance;
mod source;
mod spacial;

pub use audio::{
AudioApp, AudioEasing, AudioTween, FadeIn, FadeOut, PlayAudioCommand, PlaybackState,
Expand Down Expand Up @@ -69,6 +70,8 @@ pub mod prelude {
#[doc(hidden)]
pub use crate::source::AudioSource;
#[doc(hidden)]
pub use crate::spacial::{AudioEmitter, AudioReceiver, SpacialAudio};
#[doc(hidden)]
pub use crate::{Audio, AudioPlugin, MainTrack};
pub use kira::{
dsp::Frame,
Expand All @@ -92,6 +95,7 @@ use crate::source::ogg_loader::OggLoader;
use crate::source::settings_loader::SettingsLoader;
#[cfg(feature = "wav")]
use crate::source::wav_loader::WavLoader;
use crate::spacial::run_spacial_audio;
use bevy::prelude::{
AddAsset, App, CoreStage, IntoSystemDescriptor, Plugin, Resource, SystemLabel,
};
Expand Down Expand Up @@ -136,7 +140,8 @@ impl Plugin for AudioPlugin {
fn build(&self, app: &mut App) {
app.init_non_send_resource::<AudioOutput>()
.add_asset::<AudioSource>()
.add_asset::<AudioInstance>();
.add_asset::<AudioInstance>()
.add_system_to_stage(CoreStage::PostUpdate, run_spacial_audio);

#[cfg(feature = "mp3")]
app.init_asset_loader::<Mp3Loader>();
Expand Down Expand Up @@ -177,13 +182,13 @@ pub enum AudioSystemLabel {
/// The default audio channel
///
/// Alias for the [`AudioChannel<MainTrack>`] resource. Use it to play and control sound on the main track.
/// You can add your own channels via [`add_audio_channel`](audio::AudioApp::add_audio_channel).
/// You can add your own channels via [`add_audio_channel`](AudioApp::add_audio_channel).
pub type Audio = AudioChannel<MainTrack>;

/// Type for the default audio channel
///
/// Use it via the [`AudioChannel<MainTrack>`] resource to play and control sound on the main track.
/// You can add your own channels via [`add_audio_channel`](audio::AudioApp::add_audio_channel).
/// You can add your own channels via [`add_audio_channel`](AudioApp::add_audio_channel).
///
/// You can use [`Audio`] as a type alias for [`AudioChannel<MainTrack>`]
#[derive(Resource)]
Expand Down
Loading

0 comments on commit f066253

Please sign in to comment.