diff --git a/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml b/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml index 1b5fd385cc424..9509b340ee699 100644 --- a/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml +++ b/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml @@ -70,6 +70,7 @@ PreferencesPage { playNotesWhenEditing: noteInputModel.playNotesWhenEditing playChordWhenEditing: noteInputModel.playChordWhenEditing playChordSymbolWhenEditing: noteInputModel.playChordSymbolWhenEditing + playNotesOnMutedTracksWhenEditing: noteInputModel.playNotesOnMutedTracksWhenEditing notePlayDurationMilliseconds: noteInputModel.notePlayDurationMilliseconds navigation.section: root.navigationSection @@ -87,6 +88,10 @@ PreferencesPage { noteInputModel.playChordSymbolWhenEditing = play } + onPlayNotesOnMutedTracksWhenEditingChangeRequested: function(play) { + noteInputModel.playNotesOnMutedTracksWhenEditing = play + } + onNotePlayDurationChangeRequested: function(duration) { noteInputModel.notePlayDurationMilliseconds = duration } diff --git a/src/appshell/qml/Preferences/internal/NoteInputPlaySection.qml b/src/appshell/qml/Preferences/internal/NoteInputPlaySection.qml index cde0efe2c98d9..4d856c9fd2761 100644 --- a/src/appshell/qml/Preferences/internal/NoteInputPlaySection.qml +++ b/src/appshell/qml/Preferences/internal/NoteInputPlaySection.qml @@ -30,11 +30,13 @@ BaseSection { property alias playNotesWhenEditing: playNotesBox.checked property alias playChordWhenEditing: playChordBox.checked property alias playChordSymbolWhenEditing: playChordSymbolBox.checked + property alias playNotesOnMutedTracksWhenEditing: playNotesOnMutedTracksBox.checked property alias notePlayDurationMilliseconds: notePlayDurationControl.currentValue signal playNotesWhenEditingChangeRequested(bool play) signal playChordWhenEditingChangeRequested(bool play) signal playChordSymbolWhenEditingChangeRequested(bool play) + signal playNotesOnMutedTracksWhenEditingChangeRequested(bool play) signal notePlayDurationChangeRequested(int duration) CheckBox { @@ -108,4 +110,20 @@ BaseSection { root.playChordSymbolWhenEditingChangeRequested(!checked) } } + CheckBox { + id: playNotesOnMutedTracksBox + width: parent.width + + text: qsTrc("appshell/preferences", "Play notes on muted tracks") + + enabled: root.playNotesWhenEditing + + navigation.name: "playNotesOnMutedTracksBox" + navigation.panel: root.navigation + navigation.row: 4 + + onClicked: { + root.playNotesOnMutedTracksWhenEditingChangeRequested(!checked) + } + } } diff --git a/src/appshell/view/preferences/noteinputpreferencesmodel.cpp b/src/appshell/view/preferences/noteinputpreferencesmodel.cpp index 3637bb07d9936..08205dfba7d37 100644 --- a/src/appshell/view/preferences/noteinputpreferencesmodel.cpp +++ b/src/appshell/view/preferences/noteinputpreferencesmodel.cpp @@ -71,6 +71,11 @@ bool NoteInputPreferencesModel::playChordSymbolWhenEditing() const return playbackConfiguration()->playHarmonyWhenEditing(); } +bool NoteInputPreferencesModel::playNotesOnMutedTracksWhenEditing() const +{ + return playbackConfiguration()->playNotesOnMutedTracksWhenEditing(); +} + bool NoteInputPreferencesModel::dynamicsApplyToAllVoices() const { return engravingConfiguration()->dynamicsApplyToAllVoices(); @@ -156,6 +161,16 @@ void NoteInputPreferencesModel::setPlayChordSymbolWhenEditing(bool value) emit playChordSymbolWhenEditingChanged(value); } +void NoteInputPreferencesModel::setPlayNotesOnMutedTracksWhenEditing(bool value) +{ + if (value == playNotesOnMutedTracksWhenEditing()) { + return; + } + + playbackConfiguration()->setPlayNotesOnMutedTracksWhenEditing(value); + emit playNotesOnMutedTracksWhenEditingChanged(value); +} + void NoteInputPreferencesModel::setDynamicsApplyToAllVoices(bool value) { if (value == dynamicsApplyToAllVoices()) { diff --git a/src/appshell/view/preferences/noteinputpreferencesmodel.h b/src/appshell/view/preferences/noteinputpreferencesmodel.h index 78c77ea6da1ee..647dcf556cb45 100644 --- a/src/appshell/view/preferences/noteinputpreferencesmodel.h +++ b/src/appshell/view/preferences/noteinputpreferencesmodel.h @@ -50,6 +50,8 @@ class NoteInputPreferencesModel : public QObject, public muse::Injectable Q_PROPERTY(bool playChordWhenEditing READ playChordWhenEditing WRITE setPlayChordWhenEditing NOTIFY playChordWhenEditingChanged) Q_PROPERTY( bool playChordSymbolWhenEditing READ playChordSymbolWhenEditing WRITE setPlayChordSymbolWhenEditing NOTIFY playChordSymbolWhenEditingChanged) + Q_PROPERTY( + bool playNotesOnMutedTracksWhenEditing READ playNotesOnMutedTracksWhenEditing WRITE setPlayNotesOnMutedTracksWhenEditing NOTIFY playNotesOnMutedTracksWhenEditingChanged) Q_PROPERTY( bool dynamicsApplyToAllVoices READ dynamicsApplyToAllVoices WRITE setDynamicsApplyToAllVoices NOTIFY dynamicsApplyToAllVoicesChanged FINAL) @@ -70,6 +72,7 @@ class NoteInputPreferencesModel : public QObject, public muse::Injectable int notePlayDurationMilliseconds() const; bool playChordWhenEditing() const; bool playChordSymbolWhenEditing() const; + bool playNotesOnMutedTracksWhenEditing() const; bool dynamicsApplyToAllVoices() const; @@ -82,6 +85,7 @@ public slots: void setNotePlayDurationMilliseconds(int duration); void setPlayChordWhenEditing(bool value); void setPlayChordSymbolWhenEditing(bool value); + void setPlayNotesOnMutedTracksWhenEditing(bool value); void setDynamicsApplyToAllVoices(bool value); signals: @@ -93,6 +97,7 @@ public slots: void notePlayDurationMillisecondsChanged(int duration); void playChordWhenEditingChanged(bool value); void playChordSymbolWhenEditingChanged(bool value); + void playNotesOnMutedTracksWhenEditingChanged(bool value); void dynamicsApplyToAllVoicesChanged(bool value); }; } diff --git a/src/framework/audio/internal/worker/mixerchannel.cpp b/src/framework/audio/internal/worker/mixerchannel.cpp index 19521a261de88..e1445327e1abe 100644 --- a/src/framework/audio/internal/worker/mixerchannel.cpp +++ b/src/framework/audio/internal/worker/mixerchannel.cpp @@ -65,7 +65,14 @@ IAudioSourcePtr MixerChannel::source() const bool MixerChannel::muted() const { - return m_params.muted; + // We are not muted if we are editing notes and this setting is true + if (playNotesOnMutedTracksWhenEditing()) { + return false; + } + // Otherwise normal behaviour + else { + return m_params.muted; + } } async::Notification MixerChannel::mutedChanged() const @@ -192,11 +199,11 @@ samples_t MixerChannel::process(float* buffer, samples_t samplesPerChannel) samples_t processedSamplesCount = samplesPerChannel; - if (m_audioSource && !m_params.muted) { + if (m_audioSource && (!m_params.muted || playNotesOnMutedTracksWhenEditing())) { processedSamplesCount = m_audioSource->process(buffer, samplesPerChannel); } - if (processedSamplesCount == 0 || m_params.muted) { + if (processedSamplesCount == 0 || (m_params.muted && !playNotesOnMutedTracksWhenEditing())) { std::fill(buffer, buffer + samplesPerChannel * audioChannelsCount(), 0.f); notifyNoAudioSignal(); @@ -261,3 +268,10 @@ void MixerChannel::notifyNoAudioSignal() m_audioSignalNotifier.notifyAboutChanges(); } + +bool MixerChannel::playNotesOnMutedTracksWhenEditing() const +{ + // We are not muted if we are Editing and we want to play notes even if mixer sound is off + return !playbackController()->isPlaying() + && playbackConfiguration()->playNotesWhenEditing() && playbackConfiguration()->playNotesOnMutedTracksWhenEditing(); +} diff --git a/src/framework/audio/internal/worker/mixerchannel.h b/src/framework/audio/internal/worker/mixerchannel.h index 5b2fbd6a0c607..ba716130a3169 100644 --- a/src/framework/audio/internal/worker/mixerchannel.h +++ b/src/framework/audio/internal/worker/mixerchannel.h @@ -25,6 +25,8 @@ #include "global/modularity/ioc.h" #include "global/async/asyncable.h" #include "global/async/notification.h" +#include "playback/iplaybackcontroller.h" +#include "playback/iplaybackconfiguration.h" #include "../../ifxresolver.h" #include "../../ifxprocessor.h" @@ -35,6 +37,8 @@ namespace muse::audio { class MixerChannel : public ITrackAudioOutput, public Injectable, public async::Asyncable { Inject fxResolver = { this }; + muse::Inject playbackController = { }; + muse::Inject playbackConfiguration = { this }; public: explicit MixerChannel(const TrackId trackId, IAudioSourcePtr source, const unsigned int sampleRate, @@ -66,6 +70,7 @@ class MixerChannel : public ITrackAudioOutput, public Injectable, public async:: private: void completeOutput(float* buffer, unsigned int samplesCount) const; + bool playNotesOnMutedTracksWhenEditing() const; TrackId m_trackId = -1; diff --git a/src/playback/internal/playbackconfiguration.cpp b/src/playback/internal/playbackconfiguration.cpp index 24402b968f798..58e86f0f3620f 100644 --- a/src/playback/internal/playbackconfiguration.cpp +++ b/src/playback/internal/playbackconfiguration.cpp @@ -39,6 +39,7 @@ static const Settings::Key PLAYBACK_CURSOR_TYPE_KEY(moduleName, "application/pla static const Settings::Key PLAY_NOTES_WHEN_EDITING(moduleName, "score/note/playOnClick"); static const Settings::Key PLAY_CHORD_WHEN_EDITING(moduleName, "score/chord/playOnAddNote"); static const Settings::Key PLAY_HARMONY_WHEN_EDITING(moduleName, "score/harmony/play/onedit"); +static const Settings::Key PLAY_NOTES_ON_MUTED_TRACKS_WHEN_EDITING(moduleName, "score/note/playOnMutedTracks"); static const Settings::Key SOUND_PRESETS_MULTI_SELECTION_KEY(moduleName, "application/playback/soundPresetsMultiSelectionEnabled"); @@ -94,6 +95,8 @@ void PlaybackConfiguration::init() settings()->setDefaultValue(PLAY_NOTES_WHEN_EDITING, Val(true)); settings()->setDefaultValue(PLAY_CHORD_WHEN_EDITING, Val(true)); settings()->setDefaultValue(PLAY_HARMONY_WHEN_EDITING, Val(true)); + settings()->setDefaultValue(PLAY_NOTES_ON_MUTED_TRACKS_WHEN_EDITING, Val(false)); + settings()->setDefaultValue(PLAYBACK_CURSOR_TYPE_KEY, Val(PlaybackCursorType::STEPPED)); settings()->setDefaultValue(SOUND_PRESETS_MULTI_SELECTION_KEY, Val(false)); settings()->setDefaultValue(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_SOUND_WARNING, Val(true)); @@ -161,6 +164,16 @@ void PlaybackConfiguration::setPlayHarmonyWhenEditing(bool value) settings()->setSharedValue(PLAY_HARMONY_WHEN_EDITING, Val(value)); } +bool PlaybackConfiguration::playNotesOnMutedTracksWhenEditing() const +{ + return settings()->value(PLAY_NOTES_ON_MUTED_TRACKS_WHEN_EDITING).toBool(); +} + +void PlaybackConfiguration::setPlayNotesOnMutedTracksWhenEditing(bool value) +{ + settings()->setSharedValue(PLAY_NOTES_ON_MUTED_TRACKS_WHEN_EDITING, Val(value)); +} + PlaybackCursorType PlaybackConfiguration::cursorType() const { return settings()->value(PLAYBACK_CURSOR_TYPE_KEY).toEnum(); diff --git a/src/playback/internal/playbackconfiguration.h b/src/playback/internal/playbackconfiguration.h index 8cd8f1670856c..a857ee76f4800 100644 --- a/src/playback/internal/playbackconfiguration.h +++ b/src/playback/internal/playbackconfiguration.h @@ -47,6 +47,9 @@ class PlaybackConfiguration : public IPlaybackConfiguration, public muse::async: bool playHarmonyWhenEditing() const override; void setPlayHarmonyWhenEditing(bool value) override; + bool playNotesOnMutedTracksWhenEditing() const override; + void setPlayNotesOnMutedTracksWhenEditing(bool value) override; + PlaybackCursorType cursorType() const override; bool isMixerSectionVisible(MixerSectionType sectionType) const override; diff --git a/src/playback/iplaybackconfiguration.h b/src/playback/iplaybackconfiguration.h index 562a830e03e95..7e48e03eac431 100644 --- a/src/playback/iplaybackconfiguration.h +++ b/src/playback/iplaybackconfiguration.h @@ -40,6 +40,9 @@ class IPlaybackConfiguration : MODULE_EXPORT_INTERFACE virtual bool playChordWhenEditing() const = 0; virtual void setPlayChordWhenEditing(bool value) = 0; + virtual bool playNotesOnMutedTracksWhenEditing() const = 0; + virtual void setPlayNotesOnMutedTracksWhenEditing(bool value) = 0; + virtual bool playHarmonyWhenEditing() const = 0; virtual void setPlayHarmonyWhenEditing(bool value) = 0; diff --git a/src/stubs/playback/playbackconfigurationstub.cpp b/src/stubs/playback/playbackconfigurationstub.cpp index d33e287508a23..008757848349f 100644 --- a/src/stubs/playback/playbackconfigurationstub.cpp +++ b/src/stubs/playback/playbackconfigurationstub.cpp @@ -51,6 +51,15 @@ void PlaybackConfigurationStub::setPlayHarmonyWhenEditing(bool) { } +bool PlaybackConfigurationStub::playNotesOnMutedTracksWhenEditing() const +{ + return false; +} + +void PlaybackConfigurationStub::setPlayNotesOnMutedTracksWhenEditing(bool) +{ +} + PlaybackCursorType PlaybackConfigurationStub::cursorType() const { return PlaybackCursorType::SMOOTH; diff --git a/src/stubs/playback/playbackconfigurationstub.h b/src/stubs/playback/playbackconfigurationstub.h index 9e5965eb5006e..740f6ee886115 100644 --- a/src/stubs/playback/playbackconfigurationstub.h +++ b/src/stubs/playback/playbackconfigurationstub.h @@ -37,6 +37,9 @@ class PlaybackConfigurationStub : public IPlaybackConfiguration bool playHarmonyWhenEditing() const override; void setPlayHarmonyWhenEditing(bool value) override; + bool playNotesOnMutedTracksWhenEditing() const override; + void setPlayNotesOnMutedTracksWhenEditing(bool value) override; + PlaybackCursorType cursorType() const override; bool isMixerSectionVisible(MixerSectionType sectionType) const override;