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) 2026 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 :
23 : #include "signalnode.h"
24 :
25 : using namespace muse::audio;
26 : using namespace muse::audio::engine;
27 :
28 : static constexpr volume_dbfs_t MINIMUM_OPERABLE_DBFS_LEVEL = volume_dbfs_t::make(-100.f);
29 : static constexpr volume_dbfs_t PRESSURE_MINIMAL_VALUABLE_DIFF = volume_dbfs_t::make(2.5f);
30 :
31 0 : bool SignalNode::isSilent() const
32 : {
33 0 : return m_isSilent;
34 : }
35 :
36 0 : AudioSignalChanges SignalNode::audioSignalChanges() const
37 : {
38 0 : return m_audioSignalChanges;
39 : }
40 :
41 0 : void SignalNode::onOutputSpecChanged(const OutputSpec& spec)
42 : {
43 0 : m_channelPeaks.resize(spec.audioChannelCount, 0.f);
44 0 : }
45 :
46 0 : void SignalNode::doSelfProcess(float* buffer, samples_t samplesPerChannel)
47 : {
48 0 : const audioch_t channelsCount = m_outputSpec.audioChannelCount;
49 :
50 0 : for (audioch_t ch = 0; ch < channelsCount; ++ch) {
51 0 : m_channelPeaks[ch] = 0.f;
52 : }
53 :
54 0 : for (size_t s = 0; s < samplesPerChannel; ++s) {
55 0 : const size_t frameOffset = s * channelsCount;
56 0 : for (size_t ch = 0; ch < channelsCount; ++ch) {
57 0 : const size_t idx = frameOffset + ch;
58 0 : const float a = std::fabs(buffer[idx]);
59 0 : if (a > m_channelPeaks[ch]) {
60 0 : m_channelPeaks[ch] = a;
61 : }
62 : }
63 : }
64 :
65 0 : m_isSilent = true;
66 0 : for (audioch_t ch = 0; ch < channelsCount; ++ch) {
67 0 : float peak = m_channelPeaks[ch];
68 0 : if (peak > 0.f) {
69 0 : m_isSilent = false;
70 : }
71 0 : updateSignalValue(ch, peak);
72 : }
73 :
74 0 : notifyAboutChanges();
75 0 : }
76 :
77 0 : void SignalNode::updateSignalValue(const audioch_t ch, const float newPeak)
78 : {
79 0 : volume_dbfs_t newPressure = (newPeak > 0.f) ? volume_dbfs_t(muse::linear_to_db(newPeak)) : MINIMUM_OPERABLE_DBFS_LEVEL;
80 0 : newPressure = std::max(newPressure, MINIMUM_OPERABLE_DBFS_LEVEL);
81 :
82 0 : AudioSignalVal& signalVal = m_signalValuesMap[ch];
83 :
84 0 : if (muse::is_equal(signalVal.pressure, newPressure)) {
85 0 : return;
86 : }
87 :
88 0 : if (std::abs(signalVal.pressure - newPressure) < PRESSURE_MINIMAL_VALUABLE_DIFF) {
89 0 : return;
90 : }
91 :
92 0 : signalVal.pressure = newPressure;
93 0 : m_shouldNotifyAboutChanges = true;
94 : }
95 :
96 0 : void SignalNode::notifyAboutChanges()
97 : {
98 0 : if (m_shouldNotifyAboutChanges) {
99 0 : m_audioSignalChanges.send(m_signalValuesMap);
100 0 : m_shouldNotifyAboutChanges = false;
101 : }
102 0 : }
|