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) 2025 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 "audiomidipreferencesmodel.h"
24 :
25 : #include "translation.h"
26 : #include "log.h"
27 :
28 : using namespace mu::preferences;
29 : using namespace muse::audio;
30 : using namespace muse::midi;
31 :
32 0 : AudioMidiPreferencesModel::AudioMidiPreferencesModel(QObject* parent)
33 0 : : QObject(parent), muse::Contextable(muse::iocCtxForQmlObject(this))
34 : {
35 0 : }
36 :
37 0 : int AudioMidiPreferencesModel::currentAudioDriverIndex() const
38 : {
39 0 : QString current = QString::fromStdString(audioDriverController()->currentAudioDriverName());
40 0 : return audioDrivers().indexOf(current);
41 0 : }
42 :
43 0 : void AudioMidiPreferencesModel::setCurrentAudioDriverIndex(int index)
44 : {
45 0 : if (index == currentAudioDriverIndex()) {
46 0 : return;
47 : }
48 :
49 0 : std::vector<std::string> drivers = audioDriverController()->availableAudioDrivers();
50 0 : if (index < 0 || index >= static_cast<int>(drivers.size())) {
51 0 : return;
52 : }
53 :
54 0 : std::string fallback = audioDriverController()->currentAudioDriverName();
55 :
56 0 : audioDriverController()->availableOutputDevicesChanged().onNotify(this, [this, fallback]() {
57 0 : audioDriverController()->availableOutputDevicesChanged().disconnect(this);
58 :
59 0 : if (!audioDriverController()->availableOutputDevices().empty()) {
60 0 : return;
61 : }
62 :
63 0 : auto promise = interactive()->warning(
64 0 : muse::trc("preferences", "No audio devices available"),
65 0 : muse::qtrc("preferences", "The selected audio driver does not have any available audio devices. "
66 : "MuseScore Studio will use the default audio driver instead. "
67 : "To use %1, ensure your hardware is set up correctly, "
68 : "then restart MuseScore Studio and try again.")
69 0 : .arg(QString::fromStdString(audioDriverController()->currentAudioDriverName())).toStdString());
70 :
71 0 : promise.onResolve(this, [this, fallback](const muse::IInteractive::Result&) {
72 0 : audioDriverController()->changeCurrentAudioDriver(fallback);
73 0 : emit currentAudioDriverIndexChanged(currentAudioDriverIndex());
74 0 : });
75 0 : }, Asyncable::Mode::SetReplace);
76 :
77 0 : audioDriverController()->changeCurrentAudioDriver(drivers.at(index));
78 0 : emit currentAudioDriverIndexChanged(index);
79 0 : }
80 :
81 0 : QString AudioMidiPreferencesModel::midiInputDeviceId() const
82 : {
83 0 : return QString::fromStdString(midiInPort()->deviceID());
84 : }
85 :
86 0 : void AudioMidiPreferencesModel::inputDeviceSelected(const QString& deviceId)
87 : {
88 0 : midiConfiguration()->setMidiInputDeviceId(deviceId.toStdString());
89 0 : }
90 :
91 0 : QString AudioMidiPreferencesModel::midiOutputDeviceId() const
92 : {
93 0 : return QString::fromStdString(midiOutPort()->deviceID());
94 : }
95 :
96 0 : void AudioMidiPreferencesModel::outputDeviceSelected(const QString& deviceId)
97 : {
98 0 : midiConfiguration()->setMidiOutputDeviceId(deviceId.toStdString());
99 0 : }
100 :
101 0 : void AudioMidiPreferencesModel::init()
102 : {
103 0 : midiInPort()->availableDevicesChanged().onNotify(this, [this]() {
104 0 : emit midiInputDevicesChanged();
105 0 : });
106 :
107 0 : midiInPort()->deviceChanged().onNotify(this, [this]() {
108 0 : emit midiInputDeviceIdChanged();
109 0 : });
110 :
111 0 : midiOutPort()->availableDevicesChanged().onNotify(this, [this]() {
112 0 : emit midiOutputDevicesChanged();
113 0 : });
114 :
115 0 : midiOutPort()->deviceChanged().onNotify(this, [this]() {
116 0 : emit midiOutputDeviceIdChanged();
117 0 : });
118 :
119 0 : midiConfiguration()->useMIDI20OutputChanged().onReceive(this, [this](bool) {
120 0 : emit useMIDI20OutputChanged();
121 0 : });
122 :
123 0 : playbackConfiguration()->muteHiddenInstrumentsChanged().onReceive(this, [this](bool mute) {
124 0 : emit muteHiddenInstrumentsChanged(mute);
125 0 : });
126 :
127 0 : playbackConfiguration()->shouldShowOnlineSoundsProcessingErrorChanged().onNotify(this, [this]() {
128 0 : emit shouldShowOnlineSoundsProcessingErrorChanged();
129 0 : });
130 :
131 0 : playbackConfiguration()->onlineSoundsShowProgressBarModeChanged().onNotify(this, [this]() {
132 0 : emit onlineSoundsShowProgressBarModeChanged();
133 0 : });
134 :
135 0 : audioDriverController()->currentAudioDriverChanged().onNotify(this, [this]() {
136 0 : emit currentAudioDriverIndexChanged(currentAudioDriverIndex());
137 0 : });
138 :
139 0 : audioConfiguration()->autoProcessOnlineSoundsInBackgroundChanged().onReceive(this, [this](bool) {
140 0 : emit autoProcessOnlineSoundsInBackgroundChanged();
141 0 : });
142 :
143 0 : audioConfiguration()->useSoundFontLowPassFilterChanged().onReceive(this, [this](bool) {
144 0 : emit useSoundFontLowPassFilterChanged();
145 0 : });
146 0 : }
147 :
148 0 : QStringList AudioMidiPreferencesModel::audioDrivers() const
149 : {
150 0 : const std::vector<std::string> drivers = audioDriverController()->availableAudioDrivers();
151 :
152 0 : QStringList result;
153 0 : result.reserve(drivers.size());
154 :
155 0 : for (const std::string& driver: drivers) {
156 0 : result.emplace_back(QString::fromStdString(driver));
157 : }
158 :
159 0 : return result;
160 0 : }
161 :
162 0 : void AudioMidiPreferencesModel::restartAudioAndMidiDevices()
163 : {
164 0 : NOT_IMPLEMENTED;
165 0 : }
166 :
167 0 : bool AudioMidiPreferencesModel::onlineSoundsSectionVisible() const
168 : {
169 : #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
170 : return true;
171 : #else
172 0 : return false;
173 : #endif
174 : }
175 :
176 0 : QVariantList AudioMidiPreferencesModel::midiInputDevices() const
177 : {
178 0 : std::vector<MidiDevice> devices = midiInPort()->availableDevices();
179 :
180 0 : QVariantList result;
181 0 : result.reserve(devices.size());
182 :
183 0 : for (const MidiDevice& device : devices) {
184 0 : QVariantMap obj;
185 0 : obj["value"] = QString::fromStdString(device.id);
186 0 : obj["text"] = QString::fromStdString(device.name);
187 :
188 0 : result << obj;
189 0 : }
190 :
191 0 : return result;
192 0 : }
193 :
194 0 : QVariantList AudioMidiPreferencesModel::midiOutputDevices() const
195 : {
196 0 : std::vector<MidiDevice> devices = midiOutPort()->availableDevices();
197 :
198 0 : QVariantList result;
199 0 : result.reserve(devices.size());
200 :
201 0 : for (const MidiDevice& device : devices) {
202 0 : QVariantMap obj;
203 0 : obj["value"] = QString::fromStdString(device.id);
204 0 : obj["text"] = QString::fromStdString(device.name);
205 :
206 0 : result << obj;
207 0 : }
208 :
209 0 : return result;
210 0 : }
211 :
212 0 : bool AudioMidiPreferencesModel::isMIDI20OutputSupported() const
213 : {
214 0 : return midiOutPort()->supportsMIDI20Output();
215 : }
216 :
217 0 : bool AudioMidiPreferencesModel::useMIDI20Output() const
218 : {
219 0 : return midiConfiguration()->useMIDI20Output();
220 : }
221 :
222 0 : void AudioMidiPreferencesModel::setUseMIDI20Output(bool use)
223 : {
224 0 : if (use == useMIDI20Output()) {
225 0 : return;
226 : }
227 :
228 0 : midiConfiguration()->setUseMIDI20Output(use);
229 : }
230 :
231 0 : void AudioMidiPreferencesModel::showMidiError(const MidiDeviceID& deviceId, const std::string& text) const
232 : {
233 : // todo: display error
234 0 : LOGE() << "failed connect to device, deviceID: " << deviceId << ", err: " << text;
235 0 : }
236 :
237 0 : bool AudioMidiPreferencesModel::muteHiddenInstruments() const
238 : {
239 0 : return playbackConfiguration()->muteHiddenInstruments();
240 : }
241 :
242 0 : void AudioMidiPreferencesModel::setMuteHiddenInstruments(bool mute)
243 : {
244 0 : if (mute == muteHiddenInstruments()) {
245 0 : return;
246 : }
247 :
248 0 : playbackConfiguration()->setMuteHiddenInstruments(mute);
249 : }
250 :
251 0 : bool AudioMidiPreferencesModel::shouldShowOnlineSoundsProcessingError() const
252 : {
253 0 : return playbackConfiguration()->shouldShowOnlineSoundsProcessingError();
254 : }
255 :
256 0 : void AudioMidiPreferencesModel::setShouldShowOnlineSoundsProcessingError(bool value)
257 : {
258 0 : if (value == shouldShowOnlineSoundsProcessingError()) {
259 0 : return;
260 : }
261 :
262 0 : playbackConfiguration()->setShouldShowOnlineSoundsProcessingError(value);
263 : }
264 :
265 0 : bool AudioMidiPreferencesModel::autoProcessOnlineSoundsInBackground() const
266 : {
267 0 : return audioConfiguration()->autoProcessOnlineSoundsInBackground();
268 : }
269 :
270 0 : void AudioMidiPreferencesModel::setAutoProcessOnlineSoundsInBackground(bool value)
271 : {
272 0 : if (value == autoProcessOnlineSoundsInBackground()) {
273 0 : return;
274 : }
275 :
276 0 : audioConfiguration()->setAutoProcessOnlineSoundsInBackground(value);
277 :
278 0 : if (!value) {
279 0 : if (playbackConfiguration()->onlineSoundsShowProgressBarMode() == playback::OnlineSoundsShowProgressBarMode::DuringPlayback) {
280 0 : playbackConfiguration()->setOnlineSoundsShowProgressBarMode(playback::OnlineSoundsShowProgressBarMode::Always);
281 : }
282 : }
283 : }
284 :
285 0 : int AudioMidiPreferencesModel::onlineSoundsShowProgressBarMode() const
286 : {
287 0 : return static_cast<int>(playbackConfiguration()->onlineSoundsShowProgressBarMode());
288 : }
289 :
290 0 : void AudioMidiPreferencesModel::setOnlineSoundsShowProgressBarMode(int mode)
291 : {
292 0 : if (mode == onlineSoundsShowProgressBarMode()) {
293 0 : return;
294 : }
295 :
296 0 : playbackConfiguration()->setOnlineSoundsShowProgressBarMode(static_cast<playback::OnlineSoundsShowProgressBarMode>(mode));
297 : }
298 :
299 0 : bool AudioMidiPreferencesModel::useSoundFontLowPassFilter() const
300 : {
301 0 : return audioConfiguration()->useSoundFontLowPassFilter();
302 : }
303 :
304 0 : void AudioMidiPreferencesModel::setUseSoundFontLowPassFilter(bool value)
305 : {
306 0 : if (value == useSoundFontLowPassFilter()) {
307 0 : return;
308 : }
309 :
310 0 : audioConfiguration()->setUseSoundFontLowPassFilter(value);
311 : }
|