Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "limiter.h"
23 :
24 : #include "audiomathutils.h"
25 :
26 : using namespace muse::audio;
27 : using namespace muse::audio::dsp;
28 :
29 : static constexpr volume_db_t THRESHOLD = volume_dbfs_t::make(0.f);
30 :
31 0 : Limiter::Limiter(const unsigned int sampleRate)
32 0 : : m_filterConfig(sampleRate, 1.f, THRESHOLD)
33 : {
34 0 : }
35 :
36 0 : bool Limiter::isActive() const
37 : {
38 0 : return m_isActive;
39 : }
40 :
41 0 : void Limiter::setIsActive(const bool active)
42 : {
43 0 : m_isActive = active;
44 0 : }
45 :
46 0 : volume_db_t Limiter::gainSmoothing(const float newGainReduction) const
47 : {
48 0 : float coefficient = 0.f;
49 :
50 0 : if (newGainReduction <= m_previousGainReduction) {
51 0 : coefficient = m_filterConfig.attackTimeCoefficient();
52 : } else {
53 0 : coefficient = m_filterConfig.releaseTimeCoefficient();
54 : }
55 :
56 0 : return (coefficient * m_previousGainReduction) + ((1 - coefficient) * newGainReduction);
57 : }
58 :
59 0 : volume_db_t Limiter::computeGain(const volume_db_t& logarithmSample) const
60 : {
61 0 : if (logarithmSample < m_filterConfig.softThresholdLower()) {
62 0 : return logarithmSample;
63 : }
64 :
65 0 : if (logarithmSample >= m_filterConfig.softThresholdLower() && logarithmSample <= m_filterConfig.softThresholdUpper()) {
66 : return logarithmSample
67 0 : - (std::pow((logarithmSample - m_filterConfig.softThresholdUpper()), 2)
68 0 : / (2 * m_filterConfig.kneeWidth()));
69 : }
70 :
71 0 : return m_filterConfig.logarithmicThreshold();
72 : }
73 :
74 0 : void Limiter::process(const float& linearRms, float* buffer, const audioch_t& audioChannelsCount,
75 : const samples_t samplesPerChannel)
76 : {
77 0 : volume_db_t rmsDb = muse::linear_to_db(linearRms);
78 :
79 0 : if (rmsDb <= m_filterConfig.minimumOperableLevel()) {
80 0 : return;
81 : }
82 :
83 : // gain computing
84 0 : float computedGain = computeGain(rmsDb) - rmsDb;
85 :
86 : // gain smoothing
87 0 : float smoothedGain = gainSmoothing(computedGain);
88 0 : m_previousGainReduction = smoothedGain;
89 :
90 : // gain make-up
91 0 : float makeUpGain = smoothedGain + m_filterConfig.makeUpGain();
92 :
93 : // total linear gain
94 0 : float totalLinearGain = muse::db_to_linear(makeUpGain);
95 :
96 : // apply linear gain
97 0 : for (audioch_t audioChNum = 0; audioChNum < audioChannelsCount; ++audioChNum) {
98 0 : multiplySamples(buffer, audioChannelsCount, audioChNum, samplesPerChannel, totalLinearGain);
99 : }
100 : }
|