Browse Source

Update LUFSMeter

tags/2018-04-16
falkTX 6 years ago
parent
commit
0c5706efa1
8 changed files with 509 additions and 399 deletions
  1. +391
    -301
      ports/LUFSMeter/source/Ebu128LoudnessMeter.cpp
  2. +64
    -45
      ports/LUFSMeter/source/Ebu128LoudnessMeter.h
  3. +1
    -1
      ports/LUFSMeter/source/LUFSMeterAudioProcessor.cpp
  4. +1
    -1
      ports/LUFSMeter/source/LUFSMeterAudioProcessor.h
  5. +34
    -36
      ports/LUFSMeter/source/filters/SecondOrderIIRFilter.cpp
  6. +13
    -11
      ports/LUFSMeter/source/filters/SecondOrderIIRFilter.h
  7. +2
    -2
      ports/LUFSMeter/source/gui/MultiChannelLoudnessBar.cpp
  8. +3
    -2
      ports/LUFSMeter/source/gui/MultiChannelLoudnessBar.h

+ 391
- 301
ports/LUFSMeter/source/Ebu128LoudnessMeter.cpp
File diff suppressed because it is too large
View File


+ 64
- 45
ports/LUFSMeter/source/Ebu128LoudnessMeter.h View File

@@ -5,7 +5,7 @@
This file is part of the LUFS Meter audio measurement plugin.
Copyright 2011-14 by Klangfreund, Samuel Gaehwiler.
Copyright 2011-2016 by Klangfreund, Samuel Gaehwiler.
-------------------------------------------------------------------------------
@@ -20,8 +20,7 @@
-------------------------------------------------------------------------------
To release a closed-source product which uses the LUFS Meter or parts of it,
a commercial license is available. Visit www.klangfreund.com/lufsmeter for more
information.
get in contact via www.klangfreund.com/contact/.
===============================================================================
*/
@@ -32,8 +31,10 @@

#include "MacrosAndJuceHeaders.h"
#include "filters/SecondOrderIIRFilter.h"
#include <map>
#include <vector>

using std::map;
using std::vector;

/**
@@ -42,7 +43,7 @@ using std::vector;
The loudness is measured according to the documents
(List)
- EBU - R 128
- ITU 1770 Rev 2
- ITU 1770 Rev 2,3 and 4
- EBU - Tech 3341 (EBU mode metering)
- EBU - Tech 3342 (LRA, loudness range)
- EBU - Tech 3343
@@ -50,8 +51,8 @@ using std::vector;
class Ebu128LoudnessMeter //: public AudioProcessor
{
public:
Ebu128LoudnessMeter ();
~Ebu128LoudnessMeter ();
Ebu128LoudnessMeter();
~Ebu128LoudnessMeter();
// --------- AudioProcessor methods ---------
// const String getName ();
@@ -73,21 +74,30 @@ public:
void processBlock (AudioSampleBuffer &buffer);
const Array<float>& getShortTermLoudnessForIndividualChannels();
float getShortTermLoudness();
float getShortTermLoudness() const;
float getMaximumShortTermLoudness() const;
const Array<float>& getMomentaryLoudnessForIndividualChannels();
float getMomentaryLoudness();
vector<float>& getMomentaryLoudnessForIndividualChannels();
float getMomentaryLoudness() const;
float getMaximumMomentaryLoudness() const;
float getIntegratedLoudness();
float getIntegratedLoudness() const;
float getLoudnessRangeStart();
float getLoudnessRangeEnd();
float getLoudnessRange();
float getLoudnessRangeStart() const;
float getLoudnessRangeEnd() const;
float getLoudnessRange() const;
/** Returns the time passed since the last reset.
In seconds.
*/
float getMeasurementDuration() const;

void setFreezeLoudnessRangeOnSilence (bool freeze);
void reset();
private:
static int round (double d);
/** The buffer given to processBlock() will be copied to this buffer, such
that the filtering and squaring won't affect the audio output. I.e. thanks
@@ -99,7 +109,7 @@ private:
SecondOrderIIRFilter preFilter;
SecondOrderIIRFilter revisedLowFrequencyBCurveFilter;
int numberOfBins;
int numberOfSamplesPerBin;
int numberOfSamplesInAllBins;
@@ -108,7 +118,13 @@ private:
int numberOfBinsToCover100ms;
int numberOfBinsSinceLastGateMeasurementForI;
int millisecondsSinceLastGateMeasurementForLRA;
// int millisecondsSinceLastGateMeasurementForLRA;
/** The duration of the current measurement.
duration * 0.1 = the measurement duration in seconds.
*/
int measurementDuration;
/**
After the samples are filtered and squared, they need to be
@@ -133,7 +149,7 @@ private:
But if you ask for a measurement at time t, it will be the
accurate measurement at time t - dt, where dt \in e.g. [0, 1/20s].
*/
OwnedArray <OwnedArray<double>> bin;
vector<vector<double>> bin;
int currentBin;
int numberOfSamplesInTheCurrentBin;
@@ -143,19 +159,18 @@ private:
3 seconds.
A value for each channel.
*/
OwnedArray<double> averageOfTheLast3s;
vector<double> averageOfTheLast3s;
/*
The average of the filtered and squared samples of the last
400 milliseconds.
A value for each channel.
*/
OwnedArray<double> averageOfTheLast400ms;
vector<double> averageOfTheLast400ms;
Array<double> channelWeighting;
vector<double> channelWeighting;
Array<float> shortTermLoudness;
Array<float> momentaryLoudness;
vector<float> momentaryLoudnessForIndividualChannels;
/** If there is no signal at all, the methods getShortTermLoudness() and
getMomentaryLoudness() would perform a log10(0) which would result in
@@ -175,23 +190,19 @@ private:
double sumOfAllBlocksToCalculateRelativeThreshold;
double relativeThreshold;
int LRAnumberOfBlocksToCalculateRelativeThreshold;
double LRAsumOfAllBlocksToCalculateRelativeThreshold;
double LRArelativeThreshold;
int numberOfBlocksToCalculateRelativeThresholdLRA;
double sumOfAllBlocksToCalculateRelativeThresholdLRA;
double relativeThresholdLRA;
static const double lowestBlockLoudnessToConsider;
static const double highestBlockLoudnessToConsider;
/** The difference in loudness between two adjacent bins in the histogram.
Measured in LU;
*/
static const double histogramLoudnessStepSize;
/** Two adjacant bins in the histogram also correspond to two weighted
sums. They are related by this factor.
WeightedSum2 = WeightedSum1 * histogramWeightedSumStepFactor.
/** A lower bound for the histograms (for I and LRA).
If a measured block has a value lower than this, it will not be
considered in the calculation for I and LRA.

Without the possibility to increase the pre-measurement-gain at any
point after the measurement has started, this could have been set
to the absoluteThreshold = -70 LUFS.
*/
static const double histogramWeightedSumStepFactor;
static const double lowestBlockLoudnessToConsider;
/** Storage for the loudnesses of all 400ms blocks since the last reset.
@@ -199,14 +210,21 @@ private:
bigger than the relative threshold are needed to calculate the gated
loudness (integrated loudness), it is mandatory to keep track of all
block loudnesses.
*/
vector<int> histogramOfBlockLoudness;
/** The main loudness value of interest.
It is the return value of getIntegratedLoudness().
Adjacent bins are set apart by 0.1 LU which seems to be sufficient.
Key value = Loudness * 10 (to get an integer value).
*/
map<int,int> histogramOfBlockLoudness;
/** The main loudness value of interest. */
float integratedLoudness;

float shortTermLoudness;
float maximumShortTermLoudness;

float momentaryLoudness;
float maximumMomentaryLoudness;
/** Like histogramOfBlockLoudness, but for the measurement of the
loudness range.
@@ -215,7 +233,7 @@ private:
loudness range, because the measurement blocks for the loudness
range need to be of length 3s. Vs 400ms.
*/
vector<int> LRAhistogramOfBlockLoudness;
map<int,int> histogramOfBlockLoudnessLRA;
/**
The return values for the corresponding get member functions.
@@ -224,10 +242,11 @@ private:
*/
float loudnessRangeStart;
float loudnessRangeEnd;

bool freezeLoudnessRangeOnSilence;
bool currentBlockIsSilent;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Ebu128LoudnessMeter);
};

#endif // __EBU128_LOUDNESS_METER__

+ 1
- 1
ports/LUFSMeter/source/LUFSMeterAudioProcessor.cpp View File

@@ -290,7 +290,7 @@ float LUFSMeterAudioProcessor::getShortTermLoudness()
return ebu128LoudnessMeter.getShortTermLoudness();
}
const Array<float>& LUFSMeterAudioProcessor::getMomentaryLoudnessForIndividualChannels()
vector<float>& LUFSMeterAudioProcessor::getMomentaryLoudnessForIndividualChannels()
{
return ebu128LoudnessMeter.getMomentaryLoudnessForIndividualChannels();
}


+ 1
- 1
ports/LUFSMeter/source/LUFSMeterAudioProcessor.h View File

@@ -113,7 +113,7 @@ public:
//==============================================================================
float getShortTermLoudness();
const Array<float>& getMomentaryLoudnessForIndividualChannels();
vector<float>& getMomentaryLoudnessForIndividualChannels();
float getMomentaryLoudness();


+ 34
- 36
ports/LUFSMeter/source/filters/SecondOrderIIRFilter.cpp View File

@@ -5,7 +5,7 @@
This file is part of the LUFS Meter audio measurement plugin.
Copyright 2011-12 by Klangfreund, Samuel Gaehwiler.
Copyright 2011-2016 by Klangfreund, Samuel Gaehwiler.
-------------------------------------------------------------------------------
@@ -20,8 +20,7 @@
-------------------------------------------------------------------------------
To release a closed-source product which uses the LUFS Meter or parts of it,
a commercial license is available. Visit www.klangfreund.com/lufsmeter for more
information.
get in contact via www.klangfreund.com/contact/.
===============================================================================
*/
@@ -36,24 +35,26 @@ SecondOrderIIRFilter::SecondOrderIIRFilter(double b0_at48k_,
double b2_at48k_,
double a1_at48k_,
double a2_at48k_)
: b0_at48k(b0_at48k_),
b1_at48k(b1_at48k_),
b2_at48k(b2_at48k_),
a1_at48k(a1_at48k_),
a2_at48k(a2_at48k_),
b0(b0_at48k_),
b1(b1_at48k_),
b2(b2_at48k_),
a1(a1_at48k_),
a2(a2_at48k_)
: b0_at48k {b0_at48k_},
b1_at48k {b1_at48k_},
b2_at48k {b2_at48k_},
a1_at48k {a1_at48k_},
a2_at48k {a2_at48k_},
b0 {b0_at48k_},
b1 {b1_at48k_},
b2 {b2_at48k_},
a1 {a1_at48k_},
a2 {a2_at48k_},
numberOfChannels {0}
{
// Determine the values Q, VH, VB, VL and arctanK.
// See 111222_my_notes_to_the_calculation_of_the_filter_coefficients.tif
// for the derivations of these equations.
double KoverQ = (2. - 2.*a2_at48k)/(a2_at48k - a1_at48k + 1.);
double K = sqrt((a1_at48k + a2_at48k + 1.)/(a2_at48k - a1_at48k + 1.));
Q = K/KoverQ;
arctanK = atan(K);
const double KoverQ = (2. - 2. * a2_at48k) / (a2_at48k - a1_at48k + 1.);
const double K = sqrt ((a1_at48k + a2_at48k + 1.) / (a2_at48k - a1_at48k + 1.));
Q = K / KoverQ;
arctanK = atan (K);
VB = (b0_at48k - b2_at48k)/(1. - a2_at48k);
VH = (b0_at48k - b1_at48k + b2_at48k)/(a2_at48k - a1_at48k + 1.);
VL = (b0_at48k + b1_at48k + b2_at48k)/(a1_at48k + a2_at48k + 1.);
@@ -65,22 +66,18 @@ SecondOrderIIRFilter::~SecondOrderIIRFilter()
//==============================================================================
void SecondOrderIIRFilter::prepareToPlay (double sampleRate,
int numberOfChannels)
int numberOfChannels_)
{
// DEB("prepareToPlay called.")
// Initialize the two Arrays z1 and z2.
// I.e. fill as many values into it as there are audio channels.
z1.clear();
z2.clear();
for (int i = 0; i != numberOfChannels; ++i)
{
z1.add(0.0);
z2.add(0.0);
}
numberOfChannels = numberOfChannels_;
// Initialize z1 and z2.
z1.calloc (numberOfChannels);
z2.calloc (numberOfChannels);
// Determine the filter coefficients.
double sampleRate48k = 48000.;
const double sampleRate48k = 48000.;
if (sampleRate == sampleRate48k)
{
b0 = b0_at48k;
@@ -93,8 +90,8 @@ void SecondOrderIIRFilter::prepareToPlay (double sampleRate,
{
// See 111222_my_notes_to_the_calculation_of_the_filter_coefficients.tif
// for the derivations of these equations.
double K = tan(arctanK*sampleRate48k/sampleRate);
double commonFactor = 1./(1. + K/Q + K*K);
const double K = tan (arctanK * sampleRate48k / sampleRate);
const double commonFactor = 1. / (1. + K/Q + K*K);
b0 = (VH + VB*K/Q + VL*K*K)*commonFactor;
b1 = 2.*(VL*K*K - VH)*commonFactor;
b2 = (VH - VB*K/Q + VL*K*K)*commonFactor;
@@ -109,7 +106,9 @@ void SecondOrderIIRFilter::releaseResources()
void SecondOrderIIRFilter::processBlock (AudioSampleBuffer& buffer)
{
for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
const int numOfChannels = jmin (numberOfChannels, buffer.getNumChannels());
for (int channel = 0; channel < numOfChannels; ++channel)
{
float* samples = buffer.getWritePointer (channel);
@@ -122,17 +121,16 @@ void SecondOrderIIRFilter::processBlock (AudioSampleBuffer& buffer)
+ b1 * z1[channel]
+ b2 * z2[channel];
// This is copied from juce_IIRFilter.cpp, processSamples(),
// line 101.
// Copied from juce_IIRFilter.cpp, processSamples(),
#if JUCE_INTEL
if (!(out < -1.0e-8 || out > 1.0e-8))
out = 0.0;
#endif
z2.set(channel, z1[channel]);
z1.set(channel, factorForB0);
z2[channel] = z1[channel];
z1[channel] = factorForB0;
samples[i] = float(out);
samples[i] = float (out);
}
}


+ 13
- 11
ports/LUFSMeter/source/filters/SecondOrderIIRFilter.h View File

@@ -5,7 +5,7 @@
This file is part of the LUFS Meter audio measurement plugin.
Copyright 2011-12 by Klangfreund, Samuel Gaehwiler.
Copyright 2011-2016 by Klangfreund, Samuel Gaehwiler.
-------------------------------------------------------------------------------
@@ -20,8 +20,7 @@
-------------------------------------------------------------------------------
To release a closed-source product which uses the LUFS Meter or parts of it,
a commercial license is available. Visit www.klangfreund.com/lufsmeter for more
information.
get in contact via www.klangfreund.com/contact/.
===============================================================================
*/
@@ -31,7 +30,6 @@
#include "../MacrosAndJuceHeaders.h"
//==============================================================================
/** A second order IIR (infinite inpulse response) filter.
@@ -80,6 +78,7 @@ protected:
/** Filter coefficients, valid for a sample rate of 48000 Hertz.
*/
double b0_at48k, b1_at48k, b2_at48k, a1_at48k, a2_at48k;
/** Filter coefficients for the used sample rate. They are set in
prepareToPlay.
*/
@@ -89,15 +88,18 @@ private:
prepareToPlay to calculate the filter coefficients.
*/
double Q, VH, VB, VL, arctanK;
//==============================================================================
/** Will store the the previous value of the variable
factorForB2 for every audio channel.
/** Number of audio channels.
*/
Array<double> z1;
/** Will store the previous value of z1 for every
audio channel.
int numberOfChannels;
/** Stores the previous value of the variable factorForB2 for every audio channel.
*/
HeapBlock<double> z1;
/** Stores the previous value of z1 for every audio channel.
*/
Array<double> z2;
HeapBlock<double> z2;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SecondOrderIIRFilter);
};


+ 2
- 2
ports/LUFSMeter/source/gui/MultiChannelLoudnessBar.cpp View File

@@ -49,7 +49,7 @@ MultiChannelLoudnessBar::~MultiChannelLoudnessBar ()
maxLoudness.removeListener(this);
}
void MultiChannelLoudnessBar::setLoudness (const Array<float>& multiChannelLoudness)
void MultiChannelLoudnessBar::setLoudness (const vector<float>& multiChannelLoudness)
{
if (multiChannelLoudness.size() != currentMultiChannelLoudness.size())
{
@@ -92,7 +92,7 @@ void MultiChannelLoudnessBar::paint (Graphics& g)
g.setColour (colour);
float topLeftX = 0.0f;
for (int channel = 0; channel < currentMultiChannelLoudness.size(); ++channel)
for (size_t channel = 0; channel < currentMultiChannelLoudness.size(); ++channel)
{
float loudnessOfThisChannel = currentMultiChannelLoudness[channel];


+ 3
- 2
ports/LUFSMeter/source/gui/MultiChannelLoudnessBar.h View File

@@ -32,6 +32,7 @@
#include "../MacrosAndJuceHeaders.h"
using std::vector;
//==============================================================================
@@ -55,7 +56,7 @@ public:
~MultiChannelLoudnessBar ();
void setLoudness (const Array<float>& multiChannelLoudness);
void setLoudness (const vector<float>& multiChannelLoudness);
void valueChanged (Value & value) override;
@@ -82,7 +83,7 @@ private:
Colour colour;
Array<float> currentMultiChannelLoudness;
vector<float> currentMultiChannelLoudness;
Value minLoudness;
Value maxLoudness;
};


Loading…
Cancel
Save