From a4c91f8ba06ed1ab13340d906fee6a65bd46fbbe Mon Sep 17 00:00:00 2001 From: superpaik <68785450+superpaik@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:52:41 +0100 Subject: [PATCH] Recursively unmute channels when soloing in the mixer (#6746) * unmute related FX channels When soled one FX channel, unmute send and receive channels, to allow complex FX channel routing (BUS, SENDs, etc.) * Comment change * SEND channels Activate also SEND channels recursively * Remove unnecessary whitespace * Encapsulate mixer channel index Make the mixer channel index `m_channelIndex` private and add getters and setters. Also add a method to determine if the channel is the master channel. Move `m_channelIndex` to the end of the initialization list of the `MixerChannel` constructor because it is now the last member in the header. Adjust all clients to make use of the new methods. * Replace const int& getIndex() with int index() const * Format changes --------- Co-authored-by: Michael Gregorius Co-authored-by: Sotonye Atemie --- include/Mixer.h | 14 ++++-- src/core/Mixer.cpp | 65 ++++++++++++++++++++++---- src/gui/tracks/InstrumentTrackView.cpp | 4 +- src/gui/tracks/SampleTrackView.cpp | 4 +- 4 files changed, 70 insertions(+), 17 deletions(-) diff --git a/include/Mixer.h b/include/Mixer.h index d74f9c11c..6e3c86565 100644 --- a/include/Mixer.h +++ b/include/Mixer.h @@ -63,7 +63,6 @@ class MixerChannel : public ThreadableJob FloatModel m_volumeModel; QString m_name; QMutex m_lock; - int m_channelIndex; // what channel index are we bool m_queued; // are we queued up for rendering yet? bool m_muted; // are we muted? updated per period so we don't have to call m_muteModel.value() twice @@ -73,8 +72,15 @@ class MixerChannel : public ThreadableJob // pointers to other channels that send to this one MixerRouteVector m_receives; + int index() const { return m_channelIndex; } + void setIndex(int index) { m_channelIndex = index; } + + bool isMaster() { return m_channelIndex == 0; } + bool requiresProcessing() const override { return true; } void unmuteForSolo(); + void unmuteSenderForSolo(); + void unmuteReceiverForSolo(); auto color() const -> const std::optional& { return m_color; } void setColor(const std::optional& color) { m_color = color; } @@ -85,7 +91,7 @@ class MixerChannel : public ThreadableJob private: void doProcessing() override; - + int m_channelIndex; std::optional m_color; }; @@ -98,12 +104,12 @@ public: mix_ch_t senderIndex() const { - return m_from->m_channelIndex; + return m_from->index(); } mix_ch_t receiverIndex() const { - return m_to->m_channelIndex; + return m_to->index(); } FloatModel * amount() diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 7e3fc1f60..0add6008d 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -44,7 +44,7 @@ MixerRoute::MixerRoute( MixerChannel * from, MixerChannel * to, float amount ) : m_from( from ), m_to( to ), m_amount(amount, 0, 1, 0.001f, nullptr, - tr("Amount to send from channel %1 to channel %2").arg(m_from->m_channelIndex).arg(m_to->m_channelIndex)) + tr("Amount to send from channel %1 to channel %2").arg(m_from->index()).arg(m_to->index())) { //qDebug( "created: %d to %d", m_from->m_channelIndex, m_to->m_channelIndex ); // create send amount model @@ -54,7 +54,7 @@ MixerRoute::MixerRoute( MixerChannel * from, MixerChannel * to, float amount ) : void MixerRoute::updateName() { m_amount.setDisplayName( - tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex ).arg( m_to->m_channelIndex ) ); + tr("Amount to send from channel %1 to channel %2").arg(m_from->index()).arg(m_to->index())); } @@ -70,9 +70,9 @@ MixerChannel::MixerChannel( int idx, Model * _parent ) : m_volumeModel(1.f, 0.f, 2.f, 0.001f, _parent), m_name(), m_lock(), - m_channelIndex( idx ), m_queued( false ), - m_dependenciesMet(0) + m_dependenciesMet(0), + m_channelIndex(idx) { zeroSampleFrames(m_buffer, Engine::audioEngine()->framesPerPeriod()); } @@ -109,8 +109,55 @@ void MixerChannel::incrementDeps() void MixerChannel::unmuteForSolo() { - //TODO: Recursively activate every channel, this channel sends to m_muteModel.setValue(false); + + // if channel is not master, unmute also every channel it sends to/receives from + if (!isMaster()) + { + for (const MixerRoute* sendsRoute : m_sends) + { + sendsRoute->receiver()->unmuteSenderForSolo(); + } + + for (const MixerRoute* receiverRoute : m_receives) + { + receiverRoute->sender()->unmuteReceiverForSolo(); + } + } +} + +void MixerChannel::unmuteSenderForSolo() +{ + m_muteModel.setValue(false); + + // if channel is not master, unmute every channel it sends to + if (!isMaster()) + { + for (const MixerRoute* sendsRoute : m_sends) + { + sendsRoute->receiver()->unmuteSenderForSolo(); + } + } +} + + +void MixerChannel::unmuteReceiverForSolo() +{ + m_muteModel.setValue(false); + + // if channel is not master, unmute every channel it receives from, and of those, unmute the channels they send to + if (!isMaster()) + { + for (const MixerRoute* receiverRoute : m_receives) + { + receiverRoute->sender()->unmuteReceiverForSolo(); + } + + for (const MixerRoute* sendsRoute : m_sends) + { + sendsRoute->receiver()->unmuteSenderForSolo(); + } + } } @@ -275,7 +322,7 @@ void Mixer::toggledSolo() } else { activateSolo(); } - // unmute the soloed chan and every channel it sends to + // unmute the soloed chan and every channel it sends to/receives from m_mixerChannels[soloedChan]->unmuteForSolo(); } else { deactivateSolo(); @@ -360,7 +407,7 @@ void Mixer::deleteChannel( int index ) validateChannelName( i, i + 1 ); // set correct channel index - m_mixerChannels[i]->m_channelIndex = i; + m_mixerChannels[i]->setIndex(i); // now check all routes and update names of the send models for( MixerRoute * r : m_mixerChannels[i]->m_sends ) @@ -433,8 +480,8 @@ void Mixer::moveChannelLeft( int index ) qSwap(m_mixerChannels[index], m_mixerChannels[index - 1]); // Update m_channelIndex of both channels - m_mixerChannels[index]->m_channelIndex = index; - m_mixerChannels[index - 1]->m_channelIndex = index -1; + m_mixerChannels[index]->setIndex(index); + m_mixerChannels[index - 1]->setIndex(index - 1); } diff --git a/src/gui/tracks/InstrumentTrackView.cpp b/src/gui/tracks/InstrumentTrackView.cpp index 1d9991c31..b8ca43bcd 100644 --- a/src/gui/tracks/InstrumentTrackView.cpp +++ b/src/gui/tracks/InstrumentTrackView.cpp @@ -385,8 +385,8 @@ QMenu * InstrumentTrackView::createMixerMenu(QString title, QString newMixerLabe if ( currentChannel != mixerChannel ) { - auto index = currentChannel->m_channelIndex; - QString label = tr( "%1: %2" ).arg( currentChannel->m_channelIndex ).arg( currentChannel->m_name ); + auto index = currentChannel->index(); + QString label = tr( "%1: %2" ).arg(index).arg(currentChannel->m_name); mixerMenu->addAction(label, [this, index](){ assignMixerLine(index); }); diff --git a/src/gui/tracks/SampleTrackView.cpp b/src/gui/tracks/SampleTrackView.cpp index 8475f7fa9..064cc5206 100644 --- a/src/gui/tracks/SampleTrackView.cpp +++ b/src/gui/tracks/SampleTrackView.cpp @@ -155,8 +155,8 @@ QMenu * SampleTrackView::createMixerMenu(QString title, QString newMixerLabel) if (currentChannel != mixerChannel) { - const auto index = currentChannel->m_channelIndex; - QString label = tr("%1: %2").arg(currentChannel->m_channelIndex).arg(currentChannel->m_name); + const auto index = currentChannel->index(); + QString label = tr("%1: %2").arg(index).arg(currentChannel->m_name); mixerMenu->addAction(label, [this, index](){ assignMixerLine(index); });