From 9d5289f2e2aff4675543de5b527aeca26bf5f5d5 Mon Sep 17 00:00:00 2001 From: nadavskloot <50923728+nadavskloot@users.noreply.github.com> Date: Mon, 21 Feb 2022 21:10:03 -0600 Subject: [PATCH] Updating LoudnessMeter to Juce 6 --- Ebu128LoudnessMeter.cpp | 254 ++++++++++++++++++++++++------- Ebu128LoudnessMeter.h | 95 +++++++----- MacrosAndJuceHeaders.h | 18 +-- PluginEditor.cpp | 75 +++++++++ PluginEditor.h | 66 ++++++++ filters/SecondOrderIIRFilter.cpp | 16 +- filters/SecondOrderIIRFilter.h | 26 ++-- 7 files changed, 421 insertions(+), 129 deletions(-) create mode 100644 PluginEditor.cpp create mode 100644 PluginEditor.h diff --git a/Ebu128LoudnessMeter.cpp b/Ebu128LoudnessMeter.cpp index bbb24d3..fa714a4 100644 --- a/Ebu128LoudnessMeter.cpp +++ b/Ebu128LoudnessMeter.cpp @@ -1,7 +1,7 @@ /* =============================================================================== - Ebu128LoudnessMeter.cpp + Ebu128LoudnessMeter By Samuel Gaehwiler from Klangfreund. @@ -39,19 +39,31 @@ =============================================================================== */ - #include "Ebu128LoudnessMeter.h" +#include "PluginEditor.h" +#include // static member constants // ----------------------- -const float Ebu128LoudnessMeter::minimalReturnValue = -300.0f; -const double Ebu128LoudnessMeter::absoluteThreshold = -70.0; +const float Ebu128LoudnessMeterAudioProcessor::minimalReturnValue = -300.0f; +const double Ebu128LoudnessMeterAudioProcessor::absoluteThreshold = -70.0; // Specification for the histograms. -const double Ebu128LoudnessMeter::lowestBlockLoudnessToConsider = -100.0; // LUFS - - -Ebu128LoudnessMeter::Ebu128LoudnessMeter() - : bufferForMeasurement (2, 2048), // Initialise the buffer with some common values. +const double Ebu128LoudnessMeterAudioProcessor::lowestBlockLoudnessToConsider = -100.0; // LUFS + + +//============================================================================== +Ebu128LoudnessMeterAudioProcessor::Ebu128LoudnessMeterAudioProcessor() +#ifndef JucePlugin_PreferredChannelConfigurations + : AudioProcessor (BusesProperties() + #if ! JucePlugin_IsMidiEffect + #if ! JucePlugin_IsSynth + .withInput ("Input", juce::AudioChannelSet::stereo(), true) + #endif + .withOutput ("Output", juce::AudioChannelSet::stereo(), true) + #endif + ), +#endif + bufferForMeasurement (2, 2048), // Initialise the buffer with some common values. // Also initialise the two filters with the coefficients for a sample // rate of 44100 Hz. These values are given in the ITU-R BS.1770-2. preFilter (1.53512485958697, // b0 @@ -89,27 +101,21 @@ Ebu128LoudnessMeter::Ebu128LoudnessMeter() freezeLoudnessRangeOnSilence (false), currentBlockIsSilent (false) { - DBG ("The longest possible measurement until a buffer overflow = " - + String (INT_MAX / 10. / 3600. / 365.) + " years"); - - // If this class is used without caution and processBlock - // is called before prepareToPlay, divisions by zero - // might occure. E.g. if numberOfSamplesInAllBins = 0. - // - // To prevent this, prepareToPlay is called here with - // some arbitrary arguments. - prepareToPlay (44100.0, 2, 512, 20); +// DBG ("The longest possible measurement until a buffer overflow = " +// + juce::String (INT_MAX / 10. / 3600. / 365.) + " years"); } -Ebu128LoudnessMeter::~Ebu128LoudnessMeter() +Ebu128LoudnessMeterAudioProcessor::~Ebu128LoudnessMeterAudioProcessor() { } -void Ebu128LoudnessMeter::prepareToPlay (double sampleRate, - int numberOfInputChannels, - int estimatedSamplesPerBlock, - int expectedRequestRate) +void Ebu128LoudnessMeterAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) { + // Use this method as the place to do any pre-playback + // initialisation that you need.. + auto numberOfInputChannels = getTotalNumInputChannels(); + auto expectedRequestRate = 10; + auto estimatedSamplesPerBlock = samplesPerBlock; // Resize the buffer. bufferForMeasurement.setSize (numberOfInputChannels, estimatedSamplesPerBlock); @@ -142,13 +148,14 @@ void Ebu128LoudnessMeter::prepareToPlay (double sampleRate, if (expectedRequestRate > sampleRate/2) { expectedRequestRate = 10; - DEB ("Not possible to make expectedRequestRate a multiple of 10 and " + // was DEB + DBG ("Not possible to make expectedRequestRate a multiple of 10 and " "a divisor of the samplerate."); break; } } - DEB ("expectedRequestRate = " + String(expectedRequestRate)); +// DEB ("expectedRequestRate = " + juce::String(expectedRequestRate)); // Figure out how many bins are needed. const int timeOfAccumulationForShortTerm = 3; // seconds. @@ -158,9 +165,9 @@ void Ebu128LoudnessMeter::prepareToPlay (double sampleRate, numberOfSamplesInAllBins = numberOfBins * numberOfSamplesPerBin; numberOfBinsToCover100ms = int (0.1 * expectedRequestRate); - DEB ("numberOfBinsToCover100ms = " + String (numberOfBinsToCover100ms)); +// DEB ("numberOfBinsToCover100ms = " + String (numberOfBinsToCover100ms)); numberOfBinsToCover400ms = int (0.4 * expectedRequestRate); - DEB ("numberOfBinsToCover400ms = " + String (numberOfBinsToCover400ms)); +// DEB ("numberOfBinsToCover400ms = " + String (numberOfBinsToCover400ms)); numberOfSamplesIn400ms = numberOfBinsToCover400ms * numberOfSamplesPerBin; currentBin = 0; @@ -193,7 +200,7 @@ void Ebu128LoudnessMeter::prepareToPlay (double sampleRate, reset(); } -void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) +void Ebu128LoudnessMeterAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages) { // Copy the buffer, such that all upcoming calculations won't affect // the audio output. We want the audio output to be exactly the same @@ -212,7 +219,7 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) if (magnitude < silenceThreshold) { currentBlockIsSilent = true; - DEB ("Silence detected.") +// DEB ("Silence detected.") } else currentBlockIsSilent = false; @@ -252,10 +259,10 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) // --------------------------------------- // To prevent EXC_BAD_ACCESS when the number of channels in the buffer // suddenly changes without calling prepareToPlay() in advance. - const int numberOfChannels = jmin (bufferForMeasurement.getNumChannels(), + const int numberOfChannels = juce::jmin (bufferForMeasurement.getNumChannels(), int (bin.size()), int (averageOfTheLast400ms.size()), - jmin (int (averageOfTheLast3s.size()), + juce::jmin (int (averageOfTheLast3s.size()), int (channelWeighting.size()))); jassert (bufferForMeasurement.getNumChannels() == int (bin.size())); jassert (bufferForMeasurement.getNumChannels() == int (averageOfTheLast400ms.size())); @@ -268,7 +275,7 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) // If the new samples from the bufferForMeasurement can all be added // to the same bin. - if (numberOfSamplesInTheCurrentBin + bufferForMeasurement.getNumSamples() + if (numberOfSamplesInTheCurrentBin + bufferForMeasurement.getNumSamples() < numberOfSamplesPerBin) { for (int k = 0; k != numberOfChannels; ++k) @@ -282,12 +289,12 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) } } - numberOfSamplesInTheCurrentBin += bufferForMeasurement.getNumSamples(); + numberOfSamplesInTheCurrentBin += bufferForMeasurement.getNumSamples(); } // If the new samples are split up between two (or more (which would be a // strange setup)) bins. - else + else { int positionInBuffer = 0; bool bufferStillContainsSamples = true; @@ -360,7 +367,7 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) if (weightedSum > 0.0) // This refers to equation (2) in ITU-R BS.1770-2 - shortTermLoudness = jmax (float (-0.691 + 10.* std::log10(weightedSum)), minimalReturnValue); + shortTermLoudness = juce::jmax (float (-0.691 + 10.* std::log10(weightedSum)), minimalReturnValue); else // Since returning a value of -nan most probably would lead to // a malfunction, return the minimal return value. @@ -407,7 +414,7 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) if (weightedSum > 0.0) // This refers to equation (2) in ITU-R BS.1770-2 - momentaryLoudness = jmax (float (-0.691 + 10. * std::log10(weightedSum)), minimalReturnValue); + momentaryLoudness = juce::jmax (float (-0.691 + 10. * std::log10(weightedSum)), minimalReturnValue); else // Since returning a value of -nan most probably would lead to // a malfunction, return a minimal return value. @@ -602,8 +609,8 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) // -------------------------------------------------------------- int numberOfBlocksLRA = 0; - for (map::iterator currentBinLRA = histogramOfBlockLoudnessLRA.find (closestBinAboveRelativeThresholdKeyLRA); - currentBinLRA != histogramOfBlockLoudnessLRA.end(); + for (map::iterator currentBinLRA = histogramOfBlockLoudnessLRA.find (closestBinAboveRelativeThresholdKeyLRA); + currentBinLRA != histogramOfBlockLoudnessLRA.end(); ++currentBinLRA) { const int nrOfBlocksInBinLRA = currentBinLRA->second; @@ -676,17 +683,19 @@ void Ebu128LoudnessMeter::processBlock (juce::AudioSampleBuffer &buffer) } } -float Ebu128LoudnessMeter::getShortTermLoudness() const + + +float Ebu128LoudnessMeterAudioProcessor::getShortTermLoudness() const { return shortTermLoudness; } -float Ebu128LoudnessMeter::getMaximumShortTermLoudness() const +float Ebu128LoudnessMeterAudioProcessor::getMaximumShortTermLoudness() const { return maximumShortTermLoudness; } -vector& Ebu128LoudnessMeter::getMomentaryLoudnessForIndividualChannels() +vector& Ebu128LoudnessMeterAudioProcessor::getMomentaryLoudnessForIndividualChannels() { // calculate the momentary loudness @@ -698,7 +707,7 @@ vector& Ebu128LoudnessMeter::getMomentaryLoudnessForIndividualChannels() if (averageOfTheLast400ms[k] > 0.0f) { // This refers to equation (2) in ITU-R BS.1770-2 - kthChannelMomentaryLoudness = jmax (float (-0.691 + 10. * std::log10(averageOfTheLast400ms[k])), minimalReturnValue); + kthChannelMomentaryLoudness = juce::jmax (float (-0.691 + 10. * std::log10(averageOfTheLast400ms[k])), minimalReturnValue); } momentaryLoudnessForIndividualChannels[k] = kthChannelMomentaryLoudness; @@ -707,54 +716,54 @@ vector& Ebu128LoudnessMeter::getMomentaryLoudnessForIndividualChannels() return momentaryLoudnessForIndividualChannels; } -float Ebu128LoudnessMeter::getMomentaryLoudness() const +float Ebu128LoudnessMeterAudioProcessor::getMomentaryLoudness() const { return momentaryLoudness; } -float Ebu128LoudnessMeter::getMaximumMomentaryLoudness() const +float Ebu128LoudnessMeterAudioProcessor::getMaximumMomentaryLoudness() const { return maximumMomentaryLoudness; } -float Ebu128LoudnessMeter::getIntegratedLoudness() const +float Ebu128LoudnessMeterAudioProcessor::getIntegratedLoudness() const { return integratedLoudness; } -float Ebu128LoudnessMeter::getLoudnessRangeStart() const +float Ebu128LoudnessMeterAudioProcessor::getLoudnessRangeStart() const { return loudnessRangeStart; } -float Ebu128LoudnessMeter::getLoudnessRangeEnd() const +float Ebu128LoudnessMeterAudioProcessor::getLoudnessRangeEnd() const { return loudnessRangeEnd; } -float Ebu128LoudnessMeter::getLoudnessRange() const +float Ebu128LoudnessMeterAudioProcessor::getLoudnessRange() const { return loudnessRangeEnd - loudnessRangeStart; } -float Ebu128LoudnessMeter::getMeasurementDuration() const +float Ebu128LoudnessMeterAudioProcessor::getMeasurementDuration() const { return measurementDuration * 0.1f; } -void Ebu128LoudnessMeter::setFreezeLoudnessRangeOnSilence (bool freeze) +void Ebu128LoudnessMeterAudioProcessor::setFreezeLoudnessRangeOnSilence (bool freeze) { freezeLoudnessRangeOnSilence = freeze; } -void Ebu128LoudnessMeter::reset() +void Ebu128LoudnessMeterAudioProcessor::reset1() { // the bins // It is important to use assign() (replace all values) and not // resize() (only set new elements to the provided value). bin.assign (bin.size(), vector (numberOfBins, 0.0)); - // To ensure the returned momentary and short term loudness are at its + // To ensure the returned momentary and short term loudness are at its // minimum, even if no audio is processed at the moment. averageOfTheLast3s.assign (averageOfTheLast400ms.size(), 0.0); averageOfTheLast400ms.assign (averageOfTheLast400ms.size(), 0.0); @@ -794,9 +803,146 @@ void Ebu128LoudnessMeter::reset() maximumMomentaryLoudness = minimalReturnValue; } -int Ebu128LoudnessMeter::round (double d) +int Ebu128LoudnessMeterAudioProcessor::round (double d) { // For a negative d, int (d) will choose the next higher number, // therfore the - 0.5. return (d > 0.0) ? int (d + 0.5) : int (d - 0.5); } + + + +//============================================================================== +const juce::String Ebu128LoudnessMeterAudioProcessor::getName() const +{ + return JucePlugin_Name; +} + +bool Ebu128LoudnessMeterAudioProcessor::acceptsMidi() const +{ + #if JucePlugin_WantsMidiInput + return true; + #else + return false; + #endif +} + +bool Ebu128LoudnessMeterAudioProcessor::producesMidi() const +{ + #if JucePlugin_ProducesMidiOutput + return true; + #else + return false; + #endif +} + +bool Ebu128LoudnessMeterAudioProcessor::isMidiEffect() const +{ + #if JucePlugin_IsMidiEffect + return true; + #else + return false; + #endif +} + +double Ebu128LoudnessMeterAudioProcessor::getTailLengthSeconds() const +{ + return 0.0; +} + +int Ebu128LoudnessMeterAudioProcessor::getNumPrograms() +{ + return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, + // so this should be at least 1, even if you're not really implementing programs. +} + +int Ebu128LoudnessMeterAudioProcessor::getCurrentProgram() +{ + return 0; +} + +void Ebu128LoudnessMeterAudioProcessor::setCurrentProgram (int index) +{ +} + +const juce::String Ebu128LoudnessMeterAudioProcessor::getProgramName (int index) +{ + return {}; +} + +void Ebu128LoudnessMeterAudioProcessor::changeProgramName (int index, const juce::String& newName) +{ +} + +//============================================================================== + + + +void Ebu128LoudnessMeterAudioProcessor::releaseResources() +{ + // When playback stops, you can use this as an opportunity to free up any + // spare memory, etc. +} + +#ifndef JucePlugin_PreferredChannelConfigurations +bool Ebu128LoudnessMeterAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const +{ + #if JucePlugin_IsMidiEffect + juce::ignoreUnused (layouts); + return true; + #else + // This is the place where you check if the layout is supported. + // In this template code we only support mono or stereo. + // Some plugin hosts, such as certain GarageBand versions, will only + // load plugins that support stereo bus layouts. + if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() + && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) + return false; + + // This checks if the input layout matches the output layout + #if ! JucePlugin_IsSynth + if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) + return false; + #endif + + return true; + #endif +} +#endif + + + +//============================================================================== +bool Ebu128LoudnessMeterAudioProcessor::hasEditor() const +{ + return true; // (change this to false if you choose to not supply an editor) +} + +juce::AudioProcessorEditor* Ebu128LoudnessMeterAudioProcessor::createEditor() +{ + return new Ebu128LoudnessMeterAudioProcessorEditor (*this); +} + +//============================================================================== +void Ebu128LoudnessMeterAudioProcessor::getStateInformation (juce::MemoryBlock& destData) +{ + // You should use this method to store your parameters in the memory block. + // You could do that either as raw data, or use the XML or ValueTree classes + // as intermediaries to make it easy to save and load complex data. +} + +void Ebu128LoudnessMeterAudioProcessor::setStateInformation (const void* data, int sizeInBytes) +{ + // You should use this method to restore your parameters from this memory block, + // whose contents will have been created by the getStateInformation() call. +} + + + + +//============================================================================== +// This creates new instances of the plugin.. +juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() +{ + return new Ebu128LoudnessMeterAudioProcessor(); +} diff --git a/Ebu128LoudnessMeter.h b/Ebu128LoudnessMeter.h index 30df24a..8d919b5 100644 --- a/Ebu128LoudnessMeter.h +++ b/Ebu128LoudnessMeter.h @@ -1,7 +1,7 @@ /* =============================================================================== - Ebu128LoudnessMeter.h + Ebu128LoudnessMeter By Samuel Gaehwiler from Klangfreund. @@ -39,10 +39,9 @@ =============================================================================== */ +#pragma once -#ifndef __EBU128_LOUDNESS_METER__ -#define __EBU128_LOUDNESS_METER__ - +#include #include "MacrosAndJuceHeaders.h" #include "filters/SecondOrderIIRFilter.h" #include @@ -51,42 +50,51 @@ using std::map; using std::vector; + +//============================================================================== /** - Measures the loudness of an audio stream. - - The loudness is measured according to the documents - (List) - - EBU - R 128 - - ITU 1770 Rev 2,3 and 4 - - EBU - Tech 3341 (EBU mode metering) - - EBU - Tech 3342 (LRA, loudness range) - - EBU - Tech 3343 - */ -class Ebu128LoudnessMeter //: public AudioProcessor +*/ +class Ebu128LoudnessMeterAudioProcessor : public juce::AudioProcessor { public: - Ebu128LoudnessMeter(); - ~Ebu128LoudnessMeter(); - - // --------- AudioProcessor methods --------- -// const String getName (); + //============================================================================== + Ebu128LoudnessMeterAudioProcessor(); + ~Ebu128LoudnessMeterAudioProcessor() override; + + //============================================================================== + void prepareToPlay (double sampleRate, int samplesPerBlock) override; + void releaseResources() override; + + #ifndef JucePlugin_PreferredChannelConfigurations + bool isBusesLayoutSupported (const BusesLayout& layouts) const override; + #endif + + void processBlock (juce::AudioBuffer&, juce::MidiBuffer&) override; + + //============================================================================== + juce::AudioProcessorEditor* createEditor() override; + bool hasEditor() const override; + + //============================================================================== + const juce::String getName() const override; + + bool acceptsMidi() const override; + bool producesMidi() const override; + bool isMidiEffect() const override; + double getTailLengthSeconds() const override; + + //============================================================================== + int getNumPrograms() override; + int getCurrentProgram() override; + void setCurrentProgram (int index) override; + const juce::String getProgramName (int index) override; + void changeProgramName (int index, const juce::String& newName) override; + + //============================================================================== + void getStateInformation (juce::MemoryBlock& destData) override; + void setStateInformation (const void* data, int sizeInBytes) override; - /** - @param sampleRate - @param numberOfChannels - @param estimatedSamplesPerBlock - @param expectedRequestRate Assumption about how many times - a second the measurement values will be requested. Internally, - this will be changed to a multiple of 10 because exactly every - 0.1 second a gating block needs to be measured (for the - integrated loudness measurement). - */ - void prepareToPlay (double sampleRate, - int numberOfInputChannels, - int estimatedSamplesPerBlock, - int expectedRequestRate); - void processBlock (AudioSampleBuffer &buffer); float getShortTermLoudness() const; float getMaximumShortTermLoudness() const; @@ -108,9 +116,16 @@ class Ebu128LoudnessMeter //: public AudioProcessor void setFreezeLoudnessRangeOnSilence (bool freeze); - void reset(); + void reset1(); + + private: + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Ebu128LoudnessMeterAudioProcessor) + + + static int round (double d); /** The buffer given to processBlock() will be copied to this buffer, such @@ -119,7 +134,7 @@ class Ebu128LoudnessMeter //: public AudioProcessor It also stores the number of input channels implicitely, set in prepareToPlay. */ - AudioSampleBuffer bufferForMeasurement; + juce::AudioSampleBuffer bufferForMeasurement; SecondOrderIIRFilter preFilter; SecondOrderIIRFilter revisedLowFrequencyBCurveFilter; @@ -147,7 +162,7 @@ class Ebu128LoudnessMeter //: public AudioProcessor 3 seconds of samples need to be accumulated. For the other measurements shorter windows are used. - This task could be solved using a ring buffer capable of + This task could be solved using a ring buffer capable of holding 3 seconds of (multi-channel) audio and accumulate the samples every time the GUI wants to display the measurement. @@ -260,7 +275,5 @@ class Ebu128LoudnessMeter //: public AudioProcessor bool freezeLoudnessRangeOnSilence; bool currentBlockIsSilent; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Ebu128LoudnessMeter); -}; -#endif // __EBU128_LOUDNESS_METER__ +}; diff --git a/MacrosAndJuceHeaders.h b/MacrosAndJuceHeaders.h index 3eb5f2e..c96b815 100644 --- a/MacrosAndJuceHeaders.h +++ b/MacrosAndJuceHeaders.h @@ -2,8 +2,6 @@ =============================================================================== Macros.h - - By Samuel Gaehwiler from Klangfreund. Used in the klangfreund.com/lufsmeter/ @@ -36,16 +34,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------------------------------------------------------------------------------- - - 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. - =============================================================================== */ +#pragma once + #ifndef __LUFSMETER_MACROS__ #define __LUFSMETER_MACROS__ @@ -65,18 +59,18 @@ #include // Contains strrchr, which is used in DEB. /** Sams debug macro which also has a time stamp. - - Writes a string to the standard error stream, together with the time + + Writes a string to the standard error stream, together with the time of occurence. This is only compiled in a debug build. @see Logger::outputDebugString */ // Windows Debug #if (JUCE_DEBUG || DOXYGEN) && JUCE_WINDOWS // Windows doesn't understand __func__ - #define DEB(dbgtext) { Time currentTime = Time::getCurrentTime(); const bool includeDate = false; const bool includeTime = true; const bool includeSeconds = true; const bool use24HourClock = true; String filename = strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__; DBG(currentTime.toString(includeDate, includeTime, includeSeconds, use24HourClock) + ", " + filename + ":" + String(__LINE__) + ": " + dbgtext) } + #define DEB(dbgtext) { Time currentTime = Time::getCurrentTime(); const bool includeDate = false; const bool includeTime = true; const bool includeSeconds = true; const bool use24HourClock = true; String filename = strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__; DBG(currentTime.toString(includeDate, includeTime, includeSeconds, use24HourClock) + ", " + filename + ":" + String(__LINE__) + ": " + dbgtext) } // Mac Debug #elif (JUCE_DEBUG || DOXYGEN) - #define DEB(dbgtext) { Time currentTime = Time::getCurrentTime(); const bool includeDate = false; const bool includeTime = true; const bool includeSeconds = true; const bool use24HourClock = true; String filename = strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__; DBG(currentTime.toString(includeDate, includeTime, includeSeconds, use24HourClock) + ", " + filename + "::" + __func__ + ":" + String(__LINE__) + ": " + dbgtext) } + #define DEB(dbgtext) { Time currentTime = Time::getCurrentTime(); const bool includeDate = false; const bool includeTime = true; const bool includeSeconds = true; const bool use24HourClock = true; String filename = strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__; DBG(currentTime.toString(includeDate, includeTime, includeSeconds, use24HourClock) + ", " + filename + "::" + __func__ + ":" + String(__LINE__) + ": " + dbgtext) } // Release #else #define DEB(dbgtext) diff --git a/PluginEditor.cpp b/PluginEditor.cpp new file mode 100644 index 0000000..f3f6329 --- /dev/null +++ b/PluginEditor.cpp @@ -0,0 +1,75 @@ +/* + =============================================================================== + + Ebu128LoudnessMeter + + + By Samuel Gaehwiler from Klangfreund. + Used in the klangfreund.com/lufsmeter/ + + License: MIT + + I'd be happy to hear about your usage of this code! + -> klangfreund.com/contact/ + + ------------------------------------------------------------------------------- + + The MIT License (MIT) + + Copyright (c) 2018 Klangfreund, Samuel Gaehwiler + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + =============================================================================== + */ + +#include "Ebu128LoudnessMeter.h" +#include "PluginEditor.h" + +//============================================================================== +Ebu128LoudnessMeterAudioProcessorEditor::Ebu128LoudnessMeterAudioProcessorEditor (Ebu128LoudnessMeterAudioProcessor& p) + : AudioProcessorEditor (&p), audioProcessor (p) +{ + // Make sure that before the constructor has finished, you've set the + // editor's size to whatever you need it to be. + setSize (400, 300); + +} + +Ebu128LoudnessMeterAudioProcessorEditor::~Ebu128LoudnessMeterAudioProcessorEditor() +{ +} + +//============================================================================== +void Ebu128LoudnessMeterAudioProcessorEditor::paint (juce::Graphics& g) +{ + // (Our component is opaque, so we must completely fill the background with a solid colour) + g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); + + g.setColour (juce::Colours::white); + g.setFont (15.0f); + g.drawFittedText ("Hello World!", getLocalBounds(), juce::Justification::centred, 1); +} + +void Ebu128LoudnessMeterAudioProcessorEditor::resized() +{ + // This is generally where you'll want to lay out the positions of any + // subcomponents in your editor.. + +} diff --git a/PluginEditor.h b/PluginEditor.h new file mode 100644 index 0000000..57cd679 --- /dev/null +++ b/PluginEditor.h @@ -0,0 +1,66 @@ +/* + =============================================================================== + + Ebu128LoudnessMeter + + + By Samuel Gaehwiler from Klangfreund. + Used in the klangfreund.com/lufsmeter/ + + License: MIT + + I'd be happy to hear about your usage of this code! + -> klangfreund.com/contact/ + + ------------------------------------------------------------------------------- + + The MIT License (MIT) + + Copyright (c) 2018 Klangfreund, Samuel Gaehwiler + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + =============================================================================== + */ + +#pragma once + +#include +#include "Ebu128LoudnessMeter.h" + +//============================================================================== +/** +*/ +class Ebu128LoudnessMeterAudioProcessorEditor : public juce::AudioProcessorEditor +{ +public: + Ebu128LoudnessMeterAudioProcessorEditor (Ebu128LoudnessMeterAudioProcessor&); + ~Ebu128LoudnessMeterAudioProcessorEditor() override; + + //============================================================================== + void paint (juce::Graphics&) override; + void resized() override; + +private: + // This reference is provided as a quick way for your editor to + // access the processor object that created it. + Ebu128LoudnessMeterAudioProcessor& audioProcessor; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Ebu128LoudnessMeterAudioProcessorEditor) +}; diff --git a/filters/SecondOrderIIRFilter.cpp b/filters/SecondOrderIIRFilter.cpp index 11a6218..f3e78c7 100644 --- a/filters/SecondOrderIIRFilter.cpp +++ b/filters/SecondOrderIIRFilter.cpp @@ -1,9 +1,9 @@ /* =============================================================================== - SecondOrderIIRFilter.cpp - - + Ebu128LoudnessMeter + + By Samuel Gaehwiler from Klangfreund. Used in the klangfreund.com/lufsmeter/ @@ -67,11 +67,11 @@ SecondOrderIIRFilter::SecondOrderIIRFilter(double b0_at48k_, // for the derivations of these equations. 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; + 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.); + VL = (b0_at48k + b1_at48k + b2_at48k)/(a1_at48k + a2_at48k + 1.); } SecondOrderIIRFilter::~SecondOrderIIRFilter() @@ -79,7 +79,7 @@ SecondOrderIIRFilter::~SecondOrderIIRFilter() } //============================================================================== -void SecondOrderIIRFilter::prepareToPlay (double sampleRate, +void SecondOrderIIRFilter::prepareToPlay (double sampleRate, int numberOfChannels_) { // DEB("prepareToPlay called.") @@ -118,9 +118,9 @@ void SecondOrderIIRFilter::releaseResources() { } -void SecondOrderIIRFilter::processBlock (AudioSampleBuffer& buffer) +void SecondOrderIIRFilter::processBlock (juce::AudioSampleBuffer& buffer) { - const int numOfChannels = jmin (numberOfChannels, buffer.getNumChannels()); + const int numOfChannels = juce::jmin (numberOfChannels, buffer.getNumChannels()); for (int channel = 0; channel < numOfChannels; ++channel) { diff --git a/filters/SecondOrderIIRFilter.h b/filters/SecondOrderIIRFilter.h index 105a3c2..5731cc9 100644 --- a/filters/SecondOrderIIRFilter.h +++ b/filters/SecondOrderIIRFilter.h @@ -1,9 +1,9 @@ /* =============================================================================== - SecondOrderIIRFilter.h - - + Ebu128LoudnessMeter + + By Samuel Gaehwiler from Klangfreund. Used in the klangfreund.com/lufsmeter/ @@ -36,14 +36,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------------------------------------------------------------------------------- - - To release a closed-source product which uses the LUFS Meter or parts of it, - get in contact via www.klangfreund.com/contact/. - =============================================================================== */ +#pragma once + + #ifndef __FILTER_OF_SECOND_ORDER__ #define __FILTER_OF_SECOND_ORDER__ @@ -77,15 +75,15 @@ class SecondOrderIIRFilter virtual ~SecondOrderIIRFilter(); //============================================================================== - // Call before the playback starts, to let the filter prepare itself. + // Call before the playback starts, to let the filter prepare itself. virtual void prepareToPlay (double sampleRate, int numberOfChannels); - // Call after the playback has stopped, to let the filter free up any - // resources it no longer needs. + // Call after the playback has stopped, to let the filter free up any + // resources it no longer needs. virtual void releaseResources(); // Renders the next block. - void processBlock (AudioSampleBuffer& buffer); + void processBlock (juce::AudioSampleBuffer& buffer); void reset(); @@ -111,11 +109,11 @@ class SecondOrderIIRFilter /** Stores the previous value of the variable factorForB2 for every audio channel. */ - HeapBlock z1; + juce::HeapBlock z1; /** Stores the previous value of z1 for every audio channel. */ - HeapBlock z2; + juce::HeapBlock z2; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SecondOrderIIRFilter); };