Skip to main content

Crate banished_audio

Crate banished_audio 

Source
Expand description

§banished-audio

Sound for the game and the viewer. It decodes the game’s sounds (xWMA, with banished-wma) in the program itself, and plays them on a device with 64 channels, as the original Audio::Device does. On the desktop it plays through rodio; in the browser it plays through Web Audio. No converted sound files are needed.

PartWhat it does
decode, load_soundDecode a SoundBuffer (and the .str stream of music) to float samples
SoundA decoded sound and its loop flag. The samples are shared between channels, not copied.
Device64 channels. play takes the first free channel and returns none when all are busy.
SceneThe layer above the device that plays SoundEffects: timelines, 3D positions, emitters, kinds of sound
EffectCacheLoads and decodes the sound effects that a scene uses, on all CPU cores natively

§Use it

[dependencies]
banished-audio = { path = "crates/audio" }
banished-formats = { path = "crates/formats" }

On Linux, the build needs the ALSA headers (libasound2-dev and pkg-config).

§Play a sound

use banished_audio::{Device, PlayParams, Sound};
use banished_formats::pkg::Archive;

fn moo(archive: &Archive, device: &mut Device) -> Result<(), String> {
    let sound = Sound::load(archive, "Audio/Animal/Cow.rsc:version0")?;
    let params = PlayParams { volume: 0.8, pitch: 2.0, ..PlayParams::default() };
    match device.play(&sound, params)? {
        Some(channel) => println!("playing on channel {}", channel.index()),
        None => println!("all 64 channels are busy"),
    }
    Ok(())
}

PlayParams has a start offset, a volume, a pitch in semitones, and an optional loop flag (the default is the sound’s own flag). Device also has stop, pause, resume, seek, set_volume, set_pitch, set_looping, set_master_volume and update, which frees the channels of sounds that ended.

Device::play returns an error when there is no audio output. In the browser, sound starts only after the player clicks or types on the page; unlock resumes the Web Audio context then.

§Decode without playing

use banished_formats::pkg::Archive;

fn length(archive: &Archive) -> Result<f32, String> {
    let (pcm, looping) = banished_audio::load_sound(archive, "Audio/Music/Menu.rsc:music")?;
    let frames = pcm.samples.len() / pcm.channels as usize;
    println!("looping: {looping}");
    Ok(frames as f32 / pcm.sample_rate as f32)
}

Pcm has the number of channels, the sample rate, and interleaved samples from -1 to 1.

§Sound effects in a scene

The game does not play sounds directly. It plays SoundEffect resources through a Scene: an effect is a timeline of sounds with random choices, volumes and pitches. play_effect plays one for the interface, and play_effect_3d plays one at a position in the world. Emitters (add_emitter, move_emitter) are ambient sounds tied to a place, such as a river or a forest. Scene::update mixes them every frame, through any Mixer (the Device is one). See AUDIO.md for the details.

§Tests

cargo test --release -p banished-audio

tests/menu_music.rs decodes the menu music from your game data, and skips without it.

§The API

The full API documentation is at https://tanepiper.github.io/unbanished/api/banished_audio/index.html.

Re-exports§

pub use scene::sound_type;
pub use scene::Effect;
pub use scene::EffectCache;
pub use scene::Mixer;
pub use scene::Prepared;
pub use scene::Scene;
pub use scene::Volumes;

Modules§

scene
The sound scene: the layer above the Device that plays sound effects.

Structs§

Channel
A playing channel. Handles carry a generation, so one kept after its channel was freed and reused refers to nothing (calls on it do nothing).
Device
The multi-channel output (rodio).
Pcm
Decoded samples.
PlayParams
How a channel starts (Device::Play’s time and floats).
Slots
Channel bookkeeping without any output: first-free allocation and generations.
Sound
A decoded sound buffer (Audio::SoundBuffer) that any number of channels can play at once; the samples are shared, not copied, per channel.

Constants§

CHANNELS
Audio::Device channel count (loops in FindFreeChannel, Play, Update).

Functions§

decode
Decode a SoundBuffer; stream supplies the packets of streamed music (its .str entry).
load_sound
Load and decode a sound by resource reference (e.g. Audio\\Music\\Menu.rsc:music), reading the .str stream of streamed music. Returns the samples and the resource’s loop flag.
pitch_ratio
The playback speed for a pitch in semitones: one semitone is the twelfth root of two, as XAudio2’s frequency ratio.