Skip to content

Commit

Permalink
Update to Kira 0.9
Browse files Browse the repository at this point in the history
  • Loading branch information
NiklasEi committed Jan 3, 2025
1 parent 2f69421 commit 8563e1e
Show file tree
Hide file tree
Showing 14 changed files with 57 additions and 162 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

- update Kira to 0.9
- removed `playback_region` from `SoundSettings`
- fix spatial audio when position of receiver and emitter are the same ([#135](https://github.com/NiklasEi/bevy_kira_audio/issues/135))

## v0.21.0 - 30.11.2024
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ settings_loader = ["dep:ron", "dep:serde", "kira/serde"]
bevy = { version = "0.15.0", default-features = false, features = ["bevy_asset"] }
anyhow = "1.0"
uuid = { version = "1", features = ["fast-rng"] }
kira = { version = "0.8.7", default-features = false, features = ["cpal"] }
kira = { version = "0.9.6", default-features = false, features = ["cpal"] }
ron = { version = "0.8", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
parking_lot = "0.12"
Expand Down
2 changes: 1 addition & 1 deletion assets/sounds/loop_with_settings.ogg.ron
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
file: "sounds/loop.ogg",

// Start sound at 2 seconds
playback_region: Region(start: Seconds(2.), end: EndOfAudio),
start_position: 2.,
// Half amplitude
volume: 0.5,
// Play 50% faster (this also changes the pitch)
Expand Down
2 changes: 1 addition & 1 deletion examples/stress_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bevy::prelude::*;
use bevy_kira_audio::prelude::*;

/// This example needs to be played in release mode! `cargo run --example stress_test --release`
/// A large amount (75) of sounds will be played in every frame.
/// A large amount (100) of sounds will be played in every frame.
///
/// The main objective here is to demonstrate that the plugin and Kira can handle
/// large sound volumes over a longer period of time.
Expand Down
19 changes: 5 additions & 14 deletions src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::marker::PhantomData;
use std::time::Duration;
use uuid::Uuid;

#[derive(Debug)]
pub(crate) enum AudioCommand {
Play(PlayAudioSettings),
SetVolume(Volume, Option<AudioTween>),
Expand All @@ -28,14 +29,13 @@ pub(crate) enum AudioCommand {
Resume(Option<AudioTween>),
}

#[derive(Clone, Default)]
#[derive(Clone, Default, Debug)]
pub(crate) struct PartialSoundSettings {
pub(crate) loop_start: Option<f64>,
pub(crate) loop_end: Option<f64>,
pub(crate) volume: Option<Volume>,
pub(crate) playback_rate: Option<f64>,
pub(crate) start_position: Option<f64>,
pub(crate) end_position: Option<f64>,
pub(crate) panning: Option<f64>,
pub(crate) reverse: Option<bool>,
pub(crate) paused: bool,
Expand All @@ -45,10 +45,10 @@ pub(crate) struct PartialSoundSettings {
/// Different kinds of easing for fade-in and fade-out
pub type AudioEasing = kira::tween::Easing;

#[derive(Clone)]
/// A tween for audio transitions
///
/// Use the default for almost instantaneous transitions without audio artifacts
#[derive(Clone, Debug)]
pub struct AudioTween {
duration: Duration,
easing: AudioEasing,
Expand Down Expand Up @@ -133,10 +133,7 @@ impl PartialSoundSettings {
sound.settings.playback_rate = playback_rate.into();
}
if let Some(start) = self.start_position {
sound.settings.playback_region.start = start.into();
}
if let Some(end) = self.end_position {
sound.settings.playback_region.end = EndPosition::Custom(end.into());
sound.settings.start_position = start.into();
}
if let Some(panning) = self.panning {
sound.settings.panning = Value::Fixed(panning);
Expand All @@ -154,6 +151,7 @@ impl PartialSoundSettings {
}
}

#[derive(Debug)]
pub struct PlayAudioSettings {
pub(crate) instance_handle: Handle<AudioInstance>,
pub(crate) source: Handle<AudioSource>,
Expand Down Expand Up @@ -244,13 +242,6 @@ impl<'a> PlayAudioCommand<'a> {
self
}

/// End the sound at the given position in seconds.
pub fn end_at(&mut self, end_position: f64) -> &mut Self {
self.settings.end_position = Some(end_position);

self
}

/// Set the panning of the sound.
///
/// The default value is 0.5.
Expand Down
57 changes: 12 additions & 45 deletions src/audio_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ use bevy::asset::{Assets, Handle};
use bevy::ecs::change_detection::{NonSendMut, ResMut};
use bevy::ecs::system::{NonSend, Res, Resource};
use bevy::ecs::world::{FromWorld, World};
use bevy::log::{error, warn};
use bevy::log::warn;
use kira::manager::backend::{Backend, DefaultBackend};
use kira::manager::AudioManager;
use kira::{sound::PlaybackRate, CommandError, Volume};
use kira::{sound::PlaybackRate, Volume};
use std::collections::HashMap;

/// Non-send resource that acts as audio output
Expand Down Expand Up @@ -57,15 +57,7 @@ impl<B: Backend> AudioOutput<B> {
let tween = map_tween(tween);
for instance in instances {
if let Some(instance) = audio_instances.get_mut(instance.id()) {
match instance.handle.stop(tween) {
Err(CommandError::CommandQueueFull) => {
return AudioCommandResult::Retry;
}
Err(error) => {
error!("Failed to stop instance: {:?}", error);
}
_ => (),
}
instance.handle.stop(tween);
}
}
}
Expand All @@ -84,9 +76,7 @@ impl<B: Backend> AudioOutput<B> {
for instance in instance_handles.iter_mut() {
if let Some(instance) = audio_instances.get_mut(instance.id()) {
if kira::sound::PlaybackState::Playing == instance.handle.state() {
if let Err(error) = instance.handle.pause(tween) {
error!("Failed to pause instance: {:?}", error);
}
instance.handle.pause(tween);
}
}
}
Expand Down Expand Up @@ -116,9 +106,7 @@ impl<B: Backend> AudioOutput<B> {
|| instance.handle.state() == kira::sound::PlaybackState::Pausing
|| instance.handle.state() == kira::sound::PlaybackState::Stopping
{
if let Err(error) = instance.handle.resume(tween) {
error!("Failed to resume instance: {:?}", error);
}
instance.handle.resume(tween);
}
}
}
Expand All @@ -142,9 +130,7 @@ impl<B: Backend> AudioOutput<B> {
let tween = map_tween(tween);
for instance in instances.iter_mut() {
if let Some(instance) = audio_instances.get_mut(instance.id()) {
if let Err(error) = instance.handle.set_volume(volume, tween) {
error!("Failed to set volume for instance: {:?}", error);
}
instance.handle.set_volume(volume, tween);
}
}
}
Expand All @@ -170,9 +156,7 @@ impl<B: Backend> AudioOutput<B> {
let tween = map_tween(tween);
for instance in instances.iter_mut() {
if let Some(instance) = audio_instances.get_mut(instance.id()) {
if let Err(error) = instance.handle.set_panning(panning, tween) {
error!("Failed to set panning for instance: {:?}", error);
}
instance.handle.set_panning(panning, tween);
}
}
}
Expand All @@ -198,9 +182,7 @@ impl<B: Backend> AudioOutput<B> {
let tween = map_tween(tween);
for instance in instances.iter_mut() {
if let Some(instance) = audio_instances.get_mut(instance.id()) {
if let Err(error) = instance.handle.set_playback_rate(playback_rate, tween) {
error!("Failed to set playback rate for instance: {:?}", error);
}
instance.handle.set_playback_rate(playback_rate, tween);
}
}
}
Expand Down Expand Up @@ -244,32 +226,17 @@ impl<B: Backend> AudioOutput<B> {
let mut sound_handle = sound_handle.unwrap();
if let Some(channel_state) = self.channels.get(channel) {
if channel_state.paused {
if let Err(error) = sound_handle.pause(kira::tween::Tween::default()) {
warn!(
"Failed to pause instance (channel was paused) due to {:?}",
error
);
}
sound_handle.pause(kira::tween::Tween::default());
let playback_rate = partial_sound_settings
.playback_rate
.unwrap_or(channel_state.playback_rate);
if let Err(error) =
sound_handle.set_playback_rate(playback_rate, kira::tween::Tween::default())
{
error!("Failed to set playback rate for instance: {:?}", error);
}
sound_handle.set_playback_rate(playback_rate, kira::tween::Tween::default());
}
}
if partial_sound_settings.paused {
if let Err(error) = sound_handle.pause(kira::tween::Tween::default()) {
warn!("Failed to pause instance due to {:?}", error);
}
sound_handle.pause(kira::tween::Tween::default());
let playback_rate = partial_sound_settings.playback_rate.unwrap_or(1.0);
if let Err(error) =
sound_handle.set_playback_rate(playback_rate, kira::tween::Tween::default())
{
error!("Failed to set playback rate for instance: {:?}", error);
}
sound_handle.set_playback_rate(playback_rate, kira::tween::Tween::default());
}
audio_instances.insert(
&instance_handle,
Expand Down
2 changes: 1 addition & 1 deletion src/backend_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct AudioSettings {
/// Note that configuring a channel will cause one command per sound in the channel!
pub command_capacity: usize,
/// The maximum number of sounds that can be playing at a time.
pub sound_capacity: usize,
pub sound_capacity: u16,
}

impl Default for AudioSettings {
Expand Down
88 changes: 17 additions & 71 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,28 @@ use crate::{AudioTween, PlaybackState};
use bevy::asset::{Asset, Assets, Handle};
use kira::sound::static_sound::StaticSoundHandle;
use kira::tween::Value;
use kira::{CommandError, Volume};
use thiserror::Error;
use kira::Volume;

#[derive(Asset, bevy::reflect::TypePath)]
/// Asset for direct audio control
pub struct AudioInstance {
pub(crate) handle: StaticSoundHandle,
}

/// Errors that can occur when directly controlling audio
#[derive(Error, Debug)]
pub enum AudioCommandError {
/// The audio command que of the audio manager is full
#[error("the audio thread could not handle the command, because its command que is full")]
CommandQueueFull,

/// Something went wrong when handling the command in the audio thread
#[error("an error occurred while handling the command in the audio thread")]
AudioThreadError,
}

impl From<CommandError> for AudioCommandError {
fn from(kira_error: CommandError) -> Self {
match kira_error {
CommandError::CommandQueueFull => AudioCommandError::CommandQueueFull,
_ => AudioCommandError::AudioThreadError,
}
}
}

impl AudioInstance {
/// Pause the audio instance with the given easing
pub fn pause(&mut self, tween: AudioTween) -> Option<AudioCommandError> {
self.handle
.pause(tween.into())
.err()
.map(|kira_error| kira_error.into())
pub fn pause(&mut self, tween: AudioTween) {
self.handle.pause(tween.into());
}

/// Resume the audio instance with the given easing
pub fn resume(&mut self, tween: AudioTween) -> Option<AudioCommandError> {
self.handle
.resume(tween.into())
.err()
.map(|kira_error| kira_error.into())
pub fn resume(&mut self, tween: AudioTween) {
self.handle.resume(tween.into());
}

/// Stop the audio instance with the given easing
pub fn stop(&mut self, tween: AudioTween) -> Option<AudioCommandError> {
self.handle
.stop(tween.into())
.err()
.map(|kira_error| kira_error.into())
pub fn stop(&mut self, tween: AudioTween) {
self.handle.stop(tween.into());
}

/// Get the state of the audio instance
Expand All @@ -65,58 +34,35 @@ impl AudioInstance {
/// Set the volume of the audio instance
///
/// Default is `1.0`
pub fn set_volume(
&mut self,
volume: impl Into<Value<Volume>>,
tween: AudioTween,
) -> Option<AudioCommandError> {
self.handle
.set_volume(volume, tween.into())
.err()
.map(|kira_error| kira_error.into())
pub fn set_volume(&mut self, volume: impl Into<Value<Volume>>, tween: AudioTween) {
self.handle.set_volume(volume, tween.into());
}

/// Sets the playback rate of the sound.
///
/// Changing the playback rate will change both the speed
/// and pitch of the sound.
pub fn set_playback_rate(
&mut self,
playback_rate: f64,
tween: AudioTween,
) -> Option<AudioCommandError> {
self.handle
.set_playback_rate(playback_rate, tween.into())
.err()
.map(|kira_error| kira_error.into())
pub fn set_playback_rate(&mut self, playback_rate: f64, tween: AudioTween) {
self.handle.set_playback_rate(playback_rate, tween.into());
}

/// Sets the panning of the sound
///
/// `0.0` is hard left,
/// `0.5` is center (default)
/// `1.0` is hard right.
pub fn set_panning(&mut self, panning: f64, tween: AudioTween) -> Option<AudioCommandError> {
self.handle
.set_panning(panning, tween.into())
.err()
.map(|kira_error| kira_error.into())
pub fn set_panning(&mut self, panning: f64, tween: AudioTween) {
self.handle.set_panning(panning, tween.into());
}

/// Sets the playback position to the specified time in seconds.
pub fn seek_to(&mut self, position: f64) -> Option<AudioCommandError> {
self.handle
.seek_to(position)
.err()
.map(|kira_error| kira_error.into())
pub fn seek_to(&mut self, position: f64) {
self.handle.seek_to(position);
}

/// Moves the playback position by the specified amount of time in seconds.
pub fn seek_by(&mut self, amount: f64) -> Option<AudioCommandError> {
self.handle
.seek_by(amount)
.err()
.map(|kira_error| kira_error.into())
pub fn seek_by(&mut self, amount: f64) {
self.handle.seek_by(amount);
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub mod prelude {
#[doc(hidden)]
pub use crate::channel::AudioControl;
#[doc(hidden)]
pub use crate::instance::{AudioCommandError, AudioInstance, AudioInstanceAssetsExt};
pub use crate::instance::{AudioInstance, AudioInstanceAssetsExt};
#[doc(hidden)]
#[cfg(feature = "flac")]
pub use crate::source::flac_loader::*;
Expand All @@ -92,12 +92,11 @@ pub mod prelude {
#[doc(hidden)]
pub use crate::{Audio, AudioPlugin, MainTrack};
pub use kira::{
dsp::Frame,
sound::{
static_sound::{StaticSoundData, StaticSoundSettings},
FromFileError, Sound, SoundData,
},
Volume,
Frame, Volume,
};
}

Expand Down
Loading

0 comments on commit 8563e1e

Please sign in to comment.