common-audio-traits
)There are a lot of audio backend libraries. Authors must implement their libraries in accordance with every audio backend. This is miserable as a non-backend audio library author.
The default audio crate for bevy is lacking. As such, many people have made alternative audio libraries such as bevy_kira_audio
, and bevy_oddio
, using different audio backends (kira
and oddio
, respectively).
This creates a fracture in the bevy audio ecosystem, and libraries dealing with audio in bevy find that one needs to implement their library in accordance with every bevy audio backend library (bevy_fundsp
).
If the backend of bevy_audio
is abstracted, then future audio non-backend libraries will not have to rely on specific backend details. Users can simply plug-and-play their own preferred audio backend (the default will be rodio
), and library authors can write their own code without relying on any specific underlying implementation.
In the case for bevy_fundsp
, three different implementations are made and gated in mutually-exclusive features. This violates Rust's assumption that features are additive. Therefore, weird errors pop up, which the user may not understand at first glance.
Here are some real code that reflects this fracture of audio backend libraries (If you have your own audio library, please share your implementation in a reply).
bevy_fundsp
Copying from the bevy_fundsp
implementation of Backend
:
This is the initial code for abstracting different audio backends, used for bevy_fundsp
.
Tangentially related is bevy_fundsp
's extension trait for Audio
types
These requirements should be met when designing an implementation for this (potential) RFC.
bevy_audio
should allow different backends such rodio
, kira
, oddio
, or other rust libraries. Users can simply choose which backend to use, and non-backend library authors can simply not care about its implementation details.bevy_audio
.AudioSource
s should not care about its presentation, only when its a custom Read + Seek
or Iterator<Item = Frame>
.Here are the common types that are present for all audio backend libraries:
Audio
type)!Sync
and Send
)Asset
and Sync
These are types that contain all the bytes of the audio. Audio bytes are loaded in memory all at once.
Library | Type | Note |
---|---|---|
bevy_audio |
AudioSource |
rodio does not have an equivalent static audio source. bevy_audio uses Arc<[u8]> internally. |
bevy_kira_audio |
AudioSource |
uses StaticSoundData in kira internally |
bevy_oddio |
AudioSource |
uses oddio::Frames internally |
Library | Type |
---|---|
bevy_audio |
AudioSink |
bevy_kira_audio |
PlayAudioCommand |
bevy_oddio |
AudioSink |
These are usually accessed through a resource.
Library | Type | Note |
---|---|---|
bevy_audio |
Audio |
|
bevy_kira_audio |
AudioChannel or DynamicAudioChannel |
Audio is simply a type definition for AudioChannel<MainTrack> |
bevy_oddio |
Audio |
These traits allow users to implement their own audio type.
Library | Trait | Note |
---|---|---|
bevy_audio |
Decodable::Decoder |
internally uses rodio::Source . |
bevy_kira_audio |
does not support it as of 0.12 | kira has Sound |
bevy_oddio |
oddio::Signal |
exposes oddio::Signal directly |
Typically this is needed to implement bevy's Asset
, therefore Sync
.
Library | Trait | Note |
---|---|---|
bevy_audio |
Decodable |
rodio has no equivalent trait |
bevy_kira_audio |
does not support it as of 0.12 | kira has SoundData |
bevy_oddio |
ToSignal |
oddio has no equivalent trait |
This is typically different from audio sinks, as this allows custom control of playing audio.
Library | Trait | Note |
---|---|---|
bevy_audio |
N/A | rodio has no equivalent trait |
bevy_kira_audio |
N/A | kira has SoundData::Handle |
bevy_oddio |
oddio::Signal that implements Controlled , which has Controlled::Control |
mp3
wave
ogg
flac
AudioSource
AudioSource
is now a trait. Frame
is simply [f32; 2]
or similar, which represents the left and right channels in stereo.
There should be a way to convert a vector of frames into a static audio source.
AudioSink
AudioSink
are traits that have the basic functionality of being… an audio sink.
AudioOutput
AudioOutput
is now a trait that simply handles the audio thread.
AudioData
AudioData
is the Asset
form of AudioSource
. Generally AudioSource
is usually Send
but not Sync
, so we make another trait to convert audio data into audio sources. This is similar to bevy_audio
's Decodable
, kira
's SoundData
, and bevy_oddio
's ToSignal
traits.
AudioMixer
and Audio
AudioMixer
is the public API usually accessed by the user through a resource. Generally implementing libraries should have type alias that specifies the AudioOutput
used.
AudioLoader
Audio loaders are simply types that implement AssetLoader
. It's up to the backend library authors to implement them.
AudioPlugin
Plugins will not be provided by bevy_audio
. This will be provided by backend authors. Generally this type will:
StaticSource
as a libraryBackend library authors must implement the following traits to their own types:
Source
StaticSource
Sink
Output
AudioData
Users should essentially see no API changes (except for imports). They can choose their own custom backend (currently rodio
, kira
, and oddio
in the bevy ecosystem).
AudioPlugin
should be from the backend libraries and not from bevy_audio
, as each backend library will have their own way of setting up their audio threads, systems, resources, components, etc.
bevy_audio
?As a non-backend library author, working with the bevy audio ecosystem is frustrating:
rodio
? Why not focus on kira
?Each audio backend library has their own use cases:
kira
focuses on timing audio correctly. This is why it has functionalities related to tweening and clocks.oddio
is more on raw digital signal processing. It works by using iterator-like combinators that you combine together to manipulate audio in real time. As such, it places less focus on static audio files, and more on procedural generation and manipulation of audio.synthizer
, an unpublished audio backend crate, is heavily optimized for binaural audio that brings a native dependency.rodio
is rodio
.Since there are currently three main contenders for backend libraries (rodio
, kira
, and oddio
), this will cause non-backend library authors to create three exclusive crate features for their library. This creates a very frustrating experience, as exclusive features are not well supported in Rust.
Users should not care about implementation details, unless they need specific functionalities provided by their chosen backend libraries.
rodio
? It has many potential problems with its API, and it has a problem regarding stereo audio. (See rodio#444 and bevy#6122)kira
? This is the best potential default backend for bevy, however I found some features lacking, like sound effects and digital signal processing.oddio
? This is pretty much bare bones in terms of its features, opting for more flexibility for the user. It has first class support for spatial audio. It does not, however, output audio, rather only manipulate signals. bevy_oddio
handles this by using cpal
directly.bevy-rrise
mesh in this RFC?
bevy-rrise
can simply ignore this, as this has a vastly different architecture compared to other backend crates.