diff --git a/src/Experimental.h b/src/Experimental.h index f41da64da..c1dcc2548 100644 --- a/src/Experimental.h +++ b/src/Experimental.h @@ -253,9 +253,6 @@ // PRL 31 July 2018 #define EXPERIMENTAL_DRAGGABLE_PLAY_HEAD -// mmm-1 22 Aug 2018 -//#define EXPERIMENTAL_R128_NORM - // JKC 29 July 2019 // OD_DATA made experimental. It is on the way out because // it is dangerous and has too many bugs. See bug 536 for example. diff --git a/src/effects/Normalize.cpp b/src/effects/Normalize.cpp index 2efb7ca2a..636367602 100644 --- a/src/effects/Normalize.cpp +++ b/src/effects/Normalize.cpp @@ -6,7 +6,6 @@ Dominic Mazzoni Vaughan Johnson (Preview) - Max Maisel (Loudness) *******************************************************************//** @@ -43,10 +42,6 @@ Param( PeakLevel, double, wxT("PeakLevel"), -1.0, -145.0, 0.0, Param( RemoveDC, bool, wxT("RemoveDcOffset"), true, false, true, 1 ); Param( ApplyGain, bool, wxT("ApplyGain"), true, false, true, 1 ); Param( StereoInd, bool, wxT("StereoIndependent"), false, false, true, 1 ); -#ifdef EXPERIMENTAL_R128_NORM -Param( LUFSLevel, double, wxT("LUFSLevel"), -23.0, -145.0, 0.0, 1 ); -Param( UseLoudness, bool, wxT("UseLoudness"), false, false, true, 1 ); -#endif BEGIN_EVENT_TABLE(EffectNormalize, wxEvtHandler) EVT_CHECKBOX(wxID_ANY, EffectNormalize::OnUpdateUI) @@ -59,10 +54,6 @@ EffectNormalize::EffectNormalize() mDC = DEF_RemoveDC; mGain = DEF_ApplyGain; mStereoInd = DEF_StereoInd; -#ifdef EXPERIMENTAL_R128_NORM - mLUFSLevel = DEF_LUFSLevel; - mUseLoudness = DEF_UseLoudness; -#endif SetLinearEffectFlag(false); } @@ -80,11 +71,7 @@ ComponentInterfaceSymbol EffectNormalize::GetSymbol() wxString EffectNormalize::GetDescription() { -#ifdef EXPERIMENTAL_R128_NORM - return _("Sets the peak amplitude or loudness of one or more tracks"); -#else return _("Sets the peak amplitude of one or more tracks"); -#endif } wxString EffectNormalize::ManualPage() @@ -105,10 +92,6 @@ bool EffectNormalize::DefineParams( ShuttleParams & S ){ S.SHUTTLE_PARAM( mGain, ApplyGain ); S.SHUTTLE_PARAM( mDC, RemoveDC ); S.SHUTTLE_PARAM( mStereoInd, StereoInd ); -#ifdef EXPERIMENTAL_R128_NORM - S.SHUTTLE_PARAM( mLUFSLevel, LUFSLevel ); - S.SHUTTLE_PARAM( mUseLoudness, UseLoudness ); -#endif return true; } @@ -118,10 +101,6 @@ bool EffectNormalize::GetAutomationParameters(CommandParameters & parms) parms.Write(KEY_ApplyGain, mGain); parms.Write(KEY_RemoveDC, mDC); parms.Write(KEY_StereoInd, mStereoInd); -#ifdef EXPERIMENTAL_R128_NORM - parms.Write(KEY_LUFSLevel, mLUFSLevel); - parms.Write(KEY_UseLoudness, mUseLoudness); -#endif return true; } @@ -132,19 +111,11 @@ bool EffectNormalize::SetAutomationParameters(CommandParameters & parms) ReadAndVerifyBool(ApplyGain); ReadAndVerifyBool(RemoveDC); ReadAndVerifyBool(StereoInd); -#ifdef EXPERIMENTAL_R128_NORM - ReadAndVerifyDouble(LUFSLevel); - ReadAndVerifyBool(UseLoudness); -#endif mPeakLevel = PeakLevel; mGain = ApplyGain; mDC = RemoveDC; mStereoInd = StereoInd; -#ifdef EXPERIMENTAL_R128_NORM - mLUFSLevel = LUFSLevel; - mUseLoudness = UseLoudness; -#endif return true; } @@ -180,10 +151,6 @@ bool EffectNormalize::Startup() mPeakLevel = -mPeakLevel; boolProxy = gPrefs->Read(base + wxT("StereoIndependent"), 0L); mStereoInd = (boolProxy == 1); -#ifdef EXPERIMENTAL_R128_NORM - mUseLoudness = false; - mLUFSLevel = DEF_LUFSLevel; -#endif SaveUserPreset(GetCurrentSettingsGroup()); @@ -203,20 +170,8 @@ bool EffectNormalize::Process() float ratio; if( mGain ) { -#ifdef EXPERIMENTAL_R128_NORM - if(mUseLoudness) { - // LU use 10*log10(...) instead of 20*log10(...) - // so multiply level by 2 and use standard DB_TO_LINEAR macro. - ratio = DB_TO_LINEAR(TrapDouble(mLUFSLevel*2, MIN_LUFSLevel, MAX_LUFSLevel)); - } - else { - // same value used for all tracks - ratio = DB_TO_LINEAR(TrapDouble(mPeakLevel, MIN_PeakLevel, MAX_PeakLevel)); - } -#else // same value used for all tracks ratio = DB_TO_LINEAR(TrapDouble(mPeakLevel, MIN_PeakLevel, MAX_PeakLevel)); -#endif } else { ratio = 1.0; @@ -257,16 +212,8 @@ bool EffectNormalize::Process() wxString trackName = track->GetName(); float extent; -#ifdef EXPERIMENTAL_R128_NORM - if (mUseLoudness) - // Loudness: use sum of both tracks. - // As a result, stereo tracks appear about 3 LUFS louder, - // as specified. - extent = 0; - else -#endif - // Will compute a maximum - extent = std::numeric_limits::lowest(); + // Will compute a maximum + extent = std::numeric_limits::lowest(); std::vector offsets; wxString msg; @@ -287,12 +234,7 @@ bool EffectNormalize::Process() AnalyseTrack( channel, msg, progress, offset, extent2 ); if ( ! bGoodResult ) goto break2; -#ifdef EXPERIMENTAL_R128_NORM - if (mUseLoudness) - extent += extent2; - else -#endif - extent = std::max( extent, extent2 ); + extent = std::max( extent, extent2 ); offsets.push_back(offset); // TODO: more-than-two-channels-message msg = topMsg + @@ -302,18 +244,6 @@ bool EffectNormalize::Process() // Compute the multiplier using extent if( (extent > 0) && mGain ) { mMult = ratio / extent; -#ifdef EXPERIMENTAL_R128_NORM - if(mUseLoudness) { - // PRL: See commit 9cbb67a for the origin of the next line, - // which has no effect because mMult is again overwritten. What - // was the intent? - - // LUFS is defined as -0.691 dB + 10*log10(sum(channels)) - mMult /= 0.8529037031; - // LUFS are related to square values so the multiplier must be the root. - mMult = sqrt(ratio / extent); - } -#endif } else mMult = 1.0; @@ -373,12 +303,7 @@ void EffectNormalize::PopulateOrExchange(ShuttleGui & S) // which that is will depend on translation. So decide that here. // (strictly we should count pixels, not characters). wxString prompt1 = _("Normalize peak amplitude to"); -#ifdef EXPERIMENTAL_R128_NORM - wxString prompt2 = _("Normalize loudness to"); - wxString longerPrompt = ((prompt1.length() > prompt2.length()) ? prompt1 : prompt2) + " "; -#else wxString longerPrompt = prompt1 + " "; -#endif // Now make the checkbox. mGainCheckBox = S.AddCheckBox(longerPrompt, mGain); @@ -398,11 +323,6 @@ void EffectNormalize::PopulateOrExchange(ShuttleGui & S) wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT); } S.EndHorizontalLay(); -#ifdef EXPERIMENTAL_R128_NORM - mUseLoudnessCheckBox = S.AddCheckBox(_("Use loudness instead of peak amplitude"), - mUseLoudness); - mUseLoudnessCheckBox->SetValidator(wxGenericValidator(&mGUIUseLoudness)); -#endif mStereoIndCheckBox = S.AddCheckBox(_("Normalize stereo channels independently"), mStereoInd); mStereoIndCheckBox->SetValidator(wxGenericValidator(&mStereoInd)); @@ -412,10 +332,6 @@ void EffectNormalize::PopulateOrExchange(ShuttleGui & S) S.EndMultiColumn(); } S.EndVerticalLay(); -#ifdef EXPERIMENTAL_R128_NORM - // To ensure that the UpdateUI on creation sets the prompts correctly. - mUseLoudness = !mGUIUseLoudness; -#endif mCreating = false; } @@ -451,51 +367,27 @@ bool EffectNormalize::AnalyseTrack(const WaveTrack * track, const wxString &msg, if(mGain) { -#ifdef EXPERIMENTAL_R128_NORM - if(mUseLoudness) - { - CalcEBUR128HPF(track->GetRate()); - CalcEBUR128HSF(track->GetRate()); - if(mDC) - { - result = AnalyseTrackData(track, msg, progress, ANALYSE_LOUDNESS_DC, offset); - } - else - { - result = AnalyseTrackData(track, msg, progress, ANALYSE_LOUDNESS, offset); - offset = 0.0; - } - - // EBU R128: z_i = mean square without root - extent = mSqSum / mCount.as_double(); + // Since we need complete summary data, we need to block until the OD tasks are done for this track + // This is needed for track->GetMinMax + // TODO: should we restrict the flags to just the relevant block files (for selections) + while (ProjectFileManager::GetODFlags( *track )) { + // update the gui + if (ProgressResult::Cancelled == mProgress->Update( + 0, _("Waiting for waveform to finish computing...")) ) + return false; + wxMilliSleep(100); } - else + + // set mMin, mMax. No progress bar here as it's fast. + auto pair = track->GetMinMax(mCurT0, mCurT1); // may throw + min = pair.first, max = pair.second; + + if(mDC) { -#endif - // Since we need complete summary data, we need to block until the OD tasks are done for this track - // This is needed for track->GetMinMax - // TODO: should we restrict the flags to just the relevant block files (for selections) - while (ProjectFileManager::GetODFlags( *track )) { - // update the gui - if (ProgressResult::Cancelled == mProgress->Update( - 0, _("Waiting for waveform to finish computing...")) ) - return false; - wxMilliSleep(100); - } - - // set mMin, mMax. No progress bar here as it's fast. - auto pair = track->GetMinMax(mCurT0, mCurT1); // may throw - min = pair.first, max = pair.second; - - if(mDC) - { - result = AnalyseTrackData(track, msg, progress, ANALYSE_DC, offset); - min += offset; - max += offset; - } -#ifdef EXPERIMENTAL_R128_NORM + result = AnalyseTrackData(track, msg, progress, ANALYSE_DC, offset); + min += offset; + max += offset; } -#endif } else if(mDC) { @@ -510,10 +402,7 @@ bool EffectNormalize::AnalyseTrack(const WaveTrack * track, const wxString &msg, min = -1.0, max = 1.0; // sensible defaults? offset = 0.0; } -#ifdef EXPERIMENTAL_R128_NORM - if(!mUseLoudness) -#endif - extent = fmax(fabs(min), fabs(max)); + extent = fmax(fabs(min), fabs(max)); return result; } @@ -540,9 +429,6 @@ bool EffectNormalize::AnalyseTrackData(const WaveTrack * track, const wxString & mSum = 0.0; // dc offset inits mCount = 0; -#ifdef EXPERIMENTAL_R128_NORM - mSqSum = 0.0; // rms init -#endif sampleCount blockSamples; sampleCount totalSamples = 0; @@ -565,12 +451,6 @@ bool EffectNormalize::AnalyseTrackData(const WaveTrack * track, const wxString & //Process the buffer. if(op == ANALYSE_DC) AnalyseDataDC(buffer.get(), block); -#ifdef EXPERIMENTAL_R128_NORM - else if(op == ANALYSE_LOUDNESS) - AnalyseDataLoudness(buffer.get(), block); - else if(op == ANALYSE_LOUDNESS_DC) - AnalyseDataLoudnessDC(buffer.get(), block); -#endif //Increment s one blockfull of samples s += block; @@ -658,40 +538,6 @@ void EffectNormalize::AnalyseDataDC(float *buffer, size_t len) mCount += len; } -#ifdef EXPERIMENTAL_R128_NORM -/// @see AnalyseDataLoudnessDC -void EffectNormalize::AnalyseDataLoudness(float *buffer, size_t len) -{ - float value; - for(decltype(len) i = 0; i < len; i++) - { - value = mR128HSF.ProcessOne(buffer[i]); - value = mR128HPF.ProcessOne(value); - mSqSum += ((double)value) * ((double)value); - } - mCount += len; -} - -/// Calculates sample sum (for DC) and EBU R128 weighted square sum -/// (for loudness). This function has variants which only calculate -/// sum or square sum for performance improvements if only one of those -/// values is required. -/// @see AnalyseDataLoudness -/// @see AnalyseDataDC -void EffectNormalize::AnalyseDataLoudnessDC(float *buffer, size_t len) -{ - float value; - for(decltype(len) i = 0; i < len; i++) - { - mSum += (double)buffer[i]; - value = mR128HSF.ProcessOne(buffer[i]); - value = mR128HPF.ProcessOne(value); - mSqSum += ((double)value) * ((double)value); - } - mCount += len; -} -#endif - void EffectNormalize::ProcessData(float *buffer, size_t len, float offset) { for(decltype(len) i = 0; i < len; i++) { @@ -700,56 +546,6 @@ void EffectNormalize::ProcessData(float *buffer, size_t len, float offset) } } -#ifdef EXPERIMENTAL_R128_NORM -// EBU R128 parameter sampling rate adaption after -// Mansbridge, Stuart, Saoirse Finn, and Joshua D. Reiss. -// "Implementation and Evaluation of Autonomous Multi-track Fader Control." -// Paper presented at the 132nd Audio Engineering Society Convention, -// Budapest, Hungary, 2012." -void EffectNormalize::CalcEBUR128HPF(float fs) -{ - double f0 = 38.13547087602444; - double Q = 0.5003270373238773; - double K = tan(M_PI * f0 / fs); - - mR128HPF.Reset(); - - mR128HPF.fNumerCoeffs[Biquad::B0] = 1.0; - mR128HPF.fNumerCoeffs[Biquad::B1] = -2.0; - mR128HPF.fNumerCoeffs[Biquad::B2] = 1.0; - - mR128HPF.fDenomCoeffs[Biquad::A1] = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K); - mR128HPF.fDenomCoeffs[Biquad::A2] = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K); -} - -// EBU R128 parameter sampling rate adaption after -// Mansbridge, Stuart, Saoirse Finn, and Joshua D. Reiss. -// "Implementation and Evaluation of Autonomous Multi-track Fader Control." -// Paper presented at the 132nd Audio Engineering Society Convention, -// Budapest, Hungary, 2012." -void EffectNormalize::CalcEBUR128HSF(float fs) -{ - double db = 3.999843853973347; - double f0 = 1681.974450955533; - double Q = 0.7071752369554196; - double K = tan(M_PI * f0 / fs); - - double Vh = pow(10.0, db / 20.0); - double Vb = pow(Vh, 0.4996667741545416); - - double a0 = 1.0 + K / Q + K * K; - - mR128HSF.Reset(); - - mR128HSF.fNumerCoeffs[Biquad::B0] = (Vh + Vb * K / Q + K * K) / a0; - mR128HSF.fNumerCoeffs[Biquad::B1] = 2.0 * (K * K - Vh) / a0; - mR128HSF.fNumerCoeffs[Biquad::B2] = (Vh - Vb * K / Q + K * K) / a0; - - mR128HSF.fDenomCoeffs[Biquad::A1] = 2.0 * (K * K - 1.0) / a0; - mR128HSF.fDenomCoeffs[Biquad::A2] = (1.0 - K / Q + K * K) / a0; -} -#endif - void EffectNormalize::OnUpdateUI(wxCommandEvent & WXUNUSED(evt)) { UpdateUI(); @@ -766,44 +562,10 @@ void EffectNormalize::UpdateUI() } mWarning->SetLabel(wxT("")); -#ifdef EXPERIMENTAL_R128_NORM - // Changing the prompts causes an unwanted UpdateUI event. - // This 'guard' stops that becoming an infinite recursion. - if (mUseLoudness != mGUIUseLoudness) - { - mUseLoudness = mGUIUseLoudness; - if (mUseLoudness) - { - FloatingPointValidator vldLevel(2, &mLUFSLevel, NumValidatorStyle::ONE_TRAILING_ZERO); - vldLevel.SetRange(MIN_LUFSLevel, MAX_LUFSLevel); - mLevelTextCtrl->SetValidator(vldLevel); - /* i18n-hint: LUFS is a particular method for measuring loudnesss */ - mLevelTextCtrl->SetName(_("Loudness LUFS")); - mLevelTextCtrl->SetValue(wxString::FromDouble(mLUFSLevel)); - /* i18n-hint: LUFS is a particular method for measuring loudnesss */ - mLeveldB->SetLabel(_("LUFS")); - mGainCheckBox->SetLabelText(_("Normalize loudness to")); - } - else - { - FloatingPointValidator vldLevel(2, &mPeakLevel, NumValidatorStyle::ONE_TRAILING_ZERO); - vldLevel.SetRange(MIN_PeakLevel, MAX_PeakLevel); - mLevelTextCtrl->SetValidator(vldLevel); - mLevelTextCtrl->SetName(_("Peak amplitude dB")); - mLevelTextCtrl->SetValue(wxString::FromDouble(mPeakLevel)); - mLeveldB->SetLabel(_("dB")); - mGainCheckBox->SetLabelText(_("Normalize peak amplitude to")); - } - } -#endif - // Disallow level stuff if not normalizing mLevelTextCtrl->Enable(mGain); mLeveldB->Enable(mGain); mStereoIndCheckBox->Enable(mGain); -#ifdef EXPERIMENTAL_R128_NORM - mUseLoudnessCheckBox->Enable(mGain); -#endif // Disallow OK/Preview if doing nothing EnableApply(mGain || mDC); diff --git a/src/effects/Normalize.h b/src/effects/Normalize.h index 2e334f9b9..b3a176460 100644 --- a/src/effects/Normalize.h +++ b/src/effects/Normalize.h @@ -6,7 +6,6 @@ Dominic Mazzoni Vaughan Johnson (Preview) - Max Maisel (Loudness) **********************************************************************/ @@ -71,17 +70,8 @@ private: bool AnalyseTrackData(const WaveTrack * track, const wxString &msg, double &progress, AnalyseOperation op, float &offset); void AnalyseDataDC(float *buffer, size_t len); -#ifdef EXPERIMENTAL_R128_NORM - void AnalyseDataLoudness(float *buffer, size_t len); - void AnalyseDataLoudnessDC(float *buffer, size_t len); -#endif void ProcessData(float *buffer, size_t len, float offset); -#ifdef EXPERIMENTAL_R128_NORM - void CalcEBUR128HPF(float fs); - void CalcEBUR128HSF(float fs); -#endif - void OnUpdateUI(wxCommandEvent & evt); void UpdateUI(); @@ -90,19 +80,11 @@ private: bool mGain; bool mDC; bool mStereoInd; -#ifdef EXPERIMENTAL_R128_NORM - double mLUFSLevel; - bool mUseLoudness; - bool mGUIUseLoudness; -#endif double mCurT0; double mCurT1; float mMult; double mSum; -#ifdef EXPERIMENTAL_R128_NORM - double mSqSum; -#endif sampleCount mCount; wxCheckBox *mGainCheckBox; @@ -111,12 +93,6 @@ private: wxStaticText *mLeveldB; wxStaticText *mWarning; wxCheckBox *mStereoIndCheckBox; -#ifdef EXPERIMENTAL_R128_NORM - wxCheckBox *mUseLoudnessCheckBox; - - Biquad mR128HSF; - Biquad mR128HPF; -#endif bool mCreating;