#audio-playback #playback #gamedev #file-source

youtui-vendored-rodio

VENDORED LIBRARY FOR YOUTUI - DO NOT USE

2 releases

0.19.0-youtui-vendored.2 Aug 3, 2024

#360 in Audio

MIT/Apache

245KB
6.5K SLoC

CRATE TO ALLOW YOUTUI TO PUBLISH TO CRATESIO WITH VENDORED CHANGES - DO NOT USE - USE RODIO INSTEAD.


lib.rs:

Audio playback library.

The main concept of this library is the Source trait, which represents a sound (streaming or not). In order to play a sound, there are three steps:

  • Create an object that represents the streaming sound. It can be a sine wave, a buffer, a decoder, etc. or even your own type that implements the Source trait.
  • Get an output stream handle to a physical device. For example, get a stream to the system's default sound device with [OutputStream::try_default()]
  • Call .play_raw(source) on the output stream handle.

The play_raw function expects the source to produce [f32]s, which may not be the case. If you get a compilation error, try calling .convert_samples() on the source to fix it.

For example, here is how you would play an audio file:

use std::fs::File;
use std::io::BufReader;
use rodio::{Decoder, OutputStream, source::Source};

// Get an output stream handle to the default physical sound device.
// Note that no sound will be played if _stream is dropped
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
// Load a sound from a file, using a path relative to Cargo.toml
let file = BufReader::new(File::open("examples/music.ogg").unwrap());
// Decode that sound file into a source
let source = Decoder::new(file).unwrap();
// Play the sound directly on the device
stream_handle.play_raw(source.convert_samples());

// The sound plays in a separate audio thread,
// so we need to keep the main thread alive while it's playing.
std::thread::sleep(std::time::Duration::from_secs(5));

Sink

In order to make it easier to control the playback, the rodio library also provides a type named Sink which represents an audio track.

Instead of playing the sound with play_raw, you can add it to a Sink instead.

  • Get a Sink to the output stream, and .append() your sound to it.
use std::fs::File;
use std::io::BufReader;
use std::time::Duration;
use rodio::{Decoder, OutputStream, Sink};
use rodio::source::{SineWave, Source};

// _stream must live as long as the sink
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
let sink = Sink::try_new(&stream_handle).unwrap();

// Add a dummy source of the sake of the example.
let source = SineWave::new(440.0).take_duration(Duration::from_secs_f32(0.25)).amplify(0.20);
sink.append(source);

// The sound plays in a separate thread. This call will block the current thread until the sink
// has finished playing all its queued sounds.
sink.sleep_until_end();

The append method will add the sound at the end of the sink. It will be played when all the previous sounds have been played. If you want multiple sounds to play simultaneously, you should create multiple Sinks.

The Sink type also provides utilities such as playing/pausing or controlling the volume.

Please note that the Sink requires the OutputStream, make sure that the outputstream is not dropped before the sink.

Filters

The Source trait provides various filters, similar to the standard Iterator trait.

Example:

use rodio::Source;
use std::time::Duration;

// Repeats the first five seconds of the sound forever.
let source = source.take_duration(Duration::from_secs(5)).repeat_infinite();

Alternative Decoder Backends

Symphonia is an alternative decoder library that can be used in place of many of the default backends. Currently, the main benefit is that Symphonia is the only backend that supports M4A and AAC, but it may be used to implement additional optional functionality in the future.

To use, enable either the symphonia-all feature to enable all Symphonia codecs or enable specific codecs using one of the symphonia-{codec name} features. If you enable one or more of the Symphonia codecs, you may want to set default-features = false in order to avoid adding extra crates to your binary. See the available feature flags for all options.

How it works under the hood

Rodio spawns a background thread that is dedicated to reading from the sources and sending the output to the device. Whenever you give up ownership of a Source in order to play it, it is sent to this background thread where it will be read by rodio.

All the sounds are mixed together by rodio before being sent to the operating system or the hardware. Therefore there is no restriction on the number of sounds that play simultaneously or the number of sinks that can be created (except for the fact that creating too many will slow down your program).

Dependencies

~0.7–30MB
~466K SLoC