Releases: tesselode/kira
v0.10.1
v0.10.0
Buffered audio
Kira now processes audio in chunks instead of one sample at a time. This means that Sound::process
no longer returns a Frame
; instead it receives a slice of Frame
s to overwrite. Effect::process
takes an input slice instead of a single frame, and it overwrites that slice instead of returning a new Frame
.
The benefit of this change is significantly improved performance. The criterion benchmarks aren't comparable to the ones in v0.9.x and earlier, but in my unscientific test, I can play about twice as many sounds on my PC without crackling.
There are some tradeoffs, but I think they're reasonable:
- Modulators are no longer sample accurate. Instead, they update once per internal processing chunk. Sounds and effects can interpolate between the previous and current modulator value using
Parameter::interpolated_value
to avoid discontinuities. - Clocks are no longer sample accurate. For my use case which involves dynamically generating music, the default internal buffer size of 128 frames sounds almost exactly the same as sample-accurate clocks. You can adjust the internal buffer size to get the right tradeoff of performance vs. accuracy for your game. I have some ideas for how sample-accurate clocks could be implemented within the buffered architecture, so if you find yourself needing sample-accurate clocks, let me know!
- The delay effect can no longer have its delay time changed after the fact. If you know how to implement a delay that can smoothly change its delay time with the buffered architecture, please make a PR!
Hierarchical mixer
Sounds now live inside mixer tracks. Previously, to play a sound on a mixer track, you would use StaticSoundData
/StreamingSoundData::output_destination
. Now, you pass the sound to TrackHandle::play
. Additionally, tracks can contain other tracks. Tracks can also route their outputs to send tracks, which are a separate concept now. This change enables the following feature:
Pausing and resuming mixer tracks
Mixer tracks can now be paused and resumed. Pausing a mixer track pauses all sounds playing on the track, as well as all child tracks.
Spatial audio overhaul
The concepts of spatial scenes and emitters have been removed, and listeners no longer output to a mixer track. Instead, mixer tracks can optionally have spatial properties, like position and spatialization strength. Sounds and child tracks on the track will have spatialization applied relative to a specified listener.
This release also adds Value::FromListenerDistance
, which can be used to map sound and effect parameters to the distance between a spatial track and its corresponding listener.
Simplified volume and playback rate types
Previously, Volume
was an enum with Amplitude
and Decibels
variants, and PlaybackRate
was an enum with Factor
and Semitones
variants. There's a couple problems with this:
- It's unclear what scale a tween uses when tweening from one variant to another. For instance, if you tween a
Volume::Amplitude
to aVolume::Decibels
with linear easing, is it linear in the amplitude domain or decibels? - Amplitude isn't a good default representation for volume because it's not perceptually linear.
Now, everything that previously used Volume
uses the simpler Decibels
type, and PlaybackRate
always contains a factor. (Semitones
still exists as a separate type that implements Into<PlaybackRate>
).
There's also a new Panning
type that's used instead of bare f64
s. Panning has been changed so -1.0
is left instead of 0.0
, since this makes more sense mathematically.
Other changes
- Reorganized some types and modules to reduce unnecessary nesting
- Added
WaitingToResume
andResuming
variants toPlaybackState
- Changes to
Mapping
:- Added an
easing
field - Inputs are now always clamped to the input range
- Removed the
Default
implementation - Added methods for performing math operations on the output range
- Added an
- Implemented some math operations to
Value
- Changed the fields of
Capacities
back tou64
s ClockInfoProvider
andModulatorValueProvider
and now combined into one
Info
struct, which also provides info about spatial audio state- Added
CpalBackend::pop_cpu_usage
(desktop only for now)
v0.9.6
v0.9.5
v0.9.4
v0.9.3
v0.9.2
- Fix StaticSoundHandle/StreamingSoundHandle::pause/resume/stop not taking effect immediately if the sound has a start time. This was an unintended change from the behavior in v0.8.x and earlier versions.
- Fix sounds erroneously reporting their state as Playing before playback has resumed after calling StaticSoundHandle/StreamingSoundHandle::resume_at with a non-immediate StartTime
- Fix sounds entering a limbo state where they output no sound and can never be unloaded when their output destination (track or emitter) is removed
- Fix a bug where static sounds could enter a limbo state where they're stopped, but never unloaded if the clock they're waiting on is removed
v0.9.1
v0.9.0
v0.9.0 - May 11, 2024
ClockTime::fraction
ClockTime
now has a fraction
field, which represents a fraction of a tick. This means sounds and tweens can be scheduled for times in-between ticks.
In addition, ClockHandle::fractional_position
has been removed because ClockHandle::time
provides that info anyway, and the shape of ClockInfo
has changed to hold a ClockTime
(this is only relevant if you're creating implementations of one of Kira's traits).
Added configuration for the CpalBackend
(Implemented by @zeozeozeo)
The device and buffer size used by the CpalBackend
are now configurable via CpalBackendSettings
.
Most param changes are now infallible
Anything that could previously fail because of a command buffer filling up or getting poisoned can no longer fail that way, so you can call functions like Emitter::set_position
as frequently as you want.
Updated API for sound start positions and playback regions
v0.8 introduced a playback_region
setting for static and streaming sounds which replaced the previous start_position
setting. It was meant to serve two purposes:
- Allow you to play only a portion of a sound
- Allow setting the start position of the sound
However, these two purposes had an unintuitive interaction. Say you want to play a sound starting 3 seconds in. In v0.8, you would do something like this:
manager.play(
StaticSoundData::from_file(
"test.ogg",
StaticSoundSettings::new().playback_region(3..),
)?,
)?;
Then let's say you wanted to seek the sound to 2 seconds. The sound would stop because you've set the playback region not to include that part of the sound, when all you really wanted to do was set the start position.
In v0.9, these two purposes are separated. The playback_region
setting has been reverted to the start_position
setting from versions before v0.8, and to serve the purpose of playing portions of sounds, slice
methods have been added to StaticSoundData
and StreamingSoundData
.
Note that the loop_region
option added in v0.8 remains and works the same way in v0.9.
StartTime::delayed
Previously, you could delay the playback of a static sound by setting its start position to a negative number. This only worked with static sounds, however, not streaming sounds or tweens. This is now disallowed, which allows for some minor internal code cleanup. In its place is the more explicit and intuitive StartTime::delayed
, which works with anything that has a StartTime
.
Static/StreamingSoundHandle::resume_at
Previously, if you paused a sound and set the fade-in tween to have a start time in the future, the sound wouldn't become audible until the start time, but it would still be advancing in the background as soon as you called resume
. The resume_at
method delays playback until the specified StartTime
.
Added settings methods to Static/StreamingSoundData
Chainable methods have been added to StaticSoundData
and StreamingSoundData
to change settings on the sound data. So instead of doing this:
let sound = StaticSoundData::from_file("sound.ogg", StaticSoundSettings::new()
.volume(0.5)
.playback_rate(2.0)
)?;
You can use this less verbose code:
let sound = StaticSoundData::from_file("sound.ogg")?
.volume(0.5)
.playback_rate(2.0);
StaticSoundSettings
and StreamingSoundSettings
still exist and are still fields of the corresponding SoundData
s, so you can still store settings independently of a sound data.
Resource capacities are now u16
s
This allows for some performance improvements, but it does mean you are limited to 65,536 of each kind of resource (sounds, clocks, etc.). I apologize to anyone who was trying to play more than 65k sounds.
Remove AudioManager::pause/resume
This feature was thrown into a previous version of Kira as a quick and dirty way to pause/resume all sounds. However, it's the wrong tool for the job, since it pauses and resumes the entire audio system, which is almost never what you want.
Performance improvements
The benchmarks run about 26-29% faster (on my machine) compared to v0.8.7.
Other changes
- Added
android_shared_stdcxx
feature - Update
glam
to 0.27 - Added
TrackBuilder::add_built_effect
andTrackBuilder::with_built_effect
- Improve performance when using
start_position
with streaming sounds - Remove
RangeInclusive
conversions forRegion
s, as all current uses of
Region
s treat the end bound as exclusive - Stop streaming sounds immediately if there's a decoding error
- Remove all uses of
#[non_exhaustive]
- Add
#[must_use]
where appropriate - Moved some types and modules to reduce excessive nesting
AudioManager::main_track
now returns&mut TrackHandle
instead ofTrackHandle