Audacity 3.2.0
Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | Static Private Attributes | List of all members
EBUR128 Class Reference

Implements EBU-R128 loudness measurement. More...

#include <EBUR128.h>

Collaboration diagram for EBUR128:
[legend]

Public Member Functions

 EBUR128 (double rate, size_t channels)
 
 EBUR128 (const EBUR128 &)=delete
 
 EBUR128 (EBUR128 &&)=delete
 
 ~EBUR128 ()=default
 
void ProcessSampleFromChannel (float x_in, size_t channel) const
 
void NextSample ()
 
double IntegrativeLoudness ()
 
double IntegrativeLoudnessToLUFS (double loudness)
 

Static Public Member Functions

static ArrayOf< BiquadCalcWeightingFilter (double fs)
 

Private Member Functions

void HistogramSums (size_t start_idx, double &sum_v, long int &sum_c) const
 
void AddBlockToHistogram (size_t validLen)
 

Private Attributes

ArrayOf< long int > mLoudnessHist
 
Doubles mBlockRingBuffer
 
size_t mSampleCount { 0 }
 
size_t mBlockRingPos { 0 }
 
size_t mBlockRingSize { 0 }
 
const size_t mChannelCount
 
const double mRate
 
const size_t mBlockSize
 
const size_t mBlockOverlap
 
ArrayOf< ArrayOf< Biquad > > mWeightingFilter
 

Static Private Attributes

static constexpr size_t HIST_BIN_COUNT = 65536
 
static constexpr double GAMMA_A = (-70.0 + 0.691) / 10.0
 EBU R128 absolute threshold. More...
 

Detailed Description

Implements EBU-R128 loudness measurement.

Definition at line 21 of file EBUR128.h.

Constructor & Destructor Documentation

◆ EBUR128() [1/3]

EBUR128::EBUR128 ( double  rate,
size_t  channels 
)

Definition at line 14 of file EBUR128.cpp.

15 : mChannelCount{ channels }
16 , mRate{ rate }
17 , mBlockSize( ceil(0.4 * mRate) ) // 400 ms blocks
18 , mBlockOverlap( ceil(0.1 * mRate) ) // 100 ms overlap
19{
23 for(size_t channel = 0; channel < mChannelCount; ++channel)
25
26 memset(mLoudnessHist.get(), 0, HIST_BIN_COUNT*sizeof(long int));
27 for(size_t channel = 0; channel < mChannelCount; ++channel)
28 {
29 mWeightingFilter[channel][0].Reset();
30 mWeightingFilter[channel][1].Reset();
31 }
32}
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:58
ArrayOf< long int > mLoudnessHist
Definition: EBUR128.h:43
const size_t mChannelCount
Definition: EBUR128.h:48
static constexpr size_t HIST_BIN_COUNT
Definition: EBUR128.h:40
static ArrayOf< Biquad > CalcWeightingFilter(double fs)
Definition: EBUR128.cpp:42
const size_t mBlockSize
Definition: EBUR128.h:50
const double mRate
Definition: EBUR128.h:49
Doubles mBlockRingBuffer
Definition: EBUR128.h:44
ArrayOf< ArrayOf< Biquad > > mWeightingFilter
Definition: EBUR128.h:57
const size_t mBlockOverlap
Definition: EBUR128.h:51

References CalcWeightingFilter(), HIST_BIN_COUNT, mBlockRingBuffer, mBlockSize, mChannelCount, mLoudnessHist, mRate, mWeightingFilter, and ArrayOf< X >::reinit().

Here is the call graph for this function:

◆ EBUR128() [2/3]

EBUR128::EBUR128 ( const EBUR128 )
delete

◆ EBUR128() [3/3]

EBUR128::EBUR128 ( EBUR128 &&  )
delete

◆ ~EBUR128()

EBUR128::~EBUR128 ( )
default

Member Function Documentation

◆ AddBlockToHistogram()

void EBUR128::AddBlockToHistogram ( size_t  validLen)
private

Process new full block. Incomplete blocks shall be discarded according to the EBU R128 specification there is usually no need to call this on the last block. However, allow to override the block size if the audio to be processed is shorter than one block.

Definition at line 167 of file EBUR128.cpp.

168{
169 // Reset mBlockRingSize to full state to avoid overflow.
170 // The actual value of mBlockRingSize does not matter
171 // since this is only used to detect if blocks are complete (>= mBlockSize).
173
174 size_t idx;
175 double blockVal = 0;
176 for(size_t i = 0; i < validLen; ++i)
177 blockVal += mBlockRingBuffer[i];
178
179 // Histogram values are simplified log10() immediate values
180 // without -0.691 + 10*(...) to safe computing power. This is
181 // possible because these constant cancel out anyway during the
182 // following processing steps.
183 blockVal = log10(blockVal/double(validLen));
184 // log(blockVal) is within ]-inf, 1]
185 idx = round((blockVal - GAMMA_A) * double(HIST_BIN_COUNT) / -GAMMA_A - 1);
186
187 // idx is within ]-inf, HIST_BIN_COUNT-1], discard indices below 0
188 // as they are below the EBU R128 absolute threshold anyway.
189 if(idx < HIST_BIN_COUNT)
190 ++mLoudnessHist[idx];
191}
static constexpr double GAMMA_A
EBU R128 absolute threshold.
Definition: EBUR128.h:42
size_t mBlockRingSize
Definition: EBUR128.h:47
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept
Definition: fast_float.h:2512

References GAMMA_A, HIST_BIN_COUNT, mBlockRingBuffer, mBlockRingSize, mBlockSize, mLoudnessHist, and fast_float::round().

Referenced by IntegrativeLoudness(), and NextSample().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcWeightingFilter()

ArrayOf< Biquad > EBUR128::CalcWeightingFilter ( double  fs)
static

Definition at line 42 of file EBUR128.cpp.

43{
44 ArrayOf<Biquad> pBiquad(size_t(2), true);
45
46 //
47 // HSF pre filter
48 //
49 double db = 3.999843853973347;
50 double f0 = 1681.974450955533;
51 double Q = 0.7071752369554196;
52 double K = tan(M_PI * f0 / fs);
53
54 double Vh = pow(10.0, db / 20.0);
55 double Vb = pow(Vh, 0.4996667741545416);
56
57 double a0 = 1.0 + K / Q + K * K;
58
59 pBiquad[0].fNumerCoeffs[Biquad::B0] = (Vh + Vb * K / Q + K * K) / a0;
60 pBiquad[0].fNumerCoeffs[Biquad::B1] = 2.0 * (K * K - Vh) / a0;
61 pBiquad[0].fNumerCoeffs[Biquad::B2] = (Vh - Vb * K / Q + K * K) / a0;
62
63 pBiquad[0].fDenomCoeffs[Biquad::A1] = 2.0 * (K * K - 1.0) / a0;
64 pBiquad[0].fDenomCoeffs[Biquad::A2] = (1.0 - K / Q + K * K) / a0;
65
66 //
67 // HPF weighting filter
68 //
69 f0 = 38.13547087602444;
70 Q = 0.5003270373238773;
71 K = tan(M_PI * f0 / fs);
72
73 pBiquad[1].fNumerCoeffs[Biquad::B0] = 1.0;
74 pBiquad[1].fNumerCoeffs[Biquad::B1] = -2.0;
75 pBiquad[1].fNumerCoeffs[Biquad::B2] = 1.0;
76
77 pBiquad[1].fDenomCoeffs[Biquad::A1] = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K);
78 pBiquad[1].fDenomCoeffs[Biquad::A2] = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K);
79
80 return pBiquad;
81}
#define M_PI
Definition: Distortion.cpp:30
@ A1
Denominator coefficient indices.
Definition: Biquad.h:29
@ A2
Definition: Biquad.h:29
@ B1
Definition: Biquad.h:27
@ B2
Definition: Biquad.h:27
@ B0
Numerator coefficient indices.
Definition: Biquad.h:27

References Biquad::A1, Biquad::A2, Biquad::B0, Biquad::B1, Biquad::B2, crypto::anonymous_namespace{SHA256.cpp}::K, and M_PI.

Referenced by EBUR128().

Here is the caller graph for this function:

◆ HistogramSums()

void EBUR128::HistogramSums ( size_t  start_idx,
double &  sum_v,
long int &  sum_c 
) const
private

Definition at line 149 of file EBUR128.cpp.

150{
151 double val;
152 sum_v = 0;
153 sum_c = 0;
154 for(size_t i = start_idx; i < HIST_BIN_COUNT; ++i)
155 {
156 val = -GAMMA_A / double(HIST_BIN_COUNT) * (i+1) + GAMMA_A;
157 sum_v += pow(10, val) * mLoudnessHist[i];
158 sum_c += mLoudnessHist[i];
159 }
160}

References GAMMA_A, HIST_BIN_COUNT, and mLoudnessHist.

Referenced by IntegrativeLoudness().

Here is the caller graph for this function:

◆ IntegrativeLoudness()

double EBUR128::IntegrativeLoudness ( )

Definition at line 115 of file EBUR128.cpp.

116{
117 // EBU R128: z_i = mean square without root
118
119 // Calculate Gamma_R from histogram.
120 double sum_v;
121 long int sum_c;
122 HistogramSums(0, sum_v, sum_c);
123
124 // Handle incomplete block if no non-zero block was found.
125 if(sum_c == 0)
126 {
128 HistogramSums(0, sum_v, sum_c);
129 }
130
131 // Histogram values are simplified log(x^2) immediate values
132 // without -0.691 + 10*(...) to safe computing power. This is
133 // possible because they will cancel out anyway.
134 // The -1 in the line below is the -10 LUFS from the EBU R128
135 // specification without the scaling factor of 10.
136 double Gamma_R = log10(sum_v/sum_c) - 1;
137 size_t idx_R = round((Gamma_R - GAMMA_A) * double(HIST_BIN_COUNT) / -GAMMA_A - 1);
138
139 // Apply Gamma_R threshold and calculate gated loudness (extent).
140 HistogramSums(idx_R+1, sum_v, sum_c);
141 if(sum_c == 0)
142 // Silence was processed.
143 return 0;
144 // LUFS is defined as -0.691 dB + 10*log10(sum(channels))
145 return 0.8529037031 * sum_v / sum_c;
146}
void AddBlockToHistogram(size_t validLen)
Definition: EBUR128.cpp:167
void HistogramSums(size_t start_idx, double &sum_v, long int &sum_c) const
Definition: EBUR128.cpp:149

References AddBlockToHistogram(), GAMMA_A, HIST_BIN_COUNT, HistogramSums(), mBlockRingSize, and fast_float::round().

Here is the call graph for this function:

◆ IntegrativeLoudnessToLUFS()

double EBUR128::IntegrativeLoudnessToLUFS ( double  loudness)
inline

Definition at line 33 of file EBUR128.h.

34 { return 10 * log10(loudness); }

◆ NextSample()

void EBUR128::NextSample ( )

Definition at line 98 of file EBUR128.cpp.

99{
102
104 {
105 // A new full block of samples was submitted.
108 }
109 // Close the ring.
111 mBlockRingPos = 0;
112 ++mSampleCount;
113}
size_t mBlockRingPos
Definition: EBUR128.h:46
size_t mSampleCount
Definition: EBUR128.h:45

References AddBlockToHistogram(), mBlockOverlap, mBlockRingPos, mBlockRingSize, mBlockSize, and mSampleCount.

Referenced by EffectLoudness::AnalyseBufferBlock().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ProcessSampleFromChannel()

void EBUR128::ProcessSampleFromChannel ( float  x_in,
size_t  channel 
) const

Definition at line 83 of file EBUR128.cpp.

84{
85 double value;
86 value = mWeightingFilter[channel][0].ProcessOne(x_in);
87 value = mWeightingFilter[channel][1].ProcessOne(value);
88 if(channel == 0)
89 mBlockRingBuffer[mBlockRingPos] = value * value;
90 else
91 {
92 // Add the power of additional channels to the power of first channel.
93 // As a result, stereo tracks appear about 3 LUFS louder, as specified.
94 mBlockRingBuffer[mBlockRingPos] += value * value;
95 }
96}

References mBlockRingBuffer, mBlockRingPos, and mWeightingFilter.

Referenced by EffectLoudness::AnalyseBufferBlock().

Here is the caller graph for this function:

Member Data Documentation

◆ GAMMA_A

constexpr double EBUR128::GAMMA_A = (-70.0 + 0.691) / 10.0
staticconstexprprivate

EBU R128 absolute threshold.

Definition at line 42 of file EBUR128.h.

Referenced by AddBlockToHistogram(), HistogramSums(), and IntegrativeLoudness().

◆ HIST_BIN_COUNT

constexpr size_t EBUR128::HIST_BIN_COUNT = 65536
staticconstexprprivate

Definition at line 40 of file EBUR128.h.

Referenced by AddBlockToHistogram(), EBUR128(), HistogramSums(), and IntegrativeLoudness().

◆ mBlockOverlap

const size_t EBUR128::mBlockOverlap
private

Definition at line 51 of file EBUR128.h.

Referenced by NextSample().

◆ mBlockRingBuffer

Doubles EBUR128::mBlockRingBuffer
private

Definition at line 44 of file EBUR128.h.

Referenced by AddBlockToHistogram(), EBUR128(), and ProcessSampleFromChannel().

◆ mBlockRingPos

size_t EBUR128::mBlockRingPos { 0 }
private

Definition at line 46 of file EBUR128.h.

Referenced by NextSample(), and ProcessSampleFromChannel().

◆ mBlockRingSize

size_t EBUR128::mBlockRingSize { 0 }
private

Definition at line 47 of file EBUR128.h.

Referenced by AddBlockToHistogram(), IntegrativeLoudness(), and NextSample().

◆ mBlockSize

const size_t EBUR128::mBlockSize
private

Definition at line 50 of file EBUR128.h.

Referenced by AddBlockToHistogram(), EBUR128(), and NextSample().

◆ mChannelCount

const size_t EBUR128::mChannelCount
private

Definition at line 48 of file EBUR128.h.

Referenced by EBUR128().

◆ mLoudnessHist

ArrayOf<long int> EBUR128::mLoudnessHist
private

Definition at line 43 of file EBUR128.h.

Referenced by AddBlockToHistogram(), EBUR128(), and HistogramSums().

◆ mRate

const double EBUR128::mRate
private

Definition at line 49 of file EBUR128.h.

Referenced by EBUR128().

◆ mSampleCount

size_t EBUR128::mSampleCount { 0 }
private

Definition at line 45 of file EBUR128.h.

Referenced by NextSample().

◆ mWeightingFilter

ArrayOf<ArrayOf<Biquad> > EBUR128::mWeightingFilter
private

This is be an array of arrays of the type mWeightingFilter[CHANNEL][FILTER] with CHANNEL = LEFT/RIGHT (0/1) and FILTER = HSF/HPF (0/1)

Definition at line 57 of file EBUR128.h.

Referenced by EBUR128(), and ProcessSampleFromChannel().


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