Skip to content

Commit

Permalink
AGC: adds inner and inner_mut & uses those in example
Browse files Browse the repository at this point in the history
This removes the use of AGC's experimental atomic bool controls in
favor of the already stable periodic_access method of control.

The disadvantage is that periodic_access is significantly more difficult
for most users to undestand. It requires understanding of how closures
work with ownership and threading primitives like Atomics & Arc.
  • Loading branch information
dvdsk committed Oct 17, 2024
1 parent 71d9a6d commit 48408bc
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 14 deletions.
4 changes: 0 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,3 @@ required-features = ["symphonia-isomp4", "symphonia-aac"]
[[example]]
name = "noise_generator"
required-features = ["noise"]

[[example]]
name = "automatic_gain_control"
required-features = ["atomic_float"]
37 changes: 27 additions & 10 deletions examples/automatic_gain_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,44 @@ use rodio::source::Source;
use rodio::Decoder;
use std::fs::File;
use std::io::BufReader;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

fn main() {
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
let sink = rodio::Sink::try_new(&handle).unwrap();

let file = BufReader::new(File::open("assets/music.flac").unwrap());

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

// Apply automatic gain control to the source
let agc_source = source.automatic_gain_control(1.0, 4.0, 0.005, 5.0);

// Get a handle to control the AGC's enabled state (only when using experimental feature)
let agc_control = agc_source.get_agc_control();

// Disable AGC by default when using experimental feature
agc_control.store(true, std::sync::atomic::Ordering::Relaxed);

// Add the AGC-processed source to the sink for playback
sink.append(agc_source);
// Make it so that the source checks if automatic gain control should be
// enabled or disabled every 5 milliseconds. We must clone `agc_enabled`
// or we would lose it when we move it into the periodic access.
let agc_enabled = Arc::new(AtomicBool::new(true));
let agc_enabled_clone = agc_enabled.clone();
let controlled = agc_source.periodic_access(Duration::from_millis(5), move |agc_source| {
agc_source.set_enabled(agc_enabled_clone.load(Ordering::Relaxed));
});

// Add the source now equipped with automatic gain control and controlled via
// periodic_access to the sink for playback
sink.append(controlled);

// after 5 seconds of playback disable automatic gain control using the
// shared AtomicBool `agc_enabled`. You could do this from another part
// of the program since `agc_enabled` is of type Arc<AtomicBool> which
// is freely clone-able and move-able.
//
// Note that disabling the AGC takes up to 5 millis because periodic_access
// controls the source every 5 millis.
thread::sleep(Duration::from_secs(5));
agc_enabled.store(false, Ordering::Relaxed);

// Keep the program running until playback is complete
sink.sleep_until_end();
Expand Down
10 changes: 10 additions & 0 deletions src/source/agc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,16 @@ where
// Apply the computed gain to the input sample and return the result
sample.amplify(self.current_gain)
}

/// Returns a mutable reference to the inner source.
pub fn inner(&self) -> &I {
&self.input
}

/// Returns the inner source.
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
}

impl<I> Iterator for AutomaticGainControl<I>
Expand Down

0 comments on commit 48408bc

Please sign in to comment.