arduino-audio-tools
Loading...
Searching...
No Matches
AutomaticGainControlStream Class Reference

Slow automatic loudness normalization for PCM audio. More...

#include <AutomaticGainControlStream.h>

Inheritance diagram for AutomaticGainControlStream:
ModifyingStream AudioStream AudioStream AudioInfoSource AudioInfoSupport BaseStream AudioInfoSource AudioInfoSupport BaseStream AudioInfoSource AudioInfoSupport BaseStream AudioInfoSource AudioInfoSupport BaseStream

Public Member Functions

 AutomaticGainControlStream ()=default
 Default constructor: call setStream()/setOutput() before begin().
 AutomaticGainControlStream (AudioOutput &out)
 AutomaticGainControlStream (AudioStream &out)
 AutomaticGainControlStream (Stream &out)
 Constructs the stream with a bidirectional Stream as input and output.
virtual void addNotifyAudioChange (AudioInfoSupport &bi)
 Adds target to be notified about audio changes.
virtual void addNotifyAudioChange (AudioInfoSupport &bi)
 Adds target to be notified about audio changes.
virtual AudioInfo audioInfo () override
 provides the actual input AudioInfo
virtual AudioInfo audioInfo () override
 provides the actual input AudioInfo
virtual AudioInfo audioInfoOut ()
virtual AudioInfo audioInfoOut ()
int available () override
 Provides the available data of the input.
int availableForWrite () override
 Provides the available space of the output.
bool begin () override
 Starts processing using the current AudioInfo.
bool begin (AudioInfo cfg)
 Starts processing with the given AudioInfo, keeping the current config.
bool begin (AutomaticGainControlStreamConfig cfg)
 Starts processing with the given AutomaticGainControlStreamConfig.
virtual void clearNotifyAudioChange ()
 Deletes all change notify subscriptions.
virtual void clearNotifyAudioChange ()
 Deletes all change notify subscriptions.
AutomaticGainControlStreamConfig defaultConfig ()
 Provides the default configuration.
void end () override
 Stops processing; the underlying Stream/Print is left untouched.
void flush () override
AutomaticGainControlStreamConfig & getConfig ()
 Provides access to the current configuration.
bool isNotifyActive ()
 Checks if the automatic AudioInfo update is active.
bool isNotifyActive ()
 Checks if the automatic AudioInfo update is active.
virtual operator bool ()
virtual operator bool ()
size_t readBytes (uint8_t *data, size_t len) override
 Reads and gain-adjusts PCM data from the input Stream.
virtual size_t readSilence (uint8_t *buffer, size_t length)
 Source to generate silence: just sets the buffer to 0.
virtual size_t readSilence (uint8_t *buffer, size_t length)
 Source to generate silence: just sets the buffer to 0.
virtual bool removeNotifyAudioChange (AudioInfoSupport &bi)
 Removes a target in order not to be notified about audio changes.
virtual bool removeNotifyAudioChange (AudioInfoSupport &bi)
 Removes a target in order not to be notified about audio changes.
void reset ()
 Resets the current gain and level detector state.
virtual void setAudioInfo (AudioInfo newInfo) override
 Defines the input AudioInfo.
void setAudioInfo (AudioInfo cfg) override
 Updates the AudioInfo; resets state when reset_on_audio_change is set.
void setConfig (const AutomaticGainControlStreamConfig &cfg)
 Updates the configuration without resetting the current gain state.
void setNotifyActive (bool flag)
 Deactivate/Reactivate automatic AudioInfo updates: (default is active).
void setNotifyActive (bool flag)
 Deactivate/Reactivate automatic AudioInfo updates: (default is active).
virtual void setOutput (AudioOutput &out)
 Defines/Changes the output target and registers for audio change notifications.
void setOutput (Print &out) override
 Defines the output Print target.
virtual void setStream (AudioStream &io)
 Defines/Changes the input & output and registers for audio change notifications.
void setStream (Stream &in) override
 Defines the input Stream; output is set to the same Stream.
void setWriteBufferSize (int size)
void setWriteBufferSize (int size)
virtual size_t write (uint8_t ch) override
size_t write (const uint8_t *data, size_t len) override
 Gain-adjusts PCM data in place and writes it to the output.
virtual void writeSilence (size_t len)
 Writes len bytes of silence (=0).
virtual void writeSilence (size_t len)
 Writes len bytes of silence (=0).

Protected Member Functions

template<typename T>
void analyze (const T *data, size_t samples, float &rms, float &peak)
bool analyze (const uint8_t *buffer, size_t bytes, float &rms, float &peak)
template<typename T>
void apply (T *data, size_t samples, float gain)
void apply (uint8_t *buffer, size_t bytes, float gain)
float desiredGainDb (float rms_db, float peak_db) const
virtual int not_supported (int out, const char *msg="")
virtual int not_supported (int out, const char *msg="")
void notifyAudioChange (AudioInfo info)
void notifyAudioChange (AudioInfo info)
void process (const uint8_t *input, size_t bytes)
void refillReadBuffer ()
 Refill small read buffer (e.g. 8 bytes) to avoid single byte reads when calling read().
void refillReadBuffer ()
 Refill small read buffer (e.g. 8 bytes) to avoid single byte reads when calling read().
float smoothingCoefficient (float seconds, size_t samples) const
void updateGain (float desired_gain_db, size_t samples)

Static Protected Member Functions

static float dbToLinear (float db)
static float linearToDb (float value)

Protected Attributes

int _timeout = 10
uint16_t bits_per_sample = 16
uint16_t channels = 2
AutomaticGainControlStreamConfig config
float current_gain_db = 0.0f
bool has_level = false
AudioInfo info
bool is_notify_active = true
bool is_started = false
float measured_db = -100.0f
Vector< AudioInfoSupport * > notify_vector
Stream * p_in = nullptr
Print * p_out = nullptr
uint32_t sample_rate = 44100
RingBuffer< uint8_t > tmp_in {0}
RingBuffer< uint8_t > tmp_out {0}
int write_buffer_size = 8

Detailed Description

Slow automatic loudness normalization for PCM audio.

The stream measures the RMS level of the incoming PCM signal and adjusts an automatic gain towards a target level.

Gain reduction is relatively fast (attack), while gain increase is deliberately slow (release). This prevents the normalizer from destroying natural fades.

Recommended signal chain:

Decoder -> AutomaticGainControlStream -> VolumeStream -> I2S

The normalizer operates on decoded PCM data.

Constructor & Destructor Documentation

◆ AutomaticGainControlStream() [1/4]

AutomaticGainControlStream ( )
default

Default constructor: call setStream()/setOutput() before begin().

◆ AutomaticGainControlStream() [2/4]

AutomaticGainControlStream ( Stream & out)
inlineexplicit

Constructs the stream with a bidirectional Stream as input and output.

◆ AutomaticGainControlStream() [3/4]

AutomaticGainControlStream ( AudioStream & out)
inlineexplicit

Constructs the stream with an AudioStream as output and registers it for AudioInfo change notifications

◆ AutomaticGainControlStream() [4/4]

AutomaticGainControlStream ( AudioOutput & out)
inlineexplicit

Constructs the stream with an AudioOutput as output and registers it for AudioInfo change notifications

Member Function Documentation

◆ addNotifyAudioChange() [1/2]

virtual void addNotifyAudioChange ( AudioInfoSupport & bi)
inlinevirtualinherited

Adds target to be notified about audio changes.

Reimplemented in CodecNOP, CodecNOP, EncodedAudioOutput, and EncodedAudioStream.

◆ addNotifyAudioChange() [2/2]

virtual void addNotifyAudioChange ( AudioInfoSupport & bi)
inlinevirtualinherited

Adds target to be notified about audio changes.

Reimplemented in CodecNOP, CodecNOP, EncodedAudioOutput, and EncodedAudioStream.

◆ analyze() [1/2]

template<typename T>
void analyze ( const T * data,
size_t samples,
float & rms,
float & peak )
inlineprotected

Calculate RMS and peak for any supported integer PCM type.

Under PREFER_FIXEDPOINT the per-sample loop accumulates plain integer sums (samples are pre-shifted via AGCPCMTraits<T>::fixed_shift so the sum of squares cannot overflow int64_t), and float math (sqrtf) is only used once per block to derive rms/peak. This avoids per-sample FPU work on microcontrollers that lack a hardware float unit.

◆ analyze() [2/2]

bool analyze ( const uint8_t * buffer,
size_t bytes,
float & rms,
float & peak )
inlineprotected

Dispatch PCM analysis according to bits_per_sample.

◆ apply() [1/2]

template<typename T>
void apply ( T * data,
size_t samples,
float gain )
inlineprotected

Apply gain to any supported PCM type.

By default the calculation is performed in float precision and the result is saturated to the PCM range.

Under PREFER_FIXEDPOINT the gain is converted to a Q1.14 fixed-point factor once per block, and q1_14_t::scale() applies it per sample using pure integer multiply/shift, avoiding an FPU multiply on every sample. Q1.14 covers roughly [-2.0, 1.99994], which comfortably fits the default max_gain_db (+6 dB, ~1.995x); a max_gain_db configured well beyond that will saturate at the Q1.14 limit under PREFER_FIXEDPOINT even though the float path would not.

◆ apply() [2/2]

void apply ( uint8_t * buffer,
size_t bytes,
float gain )
inlineprotected

Dispatch PCM gain application according to bits_per_sample.

◆ audioInfo() [1/2]

◆ audioInfo() [2/2]

◆ audioInfoOut() [1/2]

◆ audioInfoOut() [2/2]

◆ available()

int available ( )
inlineoverridevirtual

Provides the available data of the input.

Reimplemented from BaseStream.

◆ availableForWrite()

int availableForWrite ( )
inlineoverridevirtual

Provides the available space of the output.

Reimplemented from BaseStream.

◆ begin() [1/3]

bool begin ( )
inlineoverridevirtual

Starts processing using the current AudioInfo.

Reimplemented from BaseStream.

◆ begin() [2/3]

bool begin ( AudioInfo cfg)
inline

Starts processing with the given AudioInfo, keeping the current config.

◆ begin() [3/3]

bool begin ( AutomaticGainControlStreamConfig cfg)
inline

Starts processing with the given AutomaticGainControlStreamConfig.

◆ clearNotifyAudioChange() [1/2]

virtual void clearNotifyAudioChange ( )
inlinevirtualinherited

◆ clearNotifyAudioChange() [2/2]

virtual void clearNotifyAudioChange ( )
inlinevirtualinherited

◆ dbToLinear()

float dbToLinear ( float db)
inlinestaticprotected

◆ defaultConfig()

AutomaticGainControlStreamConfig defaultConfig ( )
inline

Provides the default configuration.

◆ desiredGainDb()

float desiredGainDb ( float rms_db,
float peak_db ) const
inlineprotected

Calculate the desired automatic gain.

◆ end()

void end ( )
inlineoverridevirtual

Stops processing; the underlying Stream/Print is left untouched.

Reimplemented from BaseStream.

◆ flush()

void flush ( )
inlineoverridevirtual

Reimplemented from BaseStream.

◆ getConfig()

AutomaticGainControlStreamConfig & getConfig ( )
inline

Provides access to the current configuration.

◆ isNotifyActive() [1/2]

bool isNotifyActive ( )
inlineinherited

Checks if the automatic AudioInfo update is active.

◆ isNotifyActive() [2/2]

bool isNotifyActive ( )
inlineinherited

Checks if the automatic AudioInfo update is active.

◆ linearToDb()

float linearToDb ( float value)
inlinestaticprotected

◆ not_supported() [1/2]

virtual int not_supported ( int out,
const char * msg = "" )
inlineprotectedvirtualinherited

◆ not_supported() [2/2]

virtual int not_supported ( int out,
const char * msg = "" )
inlineprotectedvirtualinherited

◆ notifyAudioChange() [1/2]

void notifyAudioChange ( AudioInfo info)
inlineprotectedinherited

◆ notifyAudioChange() [2/2]

void notifyAudioChange ( AudioInfo info)
inlineprotectedinherited

◆ operator bool() [1/2]

◆ operator bool() [2/2]

◆ process()

void process ( const uint8_t * input,
size_t bytes )
inlineprotected

◆ readBytes()

size_t readBytes ( uint8_t * data,
size_t len )
inlineoverridevirtual

Reads and gain-adjusts PCM data from the input Stream.

Reimplemented from AudioStream.

◆ readSilence() [1/2]

virtual size_t readSilence ( uint8_t * buffer,
size_t length )
inlinevirtualinherited

Source to generate silence: just sets the buffer to 0.

◆ readSilence() [2/2]

virtual size_t readSilence ( uint8_t * buffer,
size_t length )
inlinevirtualinherited

Source to generate silence: just sets the buffer to 0.

◆ refillReadBuffer() [1/2]

void refillReadBuffer ( )
inlineprotectedinherited

Refill small read buffer (e.g. 8 bytes) to avoid single byte reads when calling read().

◆ refillReadBuffer() [2/2]

void refillReadBuffer ( )
inlineprotectedinherited

Refill small read buffer (e.g. 8 bytes) to avoid single byte reads when calling read().

◆ removeNotifyAudioChange() [1/2]

virtual bool removeNotifyAudioChange ( AudioInfoSupport & bi)
inlinevirtualinherited

Removes a target in order not to be notified about audio changes.

◆ removeNotifyAudioChange() [2/2]

virtual bool removeNotifyAudioChange ( AudioInfoSupport & bi)
inlinevirtualinherited

Removes a target in order not to be notified about audio changes.

◆ reset()

void reset ( )
inline

Resets the current gain and level detector state.

◆ setAudioInfo() [1/2]

◆ setAudioInfo() [2/2]

void setAudioInfo ( AudioInfo cfg)
inlineoverride

Updates the AudioInfo; resets state when reset_on_audio_change is set.

◆ setConfig()

void setConfig ( const AutomaticGainControlStreamConfig & cfg)
inline

Updates the configuration without resetting the current gain state.

◆ setNotifyActive() [1/2]

void setNotifyActive ( bool flag)
inlineinherited

Deactivate/Reactivate automatic AudioInfo updates: (default is active).

◆ setNotifyActive() [2/2]

void setNotifyActive ( bool flag)
inlineinherited

Deactivate/Reactivate automatic AudioInfo updates: (default is active).

◆ setOutput() [1/2]

virtual void setOutput ( AudioOutput & out)
inlinevirtualinherited

Defines/Changes the output target and registers for audio change notifications.

Reimplemented in AudioInputMonitor, AudioInputMonitor, EncodedAudioStream, ReformatBaseStream, TimedStream, VolumeMeter, and VolumeMeter.

◆ setOutput() [2/2]

void setOutput ( Print & out)
inlineoverridevirtual

Defines the output Print target.

Implements ModifyingStream.

◆ setStream() [1/2]

virtual void setStream ( AudioStream & io)
inlinevirtualinherited

Defines/Changes the input & output and registers for audio change notifications.

Reimplemented in AudioInputMonitor, AudioInputMonitor, EncodedAudioStream, ReformatBaseStream, TimedStream, VolumeMeter, and VolumeMeter.

◆ setStream() [2/2]

void setStream ( Stream & in)
inlineoverridevirtual

Defines the input Stream; output is set to the same Stream.

Implements ModifyingStream.

◆ setWriteBufferSize() [1/2]

void setWriteBufferSize ( int size)
inlineinherited

◆ setWriteBufferSize() [2/2]

void setWriteBufferSize ( int size)
inlineinherited

◆ smoothingCoefficient()

float smoothingCoefficient ( float seconds,
size_t samples ) const
inlineprotected

Calculate the smoothing coefficient for the current block.

The coefficient is based on the actual block duration, so the attack/release behaviour is largely independent of StreamCopy's buffer size.

◆ updateGain()

void updateGain ( float desired_gain_db,
size_t samples )
inlineprotected

◆ write() [1/2]

◆ write() [2/2]

size_t write ( const uint8_t * data,
size_t len )
inlineoverridevirtual

Gain-adjusts PCM data in place and writes it to the output.

Reimplemented from AudioStream.

◆ writeSilence() [1/2]

virtual void writeSilence ( size_t len)
inlinevirtualinherited

Writes len bytes of silence (=0).

◆ writeSilence() [2/2]

virtual void writeSilence ( size_t len)
inlinevirtualinherited

Writes len bytes of silence (=0).

Member Data Documentation

◆ _timeout

int _timeout = 10
protectedinherited

◆ bits_per_sample

uint16_t bits_per_sample = 16
protected

◆ channels

uint16_t channels = 2
protected

◆ config

◆ current_gain_db

float current_gain_db = 0.0f
protected

◆ has_level

bool has_level = false
protected

◆ info

AudioInfo info
protectedinherited

◆ is_notify_active

bool is_notify_active = true
protectedinherited

◆ is_started

bool is_started = false
protected

◆ measured_db

float measured_db = -100.0f
protected

◆ notify_vector

Vector< AudioInfoSupport * > notify_vector
protectedinherited

◆ p_in

Stream* p_in = nullptr
protected

◆ p_out

Print* p_out = nullptr
protected

◆ sample_rate

uint32_t sample_rate = 44100
protected

◆ tmp_in

RingBuffer< uint8_t > tmp_in {0}
protectedinherited

◆ tmp_out

RingBuffer< uint8_t > tmp_out {0}
protectedinherited

◆ write_buffer_size

int write_buffer_size = 8
protectedinherited

The documentation for this class was generated from the following file: