LCOV - code coverage report
Current view: top level - muse/framework/audio/engine/internal/nodes - fxchain.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 81 0
Test Date: 2026-11-05 04:07:02

            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 "fxchain.h"
      24              : #include "fxnode.h"
      25              : 
      26              : #include "log.h"
      27              : 
      28              : using namespace muse;
      29              : using namespace muse::audio;
      30              : using namespace muse::audio::engine;
      31              : 
      32            0 : void FxChain::setFxList(const std::vector<IFxProcessorPtr>& fxList)
      33              : {
      34            0 :     clear();
      35              : 
      36            0 :     for (auto it = fxList.rbegin(); it != fxList.rend(); ++it) {
      37            0 :         FxNodePtr node = std::make_shared<FxNode>(*it);
      38            0 :         doAdd(node);
      39              : 
      40            0 :         node->paramsChanged().onReceive(this, [this](const AudioFxParams& fxParams) {
      41            0 :             m_fxChainSpec.insert_or_assign(fxParams.chainOrder, fxParams);
      42            0 :             m_fxChainSpecChanged.send(m_fxChainSpec);
      43            0 :             updateShouldProcessDuringSilence();
      44            0 :         }, async::Asyncable::Mode::SetReplace);
      45            0 :     }
      46              : 
      47            0 :     rebuild();
      48            0 :     updateShouldProcessDuringSilence();
      49              : 
      50            0 :     if (!name().empty() && !m_nodes.empty()) {
      51            0 :         LOGD() << name() << ": " << m_nodes.front()->dump();
      52              :     }
      53            0 : }
      54              : 
      55            0 : void FxChain::setFxChainSpec(const AudioFxChain& fxChainSpec)
      56              : {
      57            0 :     if (m_fxChainSpec == fxChainSpec) {
      58            0 :         return;
      59              :     }
      60              : 
      61            0 :     auto findFxNode = [this](const std::pair<AudioFxChainOrder, AudioFxParams>& params) -> FxNodePtr {
      62            0 :         for (auto& node : m_nodes) {
      63            0 :             FxNodePtr fx = std::dynamic_pointer_cast<FxNode>(node);
      64            0 :             IF_ASSERT_FAILED(fx) {
      65            0 :                 continue;
      66              :             }
      67              : 
      68            0 :             if (fx->params().chainOrder != params.first) {
      69            0 :                 continue;
      70              :             }
      71              : 
      72            0 :             if (fx->params().resourceMeta == params.second.resourceMeta) {
      73            0 :                 return fx;
      74              :             }
      75            0 :         }
      76              : 
      77            0 :         return nullptr;
      78            0 :     };
      79              : 
      80            0 :     m_fxChainSpec = fxChainSpec;
      81            0 :     for (auto it = m_fxChainSpec.begin(); it != m_fxChainSpec.end();) {
      82            0 :         if (FxNodePtr fx = findFxNode(*it)) {
      83            0 :             fx->setBypassed(!it->second.active);
      84            0 :             ++it;
      85              :         } else {
      86            0 :             it = m_fxChainSpec.erase(it);
      87            0 :         }
      88              :     }
      89              : 
      90            0 :     m_fxChainSpecChanged.send(m_fxChainSpec);
      91            0 :     updateShouldProcessDuringSilence();
      92              : }
      93              : 
      94            0 : const AudioFxChain& FxChain::fxChainSpec() const
      95              : {
      96            0 :     return m_fxChainSpec;
      97              : }
      98              : 
      99            0 : async::Channel<AudioFxChain> FxChain::fxChainSpecChanged() const
     100              : {
     101            0 :     return m_fxChainSpecChanged;
     102              : }
     103              : 
     104            0 : void FxChain::setPlayheadPosition(PlayheadPositionPtr playheadPosition)
     105              : {
     106            0 :     for (auto& node : m_nodes) {
     107            0 :         FxNodePtr fx = std::dynamic_pointer_cast<FxNode>(node);
     108            0 :         IF_ASSERT_FAILED(fx) {
     109            0 :             continue;
     110              :         }
     111              : 
     112            0 :         fx->setPlayheadPosition(playheadPosition);
     113            0 :     }
     114            0 : }
     115              : 
     116            0 : void FxChain::rebuild()
     117              : {
     118            0 :     for (size_t i = 1; i < m_nodes.size(); ++i) {
     119            0 :         IAudioNodePtr& prev = m_nodes.at(i - 1);
     120            0 :         IAudioNodePtr& curr = m_nodes.at(i);
     121            0 :         curr->disconnectAll();
     122            0 :         curr->connect(prev); // prev->input = curr
     123              :     }
     124            0 : }
     125              : 
     126            0 : void FxChain::doSelfProcess(float* buffer, samples_t samplesPerChannel)
     127              : {
     128            0 :     if (!m_nodes.empty()) {
     129            0 :         m_nodes.front()->process(buffer, samplesPerChannel);
     130              :     }
     131            0 : }
     132              : 
     133            0 : void FxChain::updateShouldProcessDuringSilence()
     134              : {
     135            0 :     bool shouldProcessDuringSilence = false;
     136            0 :     for (const auto& node : m_nodes) {
     137            0 :         FxNodePtr fx = std::dynamic_pointer_cast<FxNode>(node);
     138            0 :         IF_ASSERT_FAILED(fx) {
     139            0 :             continue;
     140              :         }
     141              : 
     142            0 :         if (fx->shouldProcessDuringSilence()) {
     143            0 :             shouldProcessDuringSilence = true;
     144            0 :             break;
     145              :         }
     146            0 :     }
     147              : 
     148            0 :     if (m_shouldProcessDuringSilence != shouldProcessDuringSilence) {
     149            0 :         m_shouldProcessDuringSilence = shouldProcessDuringSilence;
     150            0 :         m_shouldProcessDuringSilenceChanged.send(shouldProcessDuringSilence);
     151              :     }
     152            0 : }
     153              : 
     154            0 : bool FxChain::shouldProcessDuringSilence() const
     155              : {
     156            0 :     return m_shouldProcessDuringSilence;
     157              : }
     158              : 
     159            0 : async::Channel<bool> FxChain::shouldProcessDuringSilenceChanged() const
     160              : {
     161            0 :     return m_shouldProcessDuringSilenceChanged;
     162              : }
        

Generated by: LCOV version 2.0-1