Skip to content

Decoder builder with additional settings #697

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
413f797
refactor: improve decoder configuration with builder pattern
roderickvd Feb 4, 2025
1f5d62f
docs: improve decoder API documentation
roderickvd Feb 4, 2025
59db8d8
refactor!: improve looped decoder implementation
roderickvd Feb 4, 2025
96f928a
feat!: make ReadSeekSource configurable through Settings
roderickvd Feb 4, 2025
9c0d70f
fix: maintain type parameter when only Symphonia decoder enabled
roderickvd Feb 4, 2025
c1da249
feat: improve size_hint and docs for LoopedDecoder
roderickvd Feb 5, 2025
5fba88e
refactor: simplify MP4 format handling
roderickvd Feb 5, 2025
12d8a37
adds total duration test for all decoders
dvdsk Feb 4, 2025
c968c20
style: fix formatting
roderickvd Feb 5, 2025
66651b7
feat: implement Source and Iterator for DecoderOutput
roderickvd Feb 5, 2025
3e3dc24
Fix decoder OGG duration, MP4 seeking and add Decoder::TryFrom<File>
roderickvd Feb 6, 2025
6f74f9b
docs: update examples to use new decoder builder API
roderickvd Feb 6, 2025
5fc56d9
docs: simplify decoder documentation and add builder() examples
roderickvd Feb 7, 2025
2f37008
change: fail TryFrom<File> if metadata unavailable
roderickvd Feb 7, 2025
a44f15f
feat: add TryFrom impls for BufReader and Cursor
roderickvd Feb 7, 2025
6500037
refactor: simplify decoder creation with build/build_looped methods
roderickvd Feb 7, 2025
1659948
refactor: improve looped decoder seek error message
roderickvd Feb 7, 2025
89dac52
test: overhaul decoder duration test
roderickvd Feb 7, 2025
69f03cc
tests: fix WAV duration test value for hound decoder
roderickvd Feb 11, 2025
0aedaa3
refactor: update decoder initialization to use try_from API in tests …
roderickvd Feb 11, 2025
0411cf5
symphonia: improve seeking precision and reliability
roderickvd Feb 19, 2025
5f18eee
refactor: split decoder builder into separate file
roderickvd Feb 19, 2025
697c8ce
refactor: address review comments
roderickvd Mar 6, 2025
a8a8b04
style: minor code comment fix
roderickvd Mar 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Minimal builds without `cpal` audio output are now supported.
See `README.md` for instructions. (#349)
- Added `Sample::is_zero()` method for checking zero samples.
- Added `DecoderBuilder` for improved configuration.
- Using `Decoder::TryFrom` for `File` now automatically wraps in `BufReader` and sets `byte_len`.
`TryFrom<Cursor<T>>` and `TryFrom<BufReader>` are also supported.

### Changed
- Breaking: `OutputStreamBuilder` should now be used to initialize an audio output stream.
Expand All @@ -29,9 +32,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Breaking: In the `Source` trait, the method `current_frame_len()` was renamed to `current_span_len()`.
- Breaking: `Decoder` now outputs `f32` samples.
- Breaking: The term 'frame' was renamed to 'span' in the crate and documentation.
- Breaking: Sources now use `f32` samples. To convert to and from other types of samples use functions from
`dasp_sample` crate. For example `DaspSample::from_sample(sample)`. Remove `integer-decoder` feature.

- Breaking: `LoopedDecoder` now returns `None` if seeking fails during loop reset.
- Breaking: `ReadSeekSource::new()` now takes `Settings`.
- Breaking: Sources now use `f32` samples. To convert to and from other types of samples use
functions from `dasp_sample` crate. For example `DaspSample::from_sample(sample)`.

### Fixed
- `ChannelVolume` no longer clips/overflows when converting from many channels to
Expand All @@ -40,12 +44,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- An issue with `SignalGenerator` that caused it to create increasingly distorted waveforms
over long run times has been corrected. (#201)
- WAV and FLAC decoder duration calculation now calculated once and handles very large files
correctly
- Removed unwrap() calls in MP3, WAV, FLAC and Vorbis format detection for better error handling
correctly.
- Removed unwrap() calls in MP3, WAV, FLAC and Vorbis format detection for better error handling.
- `LoopedDecoder::size_hint` now correctly indicates an infinite stream.
- Symphonia decoder `total_duration` for Vorbis now return the correct value (#696).
- Symphonia decoder for MP4 now seeks correctly (#577).

### Deprecated
- Deprecated `Sample::zero_value()` function in favor of `Sample::ZERO_VALUE` constant

### Removed
- Breaking: Removed `Mp4Type` enum in favor of using MIME type string "audio/mp4" for MP4 format detection with `Decoder::new_mp4` (#612).

# Version 0.20.1 (2024-11-08)

### Fixed
Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ symphonia-all = [
"symphonia-flac",
"symphonia-isomp4",
"symphonia-mp3",
"symphonia-ogg",
"symphonia-vorbis",
"symphonia-wav",
]
symphonia-flac = ["symphonia/flac"]
symphonia-isomp4 = ["symphonia/isomp4"]
symphonia-mp3 = ["symphonia/mp3"]
symphonia-ogg = ["symphonia/ogg"]
symphonia-vorbis = ["symphonia/vorbis"]
symphonia-wav = ["symphonia/wav", "symphonia/pcm", "symphonia/adpcm"]
symphonia-alac = ["symphonia/isomp4", "symphonia/alac"]
Expand Down
5 changes: 2 additions & 3 deletions examples/automatic_gain_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use rodio::source::Source;
use rodio::Decoder;
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
Expand All @@ -13,8 +12,8 @@ fn main() -> Result<(), Box<dyn Error>> {
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

// Decode the sound file into a source
let file = BufReader::new(File::open("assets/music.flac")?);
let source = Decoder::new(file)?;
let file = File::open("assets/music.flac")?;
let source = Decoder::try_from(file)?;

// Apply automatic gain control to the source
let agc_source = source.automatic_gain_control(1.0, 4.0, 0.005, 5.0);
Expand Down
3 changes: 1 addition & 2 deletions examples/callback_on_end.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::error::Error;
use std::io::BufReader;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;

Expand All @@ -8,7 +7,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.wav")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?);
sink.append(rodio::Decoder::try_from(file)?);

// lets increment a number after `music.wav` has played. We are going to use atomics
// however you could also use a `Mutex` or send a message through a `std::sync::mpsc`.
Expand Down
3 changes: 1 addition & 2 deletions examples/into_file.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use rodio::{output_to_wav, Source};
use std::error::Error;
use std::io::BufReader;

/// Converts mp3 file to a wav file.
/// This example does not use any audio devices
/// and can be used in build configurations without `cpal` feature enabled.
fn main() -> Result<(), Box<dyn Error>> {
let file = std::fs::File::open("assets/music.mp3")?;
let mut audio = rodio::Decoder::new(BufReader::new(file))?
let mut audio = rodio::Decoder::try_from(file)?
.automatic_gain_control(1.0, 4.0, 0.005, 3.0)
.speed(0.8);

Expand Down
3 changes: 1 addition & 2 deletions examples/music_flac.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::error::Error;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.flac")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?);
sink.append(rodio::Decoder::try_from(file)?);

sink.sleep_until_end();

Expand Down
3 changes: 1 addition & 2 deletions examples/music_m4a.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::error::Error;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.m4a")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?);
sink.append(rodio::Decoder::try_from(file)?);

sink.sleep_until_end();

Expand Down
3 changes: 1 addition & 2 deletions examples/music_mp3.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::error::Error;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.mp3")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?);
sink.append(rodio::Decoder::try_from(file)?);

sink.sleep_until_end();

Expand Down
3 changes: 1 addition & 2 deletions examples/music_ogg.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::error::Error;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.ogg")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?);
sink.append(rodio::Decoder::try_from(file)?);

sink.sleep_until_end();

Expand Down
3 changes: 1 addition & 2 deletions examples/music_wav.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::error::Error;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.wav")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?);
sink.append(rodio::Decoder::try_from(file)?);

sink.sleep_until_end();

Expand Down
3 changes: 1 addition & 2 deletions examples/reverb.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use rodio::Source;
use std::error::Error;
use std::io::BufReader;
use std::time::Duration;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.ogg")?;
let source = rodio::Decoder::new(BufReader::new(file))?;
let source = rodio::Decoder::try_from(file)?;
let with_reverb = source.buffered().reverb(Duration::from_millis(40), 0.7);
sink.append(with_reverb);

Expand Down
3 changes: 1 addition & 2 deletions examples/seek_mp3.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::error::Error;
use std::io::BufReader;
use std::time::Duration;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/music.mp3")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?);
sink.append(rodio::Decoder::try_from(file)?);

std::thread::sleep(std::time::Duration::from_secs(2));
sink.try_seek(Duration::from_secs(0))?;
Expand Down
3 changes: 1 addition & 2 deletions examples/spatial.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::error::Error;
use std::io::BufReader;
use std::thread;
use std::time::Duration;

Expand Down Expand Up @@ -30,7 +29,7 @@ fn main() -> Result<(), Box<dyn Error>> {
);

let file = std::fs::File::open("assets/music.ogg")?;
let source = rodio::Decoder::new(BufReader::new(file))?
let source = rodio::Decoder::try_from(file)?
.repeat_infinite()
.take_duration(total_duration);
sink.append(source);
Expand Down
3 changes: 1 addition & 2 deletions examples/stereo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

use rodio::Source;
use std::error::Error;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn Error>> {
let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?;
let sink = rodio::Sink::connect_new(&stream_handle.mixer());

let file = std::fs::File::open("assets/RL.ogg")?;
sink.append(rodio::Decoder::new(BufReader::new(file))?.amplify(0.2));
sink.append(rodio::Decoder::try_from(file)?.amplify(0.2));

sink.sleep_until_end();

Expand Down
Loading