Skip to content
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

Add Automatic Gain Control #621

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
85bfcbd
Init commit for automatic_gain_control
UnknownSuperficialNight Sep 26, 2024
625d0f2
Updated comments, refactored logic & added more member functions for …
UnknownSuperficialNight Sep 26, 2024
6b62544
Added simple flag to enable the debug temporarily during development
UnknownSuperficialNight Sep 27, 2024
611055c
Enhance AGC with asymmetric attack/release and safety limits
UnknownSuperficialNight Sep 27, 2024
97636d1
Add author credit to AGC implementation
UnknownSuperficialNight Sep 27, 2024
9497f5c
Merge branch 'master' into feature/automatic-gain-control
UnknownSuperficialNight Sep 28, 2024
1b27bcd
Add debug logging for AGC current gain value
UnknownSuperficialNight Sep 28, 2024
d9f7967
Better document comments for docs.rs
UnknownSuperficialNight Sep 28, 2024
ce3d7e0
Optimize AGC with CircularBuffer and enhance functionality
UnknownSuperficialNight Sep 28, 2024
28b3c4b
Removed MAX_PEAK_LEVEL now uses target_level as intended and styled d…
UnknownSuperficialNight Sep 29, 2024
d4a09f3
Merge branch 'master' into feature/automatic-gain-control
UnknownSuperficialNight Sep 29, 2024
f4bb729
Added benchmark for agc and inlines
UnknownSuperficialNight Sep 29, 2024
1d2a6fd
Removed bullet point from docs
UnknownSuperficialNight Sep 29, 2024
beeacf6
Added agc to CHANGELOG.md
UnknownSuperficialNight Sep 29, 2024
9bf97ac
Update benchmark to new default values
UnknownSuperficialNight Sep 29, 2024
a8a443b
Enhance AGC stability and flexibility
UnknownSuperficialNight Sep 30, 2024
68e1bd2
Pass min_attack_coeff directly
UnknownSuperficialNight Sep 30, 2024
2442aa0
Add real-time toggle for AGC processing
UnknownSuperficialNight Sep 30, 2024
b59533e
Add new benchmark for disabled_agc
UnknownSuperficialNight Sep 30, 2024
42fe832
Enhance automatic_gain_control documentation
UnknownSuperficialNight Sep 30, 2024
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
11 changes: 6 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Support for *ALAC/AIFF*
- Support for *ALAC/AIFF*
- Add `automatic_gain_control` source for dynamic audio level adjustment.
- New sources:
- `fade_out` fades an input out using a linear gain fade.
- `linear_gain_ramp` applies a linear gain change to a sound over a
given duration. `fade_out` is implemented as a `linear_gain_ramp` and
`fade_in` has been refactored to use the `linear_gain_ramp`
`fade_in` has been refactored to use the `linear_gain_ramp`
implementation.

### Fixed
- `Sink.try_seek` now updates `controls.position` before returning. Calls to `Sink.get_pos`
done immediately after a seek will now return the correct value.
done immediately after a seek will now return the correct value.

### Changed
- `SamplesBuffer` is now `Clone`
Expand All @@ -44,15 +45,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Source` trait is now also implemented for `Box<dyn Source>` and `&mut Source`
- `fn new_vorbis` is now also available when the `symphonia-vorbis` feature is enabled

### Added
### Added
- Adds a new method `try_seek` to all sources. It returns either an error or
seeks to the given position. A few sources are "unsupported" they return the
error `Unsupported`.
- Adds `SpatialSink::clear()` bringing it in line with `Sink`

### Fixed
- channel upscaling now follows the 'WAVEFORMATEXTENSIBLE' format and no longer
repeats the last source channel on all extra output channels.
repeats the last source channel on all extra output channels.
Stereo content playing on a 5.1 speaker set will now only use the front left
and front right speaker instead of repeating the right sample on all speakers
except the front left one.
Expand Down
38 changes: 38 additions & 0 deletions benches/effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,41 @@ fn amplify(bencher: Bencher) {
.with_inputs(|| TestSource::music_wav().to_f32s())
.bench_values(|source| source.amplify(0.8).for_each(divan::black_box_drop))
}

#[divan::bench]
fn agc_enabled(bencher: Bencher) {
bencher
.with_inputs(|| TestSource::music_wav().to_f32s())
.bench_values(|source| {
source
.automatic_gain_control(
1.0, // target_level
4.0, // attack_time (in seconds)
0.005, // release_time (in seconds)
5.0, // absolute_max_gain
)
.for_each(divan::black_box_drop)
})
}

#[divan::bench]
fn agc_disabled(bencher: Bencher) {
bencher
.with_inputs(|| TestSource::music_wav().to_f32s())
.bench_values(|source| {
// Create the AGC source
let amplified_source = source.automatic_gain_control(
1.0, // target_level
4.0, // attack_time (in seconds)
0.005, // release_time (in seconds)
5.0, // absolute_max_gain
);

// Get the control handle and disable AGC
let agc_control = amplified_source.get_agc_control();
agc_control.store(false, std::sync::atomic::Ordering::Relaxed);

// Process the audio stream with AGC disabled
amplified_source.for_each(divan::black_box_drop)
})
}
21 changes: 21 additions & 0 deletions src/conversions/sample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pub trait Sample: CpalSample {
/// Multiplies the value of this sample by the given amount.
fn amplify(self, value: f32) -> Self;

/// Converts the sample to an f32 value.
fn to_f32(self) -> f32;

/// Calls `saturating_add` on the sample.
fn saturating_add(self, other: Self) -> Self;

Expand All @@ -102,6 +105,12 @@ impl Sample for u16 {
((self as f32) * value) as u16
}

#[inline]
fn to_f32(self) -> f32 {
// Convert u16 to f32 in the range [-1.0, 1.0]
(self as f32 - 32768.0) / 32768.0
}

#[inline]
fn saturating_add(self, other: u16) -> u16 {
self.saturating_add(other)
Expand All @@ -125,6 +134,12 @@ impl Sample for i16 {
((self as f32) * value) as i16
}

#[inline]
fn to_f32(self) -> f32 {
// Convert i16 to f32 in the range [-1.0, 1.0]
self as f32 / 32768.0
}

#[inline]
fn saturating_add(self, other: i16) -> i16 {
self.saturating_add(other)
Expand All @@ -147,6 +162,12 @@ impl Sample for f32 {
self * value
}

#[inline]
fn to_f32(self) -> f32 {
// f32 is already in the correct format
self
}

#[inline]
fn saturating_add(self, other: f32) -> f32 {
self + other
Expand Down
Loading