Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/app/configs/data/shortcuts.xml
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,16 @@
<key>notation-select-all</key>
<seq>Ctrl+A</seq>
</SC>
<SC>
<key>unmute-all</key>
<seq>Ctrl+Shift+U</seq>
<autorepeat>0</autorepeat>
</SC>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<SC>
<key>unsolo-all</key>
<seq>Ctrl+Shift+L</seq>
<autorepeat>0</autorepeat>
</SC>
<SC>
<key>system-break</key>
<seq>Return</seq>
Expand Down
10 changes: 10 additions & 0 deletions src/app/configs/data/shortcuts_azerty.xml
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,16 @@
<key>notation-select-all</key>
<seq>Ctrl+A</seq>
</SC>
<SC>
<key>unmute-all</key>
<seq>Ctrl+Shift+U</seq>
<autorepeat>0</autorepeat>
</SC>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<SC>
<key>unsolo-all</key>
<seq>Ctrl+Shift+L</seq>
<autorepeat>0</autorepeat>
</SC>
<SC>
<key>system-break</key>
<seq>Return</seq>
Expand Down
10 changes: 10 additions & 0 deletions src/app/configs/data/shortcuts_mac.xml
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,16 @@
<key>notation-select-all</key>
<seq>Ctrl+A</seq>
</SC>
<SC>
<key>unmute-all</key>
<seq>Ctrl+Shift+U</seq>
<autorepeat>0</autorepeat>
</SC>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<SC>
<key>unsolo-all</key>
<seq>Ctrl+Shift+L</seq>
<autorepeat>0</autorepeat>
</SC>
<SC>
<key>system-break</key>
<seq>Return</seq>
Expand Down
2 changes: 2 additions & 0 deletions src/playback/internal/playbackconfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static const Settings::Key MIXER_VOLUME_SECTION_VISIBLE_KEY(moduleName, "playbac
static const Settings::Key MIXER_FADER_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/faderSectionVisible");
static const Settings::Key MIXER_MUTE_AND_SOLO_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/muteAndSoloSectionVisible");
static const Settings::Key MIXER_TITLE_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/titleSectionVisible");
static const Settings::Key MIXER_UNMUTE_AND_UNSOLO_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/unMuteAndUnSoloSectionVisible");

static const Settings::Key MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_SOUND_WARNING(moduleName,
"playback/mixer/needToShowAboutResetSoundFlagsWhwnChangeSoundWarning");
Expand Down Expand Up @@ -78,6 +79,7 @@ static Settings::Key mixerSectionVisibleKey(MixerSectionType sectionType)
case MixerSectionType::Fader: return MIXER_FADER_SECTION_VISIBLE_KEY;
case MixerSectionType::MuteAndSolo: return MIXER_MUTE_AND_SOLO_SECTION_VISIBLE_KEY;
case MixerSectionType::Title: return MIXER_TITLE_SECTION_VISIBLE_KEY;
case MixerSectionType::UnMuteAndUnSolo: return MIXER_UNMUTE_AND_UNSOLO_SECTION_VISIBLE_KEY;
case MixerSectionType::Unknown: break;
}

Expand Down
39 changes: 39 additions & 0 deletions src/playback/internal/playbackcontroller.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ static const ActionCode REPEAT_CODE("repeat");
static const ActionCode PLAY_CHORD_SYMBOLS_CODE("play-chord-symbols");
static const ActionCode PLAYBACK_SETUP("playback-setup");
static const ActionCode TOGGLE_HEAR_PLAYBACK_WHEN_EDITING_CODE("toggle-hear-playback-when-editing");
static const ActionCode UNMUTE_ALL_CODE("unmute-all");
static const ActionCode UNSOLO_ALL_CODE("unsolo-all");

static AudioOutputParams makeReverbOutputParams()
{
Expand Down Expand Up @@ -127,6 +129,8 @@ void PlaybackController::init()
dispatcher()->reg(this, PLAYBACK_SETUP, this, &PlaybackController::openPlaybackSetupDialog);
dispatcher()->reg(this, TOGGLE_HEAR_PLAYBACK_WHEN_EDITING_CODE, this, &PlaybackController::toggleHearPlaybackWhenEditing);
dispatcher()->reg(this, "playback-reload-cache", this, &PlaybackController::reloadPlaybackCache);
dispatcher()->reg(this, UNMUTE_ALL_CODE, this, &PlaybackController::unmuteAll);
dispatcher()->reg(this, UNSOLO_ALL_CODE, this, &PlaybackController::unsoloAll);

m_onlineSoundsController->regActions();

Expand Down Expand Up @@ -956,6 +960,41 @@ void PlaybackController::reloadPlaybackCache()
}
}

void PlaybackController::unmuteAll()
{
InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();

for (const InstrumentTrackId& instrumentTrackId : existingTrackIdSet) {
if (instrumentTrackId == notationPlayback()->metronomeTrackId()) {
continue;
}

INotationSoloMuteState::SoloMuteState newState = m_notation->soloMuteState()->trackSoloMuteState(instrumentTrackId);
if (newState.mute == true) {
newState.mute = false;

setTrackSoloMuteState(instrumentTrackId, newState);
}
}

updateSoloMuteStates();
}
Comment on lines +963 to +981

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Code style issues in unmuteAll().

Several style inconsistencies:

  • Line 972: Variable new_state uses snake_case instead of camelCase (codebase convention)
  • Line 973: Redundant comparison if(new_state.mute == true) should be if (new_state.mute), plus missing space after if
  • Line 976: Missing space after comma in function call
♻️ Proposed fix for style issues
-        INotationSoloMuteState::SoloMuteState new_state = m_notation->soloMuteState()->trackSoloMuteState(instrumentTrackId);
-        if(new_state.mute == true) {
+        INotationSoloMuteState::SoloMuteState newState = m_notation->soloMuteState()->trackSoloMuteState(instrumentTrackId);
+        if (newState.mute) {
-            new_state.mute = false;
+            newState.mute = false;

-            setTrackSoloMuteState(instrumentTrackId,new_state);
+            setTrackSoloMuteState(instrumentTrackId, newState);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/internal/playbackcontroller.cpp` around lines 963 - 981, In
PlaybackController::unmuteAll rename the local variable new_state to newState
(use camelCase), change the conditional from if(new_state.mute == true) to if
(newState.mute) (add a space after the if and use the simpler boolean check),
and ensure proper spacing in the call
setTrackSoloMuteState(instrumentTrackId,new_state) by adding a space after the
comma and updating the identifier to setTrackSoloMuteState(instrumentTrackId,
newState); keep the rest of the logic (notationPlayback(), metronomeTrackId(),
INotationSoloMuteState::SoloMuteState, updateSoloMuteStates()) unchanged.


void PlaybackController::unsoloAll()
{
InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();

for (const InstrumentTrackId& instrumentTrackId : existingTrackIdSet) {
INotationSoloMuteState::SoloMuteState newState = trackSoloMuteState(instrumentTrackId);
if (newState.solo == true) {
newState.solo = false;
setTrackSoloMuteState(instrumentTrackId, newState);
}
}

updateSoloMuteStates();
}
Comment on lines +963 to +996

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing null safety checks in unmuteAll() and unsoloAll().

Both methods call notationPlayback()->existingTrackIdSet() (Lines 965, 985) and m_notation->soloMuteState() (Line 972) without checking if notationPlayback() or m_notation are non-null. Other methods in this file (e.g., updateCurrentTempo() at Line 178, seekElement() at Line 425) guard these calls with IF_ASSERT_FAILED or early returns.

🛡️ Proposed fix to add guards
 void PlaybackController::unmuteAll()
 {
+    IF_ASSERT_FAILED(notationPlayback() && m_notation) {
+        return;
+    }
+
     InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();
     ...
 }

 void PlaybackController::unsoloAll()
 {
+    IF_ASSERT_FAILED(notationPlayback()) {
+        return;
+    }
+
     InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();
     ...
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void PlaybackController::unmuteAll()
{
InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();
for (const InstrumentTrackId& instrumentTrackId : existingTrackIdSet) {
if (instrumentTrackId == notationPlayback()->metronomeTrackId()) {
continue;
}
INotationSoloMuteState::SoloMuteState new_state = m_notation->soloMuteState()->trackSoloMuteState(instrumentTrackId);
if(new_state.mute == true) {
new_state.mute = false;
setTrackSoloMuteState(instrumentTrackId,new_state);
}
}
updateSoloMuteStates();
}
void PlaybackController::unsoloAll()
{
InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();
for (const InstrumentTrackId& instrumentTrackId : existingTrackIdSet) {
INotationSoloMuteState::SoloMuteState new_state = trackSoloMuteState(instrumentTrackId);
if(new_state.solo == true) {
new_state.solo = false;
setTrackSoloMuteState(instrumentTrackId,new_state);
}
}
updateSoloMuteStates();
}
void PlaybackController::unmuteAll()
{
IF_ASSERT_FAILED(notationPlayback() && m_notation) {
return;
}
InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();
for (const InstrumentTrackId& instrumentTrackId : existingTrackIdSet) {
if (instrumentTrackId == notationPlayback()->metronomeTrackId()) {
continue;
}
INotationSoloMuteState::SoloMuteState new_state = m_notation->soloMuteState()->trackSoloMuteState(instrumentTrackId);
if(new_state.mute == true) {
new_state.mute = false;
setTrackSoloMuteState(instrumentTrackId,new_state);
}
}
updateSoloMuteStates();
}
void PlaybackController::unsoloAll()
{
IF_ASSERT_FAILED(notationPlayback()) {
return;
}
InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();
for (const InstrumentTrackId& instrumentTrackId : existingTrackIdSet) {
INotationSoloMuteState::SoloMuteState new_state = trackSoloMuteState(instrumentTrackId);
if(new_state.solo == true) {
new_state.solo = false;
setTrackSoloMuteState(instrumentTrackId,new_state);
}
}
updateSoloMuteStates();
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/internal/playbackcontroller.cpp` around lines 963 - 997, Add
null-safety guards at the start of both PlaybackController::unmuteAll() and
PlaybackController::unsoloAll(): verify notationPlayback() and m_notation (as
used) are non-null (or use IF_ASSERT_FAILED macros like other methods) and
return early if the checks fail; then proceed to call existingTrackIdSet(),
m_notation->soloMuteState(), trackSoloMuteState(), setTrackSoloMuteState(...)
and updateSoloMuteStates() as before. Ensure you reference the same null-check
pattern used in updateCurrentTempo() and seekElement() so behavior and
logging/assertion are consistent.

Comment on lines +983 to +996

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inconsistent metronome handling between unmuteAll() and unsoloAll().

unmuteAll() (Line 968-970) explicitly skips the metronome track, but unsoloAll() does not. While the QML UI behavior mirrors this (see MixerUnMuteAndUnSoloSection.qml:48-109), the inconsistency suggests a design gap: should solo operations on the metronome be allowed at all?

Additionally, the same code-style issues apply here: snake_case naming, redundant bool comparison, missing space after if (Line 990), and missing space after comma (Line 992).

♻️ Proposed fix for consistency and style

Add metronome skip for symmetry and apply style fixes:

 void PlaybackController::unsoloAll()
 {
     InstrumentTrackIdSet existingTrackIdSet = notationPlayback()->existingTrackIdSet();

     for (const InstrumentTrackId& instrumentTrackId : existingTrackIdSet) {
-
-        INotationSoloMuteState::SoloMuteState new_state = trackSoloMuteState(instrumentTrackId);
-        if(new_state.solo == true) {
-            new_state.solo = false;
-            setTrackSoloMuteState(instrumentTrackId,new_state);
+        if (instrumentTrackId == notationPlayback()->metronomeTrackId()) {
+            continue;
+        }
+
+        INotationSoloMuteState::SoloMuteState newState = trackSoloMuteState(instrumentTrackId);
+        if (newState.solo) {
+            newState.solo = false;
+            setTrackSoloMuteState(instrumentTrackId, newState);
         }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/internal/playbackcontroller.cpp` around lines 983 - 997, The
unsoloAll() implementation is inconsistent with unmuteAll(): it must skip the
metronome track like unmuteAll() does and also fix local style issues; update
PlaybackController::unsoloAll() to check and skip the metronome (use the same
check used in unmuteAll()), rename the local variable new_state to newState to
follow camelCase, remove the redundant "== true" so the condition is simply if
(newState.solo), and ensure spacing after keywords and commas (e.g., if
(newState.solo) and setTrackSoloMuteState(instrumentTrackId, newState)); keep
the call to updateSoloMuteStates() at the end.


void PlaybackController::openPlaybackSetupDialog()
{
interactive()->open("musescore://playback/soundprofilesdialog");
Expand Down
2 changes: 2 additions & 0 deletions src/playback/internal/playbackcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ class PlaybackController : public IPlaybackController, public muse::actions::Act
void setMidiUseWrittenPitch(bool useWrittenPitch);
void toggleLoopPlayback();
void toggleHearPlaybackWhenEditing();
void unmuteAll();
void unsoloAll();

void reloadPlaybackCache();

Expand Down
14 changes: 14 additions & 0 deletions src/playback/internal/playbackuiactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,19 @@ const UiActionList PlaybackUiActions::s_diagnosticActions = {
)
};

const UiActionList PlaybackUiActions::s_mixerActions = {
UiAction("unmute-all",
mu::context::UiCtxAny,
mu::context::CTX_ANY,
TranslatableString("action", "Unmute All Channels")
),
UiAction("unsolo-all",
mu::context::UiCtxAny,
mu::context::CTX_ANY,
TranslatableString("action", "Unsolo All Channels")
)
};

const UiActionList PlaybackUiActions::s_onlineSoundsActions = {
UiAction(CLEAR_ONLINE_SOUNDS_CACHE_CODE,
mu::context::UiCtxAny,
Expand Down Expand Up @@ -264,6 +277,7 @@ const UiActionList& PlaybackUiActions::actionsList() const
alist.insert(alist.end(), s_settingsActions.cbegin(), s_settingsActions.cend());
alist.insert(alist.end(), s_loopBoundaryActions.cbegin(), s_loopBoundaryActions.cend());
alist.insert(alist.end(), s_diagnosticActions.cbegin(), s_diagnosticActions.cend());
alist.insert(alist.end(), s_mixerActions.cbegin(), s_mixerActions.cend());
alist.insert(alist.end(), s_onlineSoundsActions.cbegin(), s_onlineSoundsActions.cend());
}
return alist;
Expand Down
1 change: 1 addition & 0 deletions src/playback/internal/playbackuiactions.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class PlaybackUiActions : public muse::ui::IUiActionsModule, public muse::async:
static const muse::ui::UiActionList s_loopBoundaryActions;
static const muse::ui::UiActionList s_diagnosticActions;
static const muse::ui::UiActionList s_onlineSoundsActions;
static const muse::ui::UiActionList s_mixerActions;

std::shared_ptr<PlaybackController> m_controller;
muse::async::Channel<muse::actions::ActionCodeList> m_actionEnabledChanged;
Expand Down
2 changes: 2 additions & 0 deletions src/playback/playbacktypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum class MixerSectionType {
Volume,
Fader,
MuteAndSolo,
UnMuteAndUnSolo,
Title
};

Expand All @@ -57,6 +58,7 @@ inline QList<MixerSectionType> allMixerSectionTypes()
MixerSectionType::Volume,
MixerSectionType::Fader,
MixerSectionType::MuteAndSolo,
MixerSectionType::UnMuteAndUnSolo,
MixerSectionType::Title
};

Expand Down
1 change: 1 addition & 0 deletions src/playback/qml/MuseScore/Playback/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ qt_add_qml_module(playback_qml
internal/SoundFlag/ParamsGridView.qml
internal/VolumePressureMeter.qml
internal/VolumeSlider.qml
internal/MixerUnMuteAndUnSoloSection.qml
MixerPanel.qml
NotationRegionsBeingProcessedView.qml
OnlineSoundsStatusView.qml
Expand Down
35 changes: 24 additions & 11 deletions src/playback/qml/MuseScore/Playback/MixerPanel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -305,21 +305,34 @@ ColumnLayout {
}
}

MixerMuteAndSoloSection {
id: muteAndSoloSection
Item {
width: contentColumn.width
height: muteAndSoloSection.height

visible: contextMenuModel.muteAndSoloSectionVisible
headerVisible: contextMenuModel.labelsSectionVisible
headerWidth: prv.headerWidth
channelItemWidth: prv.channelItemWidth
MixerMuteAndSoloSection {
id: muteAndSoloSection

model: mixerPanelModel
visible: contextMenuModel.muteAndSoloSectionVisible
headerVisible: contextMenuModel.labelsSectionVisible
headerWidth: prv.headerWidth
channelItemWidth: prv.channelItemWidth

navigationRowStart: 600
needReadChannelName: prv.isPanelActivated
model: mixerPanelModel
navigationRowStart: 600
needReadChannelName: prv.isPanelActivated

onNavigateControlIndexChanged: function(index) {
prv.setNavigateControlIndex(index)
onNavigateControlIndexChanged: function(index) {
prv.setNavigateControlIndex(index)
}
}

MixerUnMuteAndUnSoloSection {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
visible: contextMenuModel.unMuteAndUnSoloSectionVisible
headerVisible: contextMenuModel.labelsSectionVisible
headerWidth: prv.headerWidth
model: mixerPanelModel
}
Comment on lines +329 to 336

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing required navigation properties causes runtime error and breaks keyboard navigation.

The MixerUnMuteAndUnSoloSection component references root.channelItem.panel, root.navigationRowStart, root.accessibleName, and root.navigateControlIndexChanged in its button navigation setup (see src/playback/qml/MuseScore/Playback/internal/MixerUnMuteAndUnSoloSection.qml lines 40, 42, 44, 68, 70, 72), but none of these properties are set here. Accessing undefined root.channelItem.panel will cause a QML runtime error when keyboard navigation activates. Additionally, the missing onNavigateControlIndexChanged handler breaks navigation tracking, and the missing navigationRowStart breaks keyboard navigation sequencing.

Every other mixer section in this file (sound, fx, auxSends, balance, volume, fader, muteAndSolo, title) sets navigationRowStart and wires onNavigateControlIndexChanged.

🔧 Proposed fix to add missing navigation properties
 MixerUnMuteAndUnSoloSection {
     anchors.left: parent.left
     anchors.verticalCenter: parent.verticalCenter
     visible: contextMenuModel.unMuteAndUnSoloSectionVisible
     headerVisible: contextMenuModel.labelsSectionVisible
     headerWidth: prv.headerWidth
     model: mixerPanelModel
+    navigationRowStart: 650
+    needReadChannelName: prv.isPanelActivated
+
+    onNavigateControlIndexChanged: function(index) {
+        prv.setNavigateControlIndex(index)
+    }
 }

Note: navigationRowStart: 650 is suggested to place it between MixerMuteAndSoloSection (600) and MixerTitleSection (700). You may also need to verify that MixerUnMuteAndUnSoloSection.qml declares the required properties (navigationRowStart, needReadChannelName, signal navigateControlIndexChanged) if they are not already present.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
MixerUnMuteAndUnSoloSection {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
visible: contextMenuModel.unMuteAndUnSoloSectionVisible
headerVisible: contextMenuModel.labelsSectionVisible
headerWidth: prv.headerWidth
model: mixerPanelModel
}
MixerUnMuteAndUnSoloSection {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
visible: contextMenuModel.unMuteAndUnSoloSectionVisible
headerVisible: contextMenuModel.labelsSectionVisible
headerWidth: prv.headerWidth
model: mixerPanelModel
navigationRowStart: 650
needReadChannelName: prv.isPanelActivated
onNavigateControlIndexChanged: function(index) {
prv.setNavigateControlIndex(index)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/qml/MuseScore/Playback/MixerPanel.qml` around lines 329 - 336,
The MixerUnMuteAndUnSoloSection instance is missing required navigation
properties used internally (causing runtime errors); set the navigation props on
this instance: provide channelItem.panel by wiring channelItem.panel:
root.channelItem.panel, set navigationRowStart (e.g. navigationRowStart: 650 to
sit between the mute/solo and title sections), forward accessibleName:
accessibleName: root.accessibleName, and hook the navigation signal with
onNavigateControlIndexChanged: root.navigateControlIndexChanged; also add
needReadChannelName: true if the component expects it. Ensure
MixerUnMuteAndUnSoloSection.qml declares these properties/signals if not
already.

}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-Studio-CLA-applies
*
* MuseScore Studio
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore Limited
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

pragma ComponentBehavior: Bound

import QtQuick

import Muse.Ui
import Muse.UiComponents
import MuseScore.Playback

Item {
id: root

property var model: undefined
property int headerWidth: 98
property bool headerVisible: true
property alias unMuteButton: unMuteAllButton
property alias unSoloButton: unSoloAllButton

height: 28
width: headerWidth
visible: headerVisible

Row {
anchors.centerIn: parent
spacing: 6

FlatToggleButton {
id: unMuteAllButton

height: 20
width: 20

icon: IconCode.MUTE

enabled: parent.enabled
visible: parent.visible

navigation.name: "UnMuteAllButton"
navigation.panel: root.channelItem.panel
navigation.row: root.navigationRowStart
navigation.accessible.name: root.accessibleName + " " + qsTrc("playback", "Unmute All")
navigation.onActiveChanged: {
if (navigation.active) {
root.navigateControlIndexChanged({row: navigation.row, column: navigation.column})
}
}

onToggled: {
for (let i = 0; i < model.rowCount(); i++) {
let item = model.get(i);

if(item.channelItem.type === MixerChannelItem.Metronome){
continue
}

item.channelItem.muted = false
}
}
}

FlatToggleButton {
id: unSoloAllButton

height: 20
width: 20

icon: IconCode.SOLO

enabled: parent.enabled
visible: parent.visible

navigation.name: "UnSoloAllButton"
navigation.panel: root.channelItem.panel
navigation.row: root.navigationRowStart + 1
navigation.accessible.name: root.accessibleName + " " + qsTrc("playback", "Unsolo All")
navigation.onActiveChanged: {
if (navigation.active) {
root.navigateControlIndexChanged({row: navigation.row, column: navigation.column})
}
}

onToggled: {
for (let i = 0; i < model.rowCount(); i++) {
let item = model.get(i);
item.channelItem.solo = false
}
}
}
}
}
10 changes: 10 additions & 0 deletions src/playback/qml/MuseScore/Playback/mixerpanelcontextmenumodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static TranslatableString mixerSectionTitle(MixerSectionType type)
case MixerSectionType::Fader: return TranslatableString("playback", "Fader");
case MixerSectionType::MuteAndSolo: return TranslatableString("playback", "Mute and solo");
case MixerSectionType::Title: return TranslatableString("playback", "Name");
case MixerSectionType::UnMuteAndUnSolo: return TranslatableString("playback", "Unmute and Unsolo");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Inconsistent capitalization in section title.

The title "Unmute and Unsolo" capitalizes "Unsolo", but line 50 uses lowercase "solo" in "Mute and solo". For consistency, this should be "Unmute and unsolo".

✏️ Proposed fix
-    case MixerSectionType::UnMuteAndUnSolo: return TranslatableString("playback", "Unmute and Unsolo");
+    case MixerSectionType::UnMuteAndUnSolo: return TranslatableString("playback", "Unmute and unsolo");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case MixerSectionType::UnMuteAndUnSolo: return TranslatableString("playback", "Unmute and Unsolo");
case MixerSectionType::UnMuteAndUnSolo: return TranslatableString("playback", "Unmute and unsolo");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/qml/MuseScore/Playback/mixerpanelcontextmenumodel.cpp` at line
52, The string returned for MixerSectionType::UnMuteAndUnSolo uses inconsistent
capitalization ("Unmute and Unsolo"); update the TranslatableString in the
corresponding case in mixerpanelcontextmenumodel.cpp to use "Unmute and unsolo"
so it matches the lowercase "solo" used in the "Mute and solo" entry (change the
second word to lowercase "unsolo" in the TranslatableString call).

case MixerSectionType::Unknown: break;
}

Expand Down Expand Up @@ -121,6 +122,11 @@ bool MixerPanelContextMenuModel::titleSectionVisible() const
return isSectionVisible(MixerSectionType::Title);
}

bool MixerPanelContextMenuModel::unMuteAndUnSoloSectionVisible() const
{
return isSectionVisible(MixerSectionType::UnMuteAndUnSolo);
}

void MixerPanelContextMenuModel::load()
{
AbstractMenuModel::load();
Expand Down Expand Up @@ -149,6 +155,7 @@ void MixerPanelContextMenuModel::load()
buildSectionVisibleItem(MixerSectionType::Labels),
buildSectionVisibleItem(MixerSectionType::Sound),
buildSectionVisibleItem(MixerSectionType::AudioFX),
buildSectionVisibleItem(MixerSectionType::UnMuteAndUnSolo),
};

for (aux_channel_idx_t idx = 0; idx < AUX_CHANNEL_NUM; ++idx) {
Expand Down Expand Up @@ -318,6 +325,9 @@ void MixerPanelContextMenuModel::emitMixerSectionVisibilityChanged(MixerSectionT
case MixerSectionType::Title:
emit titleSectionVisibleChanged();
break;
case MixerSectionType::UnMuteAndUnSolo:
emit unMuteAndUnSoloSectionVisibleChanged();
break;
case MixerSectionType::Unknown:
break;
}
Expand Down
Loading
Loading