arduino-audio-tools
Loading...
Searching...
No Matches
Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
AutomaticGainControlStream Class Reference

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

#include <AutomaticGainControlStream.h>

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

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 AudioInfo audioInfo () override
 provides the actual input AudioInfo
 
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.
 
AutomaticGainControlStreamConfig defaultConfig ()
 Provides the default configuration.
 
void end () override
 Stops processing; the underlying Stream/Print is left untouched.
 
void flush () override
 
AutomaticGainControlStreamConfiggetConfig ()
 Provides access to the current configuration.
 
bool isNotifyActive ()
 Checks if the automatic AudioInfo update is active.
 
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 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.
 
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)
 
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)
 
size_t write (const uint8_t *data, size_t len) override
 Gain-adjusts PCM data in place and writes it to the output.
 
virtual size_t write (uint8_t ch) override
 
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="")
 
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()
 
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
 
Streamp_in = nullptr
 
Printp_out = nullptr
 
uint32_t sample_rate = 44100
 
RingBuffer< uint8_t > tmp_in {0}
 
RingBuffer< uint8_t > tmp_out {0}
 
int write_buffer_size = MAX_SINGLE_CHARS
 

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]

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()

virtual void addNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

◆ 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()

virtual AudioInfo audioInfo ( )
inlineoverridevirtualinherited

◆ audioInfoOut()

virtual AudioInfo audioInfoOut ( )
inlinevirtualinherited

◆ 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()

virtual void clearNotifyAudioChange ( )
inlinevirtualinherited

Deletes all change notify subscriptions.

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ dbToLinear()

static 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()

bool isNotifyActive ( )
inlineinherited

Checks if the automatic AudioInfo update is active.

◆ linearToDb()

static float linearToDb ( float  value)
inlinestaticprotected

◆ not_supported()

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

◆ notifyAudioChange()

void notifyAudioChange ( AudioInfo  info)
inlineprotectedinherited

◆ operator bool()

virtual operator bool ( )
inlinevirtualinherited

◆ 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()

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

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

◆ refillReadBuffer()

void refillReadBuffer ( )
inlineprotectedinherited

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

◆ removeNotifyAudioChange()

virtual bool removeNotifyAudioChange ( AudioInfoSupport bi)
inlinevirtualinherited

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

Reimplemented in RTSPClient< TcpClient, UdpSocket >.

◆ reset()

void reset ( )
inline

Resets the current gain and level detector state.

◆ setAudioInfo()

void setAudioInfo ( AudioInfo  cfg)
inlineoverridevirtual

Updates the AudioInfo; resets state when reset_on_audio_change is set.

Reimplemented from AudioStream.

◆ setConfig()

void setConfig ( const AutomaticGainControlStreamConfig cfg)
inline

Updates the configuration without resetting the current gain state.

◆ setNotifyActive()

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 TimedStream, VolumeMeter, AudioInputMonitor, ReformatBaseStream, FormatConverterStream, and EncodedAudioStream.

◆ 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 VolumeMeter, AudioInputMonitor, FormatConverterStream, ReformatBaseStream, TimedStream, and EncodedAudioStream.

◆ setStream() [2/2]

void setStream ( Stream in)
inlineoverridevirtual

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

Implements ModifyingStream.

◆ setWriteBufferSize()

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]

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.

◆ write() [2/2]

virtual size_t write ( uint8_t  ch)
inlineoverridevirtualinherited

◆ writeSilence()

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 = MAX_SINGLE_CHARS
protectedinherited

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