Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 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 : #include "playbackconfiguration.h"
23 :
24 : #include "settings.h"
25 : #include "types/string.h"
26 :
27 : #include "playbacktypes.h"
28 :
29 : #include "log.h"
30 :
31 : using namespace mu;
32 : using namespace mu::playback;
33 : using namespace muse;
34 : using namespace muse::audio;
35 :
36 : static const std::string moduleName("playback");
37 :
38 : static const Settings::Key PLAYBACK_CURSOR_TYPE_KEY(moduleName, "application/playback/cursorType");
39 : static const Settings::Key PLAY_NOTES_WHEN_EDITING(moduleName, "score/note/playOnClick");
40 : static const Settings::Key PLAY_NOTES_ON_MIDI_INPUT(moduleName, "score/note/playOnMidiInput");
41 : static const Settings::Key PLAY_CHORD_WHEN_EDITING(moduleName, "score/chord/playOnAddNote");
42 : static const Settings::Key PLAY_HARMONY_WHEN_EDITING(moduleName, "score/harmony/play/onedit");
43 :
44 : static const Settings::Key SOUND_PRESETS_MULTI_SELECTION_KEY(moduleName, "application/playback/soundPresetsMultiSelectionEnabled");
45 :
46 : static const Settings::Key MIXER_LABELS_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/labelsSectionVisible");
47 : static const Settings::Key MIXER_SOUND_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/soundSectionVisible");
48 : static const Settings::Key MIXER_AUDIO_FX_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/audioFxSectionVisible");
49 : static const Settings::Key MIXER_BALANCE_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/balanceSectionVisible");
50 : static const Settings::Key MIXER_VOLUME_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/volumeSectionVisible");
51 : static const Settings::Key MIXER_FADER_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/faderSectionVisible");
52 : static const Settings::Key MIXER_MUTE_AND_SOLO_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/muteAndSoloSectionVisible");
53 : static const Settings::Key MIXER_TITLE_SECTION_VISIBLE_KEY(moduleName, "playback/mixer/titleSectionVisible");
54 :
55 : static const Settings::Key MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_SOUND_WARNING(moduleName,
56 : "playback/mixer/needToShowAboutResetSoundFlagsWhwnChangeSoundWarning");
57 : static const Settings::Key MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_PLAYBACK_PROFILE_WARNING(moduleName,
58 : "playback/mixer/needToShowAboutResetSoundFlagsWhwnChangePlaybackProfileWarning");
59 :
60 : static const Settings::Key ONLINE_SOUNDS_SHOW_ERROR(moduleName, "playback/onlineSounds/showError");
61 : static const Settings::Key ONLINE_SOUNDS_SHOW_PROGRESS_BAR_MODE(moduleName, "playback/onlineSounds/showProgressBarMode");
62 :
63 : static const Settings::Key MUTE_HIDDEN_INSTRUMENTS(moduleName, "playback/mixer/muteHiddenInstruments");
64 :
65 : static const Settings::Key DEFAULT_SOUND_PROFILE_FOR_NEW_PROJECTS(moduleName, "playback/profiles/defaultProfileName");
66 : static const SoundProfileName BASIC_PROFILE_NAME(u"MuseScore Basic");
67 : static const SoundProfileName MUSESOUNDS_PROFILE_NAME(u"MuseSounds");
68 : static const SoundProfileName COMPAT_MUSESOUNDS_PROFILE_NAME(u"Muse Sounds");
69 :
70 0 : static Settings::Key mixerSectionVisibleKey(MixerSectionType sectionType)
71 : {
72 0 : switch (sectionType) {
73 0 : case MixerSectionType::Labels: return MIXER_LABELS_SECTION_VISIBLE_KEY;
74 0 : case MixerSectionType::Sound: return MIXER_SOUND_SECTION_VISIBLE_KEY;
75 0 : case MixerSectionType::AudioFX: return MIXER_AUDIO_FX_SECTION_VISIBLE_KEY;
76 0 : case MixerSectionType::Balance: return MIXER_BALANCE_SECTION_VISIBLE_KEY;
77 0 : case MixerSectionType::Volume: return MIXER_VOLUME_SECTION_VISIBLE_KEY;
78 0 : case MixerSectionType::Fader: return MIXER_FADER_SECTION_VISIBLE_KEY;
79 0 : case MixerSectionType::MuteAndSolo: return MIXER_MUTE_AND_SOLO_SECTION_VISIBLE_KEY;
80 0 : case MixerSectionType::Title: return MIXER_TITLE_SECTION_VISIBLE_KEY;
81 0 : case MixerSectionType::Unknown: break;
82 : }
83 :
84 0 : return Settings::Key();
85 : }
86 :
87 0 : static Settings::Key auxSendVisibleKey(aux_channel_idx_t index)
88 : {
89 0 : return Settings::Key(moduleName, "playback/mixer/auxSend" + std::to_string(index) + "Visible");
90 : }
91 :
92 0 : static Settings::Key auxChannelVisibleKey(aux_channel_idx_t index)
93 : {
94 0 : return Settings::Key(moduleName, "playback/mixer/auxChannel" + std::to_string(index) + "Visible");
95 : }
96 :
97 0 : void PlaybackConfiguration::init()
98 : {
99 0 : settings()->setDefaultValue(PLAY_NOTES_WHEN_EDITING, Val(true));
100 0 : settings()->valueChanged(PLAY_NOTES_WHEN_EDITING).onReceive(this, [this](const Val&) {
101 0 : m_playNotesWhenEditingChanged.notify();
102 0 : });
103 0 : settings()->setDefaultValue(PLAY_CHORD_WHEN_EDITING, Val(true));
104 0 : settings()->valueChanged(PLAY_CHORD_WHEN_EDITING).onReceive(this, [this](const Val& val) {
105 0 : m_playChordWhenEditingChanged.send(val.toBool());
106 0 : });
107 0 : settings()->setDefaultValue(PLAY_HARMONY_WHEN_EDITING, Val(true));
108 0 : settings()->valueChanged(PLAY_HARMONY_WHEN_EDITING).onReceive(this, [this](const Val& val) {
109 0 : m_playHarmonyWhenEditingChanged.send(val.toBool());
110 0 : });
111 0 : settings()->setDefaultValue(PLAY_NOTES_ON_MIDI_INPUT, Val(true));
112 0 : settings()->valueChanged(PLAY_NOTES_ON_MIDI_INPUT).onReceive(this, [this](const Val& val) {
113 0 : m_playNotesOnMidiInputChanged.send(val.toBool());
114 0 : });
115 0 : settings()->setDefaultValue(PLAYBACK_CURSOR_TYPE_KEY, Val(PlaybackCursorType::STEPPED));
116 0 : settings()->setDefaultValue(SOUND_PRESETS_MULTI_SELECTION_KEY, Val(false));
117 0 : settings()->setDefaultValue(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_SOUND_WARNING, Val(true));
118 0 : settings()->setDefaultValue(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_PLAYBACK_PROFILE_WARNING, Val(true));
119 :
120 0 : for (MixerSectionType sectionType : allMixerSectionTypes()) {
121 0 : bool sectionEnabledByDefault = sectionType != MixerSectionType::Volume;
122 0 : settings()->setDefaultValue(mixerSectionVisibleKey(sectionType), Val(sectionEnabledByDefault));
123 0 : settings()->valueChanged(mixerSectionVisibleKey(sectionType)).onReceive(this, [this, sectionType](const Val& val) {
124 0 : m_isMixerSectionVisibleChanged.send(sectionType, val.toBool());
125 0 : });
126 0 : }
127 :
128 0 : settings()->setDefaultValue(MUTE_HIDDEN_INSTRUMENTS, Val(true));
129 0 : settings()->valueChanged(MUTE_HIDDEN_INSTRUMENTS).onReceive(nullptr, [this](const Val& mute) {
130 0 : m_muteHiddenInstrumentsChanged.send(mute.toBool());
131 0 : });
132 :
133 0 : settings()->setDefaultValue(DEFAULT_SOUND_PROFILE_FOR_NEW_PROJECTS, Val(fallbackSoundProfileStr().toStdString()));
134 :
135 0 : for (aux_channel_idx_t idx = 0; idx < AUX_CHANNEL_NUM; ++idx) {
136 0 : Settings::Key auxSendKey = auxSendVisibleKey(idx);
137 0 : Settings::Key auxChannelKey = auxChannelVisibleKey(idx);
138 :
139 0 : settings()->setDefaultValue(auxSendKey, Val(idx == REVERB_CHANNEL_IDX));
140 0 : settings()->setDefaultValue(auxChannelKey, Val(false));
141 :
142 0 : settings()->valueChanged(auxSendKey).onReceive(this, [this, idx](const Val& val) {
143 0 : m_isAuxSendVisibleChanged.send(idx, val.toBool());
144 0 : });
145 :
146 0 : settings()->valueChanged(auxChannelKey).onReceive(this, [this, idx](const Val& val) {
147 0 : m_isAuxChannelVisibleChanged.send(idx, val.toBool());
148 0 : });
149 0 : }
150 :
151 0 : settings()->setDefaultValue(ONLINE_SOUNDS_SHOW_ERROR, Val(true));
152 0 : settings()->valueChanged(ONLINE_SOUNDS_SHOW_ERROR).onReceive(nullptr, [this](const Val&) {
153 0 : m_shouldShowOnlineSoundsProcessingErrorChanged.notify();
154 0 : });
155 :
156 0 : settings()->setDefaultValue(ONLINE_SOUNDS_SHOW_PROGRESS_BAR_MODE, Val(static_cast<int>(OnlineSoundsShowProgressBarMode::Always)));
157 0 : settings()->valueChanged(ONLINE_SOUNDS_SHOW_PROGRESS_BAR_MODE).onReceive(nullptr, [this](const Val&) {
158 0 : m_onlineSoundsShowProgressBarModeChanged.notify();
159 0 : });
160 0 : }
161 :
162 0 : bool PlaybackConfiguration::playNotesWhenEditing() const
163 : {
164 0 : return settings()->value(PLAY_NOTES_WHEN_EDITING).toBool();
165 : }
166 :
167 0 : void PlaybackConfiguration::setPlayNotesWhenEditing(bool value)
168 : {
169 0 : settings()->setSharedValue(PLAY_NOTES_WHEN_EDITING, Val(value));
170 0 : }
171 :
172 0 : muse::async::Notification PlaybackConfiguration::playNotesWhenEditingChanged() const
173 : {
174 0 : return m_playNotesWhenEditingChanged;
175 : }
176 :
177 0 : bool PlaybackConfiguration::playChordWhenEditing() const
178 : {
179 0 : return settings()->value(PLAY_CHORD_WHEN_EDITING).toBool();
180 : }
181 :
182 0 : void PlaybackConfiguration::setPlayChordWhenEditing(bool value)
183 : {
184 0 : settings()->setSharedValue(PLAY_CHORD_WHEN_EDITING, Val(value));
185 0 : }
186 :
187 0 : async::Channel<bool> PlaybackConfiguration::playChordWhenEditingChanged() const
188 : {
189 0 : return m_playChordWhenEditingChanged;
190 : }
191 :
192 0 : bool PlaybackConfiguration::playHarmonyWhenEditing() const
193 : {
194 0 : return settings()->value(PLAY_HARMONY_WHEN_EDITING).toBool();
195 : }
196 :
197 0 : void PlaybackConfiguration::setPlayHarmonyWhenEditing(bool value)
198 : {
199 0 : settings()->setSharedValue(PLAY_HARMONY_WHEN_EDITING, Val(value));
200 0 : }
201 :
202 0 : async::Channel<bool> PlaybackConfiguration::playHarmonyWhenEditingChanged() const
203 : {
204 0 : return m_playHarmonyWhenEditingChanged;
205 : }
206 :
207 0 : bool PlaybackConfiguration::playNotesOnMidiInput() const
208 : {
209 0 : return settings()->value(PLAY_NOTES_ON_MIDI_INPUT).toBool();
210 : }
211 :
212 0 : void PlaybackConfiguration::setPlayNotesOnMidiInput(bool value)
213 : {
214 0 : settings()->setSharedValue(PLAY_NOTES_ON_MIDI_INPUT, Val(value));
215 0 : }
216 :
217 0 : muse::async::Channel<bool> PlaybackConfiguration::playNotesOnMidiInputChanged() const
218 : {
219 0 : return m_playNotesOnMidiInputChanged;
220 : }
221 :
222 0 : PlaybackCursorType PlaybackConfiguration::cursorType() const
223 : {
224 0 : return settings()->value(PLAYBACK_CURSOR_TYPE_KEY).toEnum<PlaybackCursorType>();
225 : }
226 :
227 0 : bool PlaybackConfiguration::isMixerSectionVisible(MixerSectionType sectionType) const
228 : {
229 0 : return settings()->value(mixerSectionVisibleKey(sectionType)).toBool();
230 : }
231 :
232 0 : void PlaybackConfiguration::setMixerSectionVisible(MixerSectionType sectionType, bool visible)
233 : {
234 0 : settings()->setSharedValue(mixerSectionVisibleKey(sectionType), Val(visible));
235 0 : }
236 :
237 0 : muse::async::Channel<MixerSectionType, bool> PlaybackConfiguration::isMixerSectionVisibleChanged() const
238 : {
239 0 : return m_isMixerSectionVisibleChanged;
240 : }
241 :
242 0 : bool PlaybackConfiguration::isAuxSendVisible(aux_channel_idx_t index) const
243 : {
244 0 : return settings()->value(auxSendVisibleKey(index)).toBool();
245 : }
246 :
247 0 : void PlaybackConfiguration::setAuxSendVisible(aux_channel_idx_t index, bool visible)
248 : {
249 0 : settings()->setSharedValue(auxSendVisibleKey(index), Val(visible));
250 0 : }
251 :
252 0 : muse::async::Channel<aux_channel_idx_t, bool> PlaybackConfiguration::isAuxSendVisibleChanged() const
253 : {
254 0 : return m_isAuxSendVisibleChanged;
255 : }
256 :
257 0 : bool PlaybackConfiguration::isAuxChannelVisible(aux_channel_idx_t index) const
258 : {
259 0 : return settings()->value(auxChannelVisibleKey(index)).toBool();
260 : }
261 :
262 0 : void PlaybackConfiguration::setAuxChannelVisible(aux_channel_idx_t index, bool visible) const
263 : {
264 0 : settings()->setSharedValue(auxChannelVisibleKey(index), Val(visible));
265 0 : }
266 :
267 0 : muse::async::Channel<aux_channel_idx_t, bool> PlaybackConfiguration::isAuxChannelVisibleChanged() const
268 : {
269 0 : return m_isAuxChannelVisibleChanged;
270 : }
271 :
272 0 : gain_t PlaybackConfiguration::defaultAuxSendValue(aux_channel_idx_t index, AudioSourceType sourceType,
273 : const muse::String& instrumentSoundId) const
274 : {
275 0 : TRACEFUNC;
276 :
277 0 : constexpr gain_t DEFAULT_VALUE = 0.30f;
278 :
279 0 : if (sourceType == AudioSourceType::MuseSampler) {
280 0 : if (index == REVERB_CHANNEL_IDX) {
281 0 : float lvl = musesamplerInfo()->defaultReverbLevel(instrumentSoundId);
282 0 : return muse::RealIsNull(lvl) ? DEFAULT_VALUE : lvl;
283 : }
284 0 : } else if (sourceType == AudioSourceType::Vsti) {
285 0 : return 0.f;
286 : }
287 :
288 0 : return DEFAULT_VALUE;
289 0 : }
290 :
291 0 : bool PlaybackConfiguration::muteHiddenInstruments() const
292 : {
293 0 : return settings()->value(MUTE_HIDDEN_INSTRUMENTS).toBool();
294 : }
295 :
296 0 : void PlaybackConfiguration::setMuteHiddenInstruments(bool mute)
297 : {
298 0 : settings()->setSharedValue(MUTE_HIDDEN_INSTRUMENTS, Val(mute));
299 0 : }
300 :
301 0 : muse::async::Channel<bool> PlaybackConfiguration::muteHiddenInstrumentsChanged() const
302 : {
303 0 : return m_muteHiddenInstrumentsChanged;
304 : }
305 :
306 0 : const SoundProfileName& PlaybackConfiguration::basicSoundProfileName() const
307 : {
308 0 : return BASIC_PROFILE_NAME;
309 : }
310 :
311 0 : const SoundProfileName& PlaybackConfiguration::museSoundsProfileName() const
312 : {
313 0 : return MUSESOUNDS_PROFILE_NAME;
314 : }
315 :
316 0 : const SoundProfileName& PlaybackConfiguration::compatMuseSoundsProfileName() const
317 : {
318 0 : return COMPAT_MUSESOUNDS_PROFILE_NAME;
319 : }
320 :
321 0 : SoundProfileName PlaybackConfiguration::defaultProfileForNewProjects() const
322 : {
323 0 : return muse::String::fromStdString(settings()->value(DEFAULT_SOUND_PROFILE_FOR_NEW_PROJECTS).toString());
324 : }
325 :
326 0 : void PlaybackConfiguration::setDefaultProfileForNewProjects(const SoundProfileName& name)
327 : {
328 0 : settings()->setSharedValue(DEFAULT_SOUND_PROFILE_FOR_NEW_PROJECTS, Val(name.toStdString()));
329 0 : }
330 :
331 0 : bool PlaybackConfiguration::soundPresetsMultiSelectionEnabled() const
332 : {
333 0 : return settings()->value(SOUND_PRESETS_MULTI_SELECTION_KEY).toBool();
334 : }
335 :
336 0 : void PlaybackConfiguration::setSoundPresetsMultiSelectionEnabled(bool enabled)
337 : {
338 0 : settings()->setSharedValue(SOUND_PRESETS_MULTI_SELECTION_KEY, Val(enabled));
339 0 : }
340 :
341 0 : bool PlaybackConfiguration::needToShowResetSoundFlagsWhenChangeSoundWarning() const
342 : {
343 0 : return settings()->value(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_SOUND_WARNING).toBool();
344 : }
345 :
346 0 : void PlaybackConfiguration::setNeedToShowResetSoundFlagsWhenChangeSoundWarning(bool show)
347 : {
348 0 : settings()->setSharedValue(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_SOUND_WARNING, Val(show));
349 0 : }
350 :
351 0 : bool PlaybackConfiguration::needToShowResetSoundFlagsWhenChangePlaybackProfileWarning() const
352 : {
353 0 : return settings()->value(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_PLAYBACK_PROFILE_WARNING).toBool();
354 : }
355 :
356 0 : void PlaybackConfiguration::setNeedToShowResetSoundFlagsWhenChangePlaybackProfileWarning(bool show)
357 : {
358 0 : settings()->setSharedValue(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_PLAYBACK_PROFILE_WARNING, Val(show));
359 0 : }
360 :
361 0 : bool PlaybackConfiguration::shouldShowOnlineSoundsProcessingError() const
362 : {
363 0 : return settings()->value(ONLINE_SOUNDS_SHOW_ERROR).toBool();
364 : }
365 :
366 0 : void PlaybackConfiguration::setShouldShowOnlineSoundsProcessingError(bool show)
367 : {
368 0 : settings()->setSharedValue(ONLINE_SOUNDS_SHOW_ERROR, Val(show));
369 0 : }
370 :
371 0 : muse::async::Notification PlaybackConfiguration::shouldShowOnlineSoundsProcessingErrorChanged() const
372 : {
373 0 : return m_shouldShowOnlineSoundsProcessingErrorChanged;
374 : }
375 :
376 0 : muse::String PlaybackConfiguration::onlineSoundsHandbookUrl() const
377 : {
378 0 : return u"https://handbook.musescore.org/sound-and-playback/installing-muse-sounds/online-sounds";
379 : }
380 :
381 0 : OnlineSoundsShowProgressBarMode PlaybackConfiguration::onlineSoundsShowProgressBarMode() const
382 : {
383 0 : return static_cast<OnlineSoundsShowProgressBarMode>(settings()->value(ONLINE_SOUNDS_SHOW_PROGRESS_BAR_MODE).toInt());
384 : }
385 :
386 0 : void PlaybackConfiguration::setOnlineSoundsShowProgressBarMode(OnlineSoundsShowProgressBarMode mode)
387 : {
388 0 : settings()->setSharedValue(ONLINE_SOUNDS_SHOW_PROGRESS_BAR_MODE, Val(static_cast<int>(mode)));
389 0 : }
390 :
391 0 : muse::async::Notification PlaybackConfiguration::onlineSoundsShowProgressBarModeChanged() const
392 : {
393 0 : return m_onlineSoundsShowProgressBarModeChanged;
394 : }
395 :
396 0 : bool PlaybackConfiguration::shouldMeasureInputLag() const
397 : {
398 0 : return audioConfiguration()->shouldMeasureInputLag();
399 : }
400 :
401 0 : const SoundProfileName& PlaybackConfiguration::fallbackSoundProfileStr() const
402 : {
403 0 : if (musesamplerInfo() && musesamplerInfo()->isLoaded()) {
404 0 : return MUSESOUNDS_PROFILE_NAME;
405 : }
406 :
407 0 : return BASIC_PROFILE_NAME;
408 : }
|