Skip to content

Commit 48408bc

Browse files
author
dvdsk
committed
AGC: adds inner and inner_mut & uses those in example
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.
1 parent 71d9a6d commit 48408bc

3 files changed

Lines changed: 37 additions & 14 deletions

File tree

Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,3 @@ required-features = ["symphonia-isomp4", "symphonia-aac"]
6969
[[example]]
7070
name = "noise_generator"
7171
required-features = ["noise"]
72-
73-
[[example]]
74-
name = "automatic_gain_control"
75-
required-features = ["atomic_float"]

examples/automatic_gain_control.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,44 @@ use rodio::source::Source;
22
use rodio::Decoder;
33
use std::fs::File;
44
use std::io::BufReader;
5+
use std::sync::atomic::{AtomicBool, Ordering};
6+
use std::sync::Arc;
7+
use std::thread;
8+
use std::time::Duration;
59

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

10-
let file = BufReader::new(File::open("assets/music.flac").unwrap());
11-
1214
// Decode the sound file into a source
15+
let file = BufReader::new(File::open("assets/music.flac").unwrap());
1316
let source = Decoder::new(file).unwrap();
1417

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

18-
// Get a handle to control the AGC's enabled state (only when using experimental feature)
19-
let agc_control = agc_source.get_agc_control();
20-
21-
// Disable AGC by default when using experimental feature
22-
agc_control.store(true, std::sync::atomic::Ordering::Relaxed);
23-
24-
// Add the AGC-processed source to the sink for playback
25-
sink.append(agc_source);
21+
// Make it so that the source checks if automatic gain control should be
22+
// enabled or disabled every 5 milliseconds. We must clone `agc_enabled`
23+
// or we would lose it when we move it into the periodic access.
24+
let agc_enabled = Arc::new(AtomicBool::new(true));
25+
let agc_enabled_clone = agc_enabled.clone();
26+
let controlled = agc_source.periodic_access(Duration::from_millis(5), move |agc_source| {
27+
agc_source.set_enabled(agc_enabled_clone.load(Ordering::Relaxed));
28+
});
29+
30+
// Add the source now equipped with automatic gain control and controlled via
31+
// periodic_access to the sink for playback
32+
sink.append(controlled);
33+
34+
// after 5 seconds of playback disable automatic gain control using the
35+
// shared AtomicBool `agc_enabled`. You could do this from another part
36+
// of the program since `agc_enabled` is of type Arc<AtomicBool> which
37+
// is freely clone-able and move-able.
38+
//
39+
// Note that disabling the AGC takes up to 5 millis because periodic_access
40+
// controls the source every 5 millis.
41+
thread::sleep(Duration::from_secs(5));
42+
agc_enabled.store(false, Ordering::Relaxed);
2643

2744
// Keep the program running until playback is complete
2845
sink.sleep_until_end();

src/source/agc.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ where
415415
// Apply the computed gain to the input sample and return the result
416416
sample.amplify(self.current_gain)
417417
}
418+
419+
/// Returns a mutable reference to the inner source.
420+
pub fn inner(&self) -> &I {
421+
&self.input
422+
}
423+
424+
/// Returns the inner source.
425+
pub fn inner_mut(&mut self) -> &mut I {
426+
&mut self.input
427+
}
418428
}
419429

420430
impl<I> Iterator for AutomaticGainControl<I>

0 commit comments

Comments
 (0)