Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-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 : #include "audioconfiguration.h"
23 :
24 : //TODO: remove with global clearing of Q_OS_*** defines
25 : #include <QtGlobal>
26 :
27 : #include "global/settings.h"
28 :
29 : #include "audio/common/soundfonttypes.h"
30 : #include "audio/common/audioutils.h"
31 : #include "audio/common/rpc/rpcpacker.h"
32 :
33 : #include "log.h"
34 :
35 : using namespace muse;
36 : using namespace muse::audio;
37 : using namespace muse::audio::synth;
38 :
39 : static constexpr audioch_t AUDIO_CHANNELS = 2;
40 : static constexpr samples_t DEFAULT_BUFFER_SIZE = 1024;
41 : static constexpr sample_rate_t DEFAULT_SAMPLE_RATE = 44100;
42 :
43 : //TODO: add other setting: audio device etc
44 : static const Settings::Key AUDIO_DRIVER_KEY("audio", "io/audioDriver");
45 : static const Settings::Key AUDIO_OUTPUT_DEVICE_ID_KEY("audio", "io/outputDevice");
46 : static const Settings::Key AUDIO_BUFFER_SIZE_KEY("audio", "io/bufferSize");
47 : static const Settings::Key AUDIO_SAMPLE_RATE_KEY("audio", "io/sampleRate");
48 : static const Settings::Key AUDIO_MEASURE_INPUT_LAG("audio", "io/measureInputLag");
49 :
50 : static const Settings::Key ONLINE_SOUNDS_PROCESS_IN_BACKGROUND("audio", "io/onlineSounds/processInBackground");
51 : static const Settings::Key USE_SOUNDFONT_LOWPASS_FILTER("audio", "synthesizer/useSoundFontLowPassFilter");
52 :
53 : static const Settings::Key USER_SOUNDFONTS_PATHS("midi", "application/paths/mySoundfonts");
54 :
55 0 : void AudioConfiguration::init()
56 : {
57 0 : settings()->setDefaultValue(AUDIO_BUFFER_SIZE_KEY, Val(static_cast<int>(DEFAULT_BUFFER_SIZE)));
58 0 : settings()->valueChanged(AUDIO_BUFFER_SIZE_KEY).onReceive(nullptr, [this](const Val&) {
59 0 : m_driverBufferSizeChanged.notify();
60 0 : });
61 :
62 : #if defined(Q_OS_WIN)
63 : settings()->setDefaultValue(AUDIO_DRIVER_KEY, Val("WASAPI"));
64 : #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
65 0 : settings()->setDefaultValue(AUDIO_DRIVER_KEY, Val("ALSA"));
66 : #elif defined(Q_OS_MACOS)
67 : settings()->setDefaultValue(AUDIO_DRIVER_KEY, Val("CoreAudio"));
68 : #endif
69 0 : settings()->valueChanged(AUDIO_DRIVER_KEY).onReceive(nullptr, [this](const Val&) {
70 0 : m_currentAudioDriverChanged.notify();
71 0 : });
72 :
73 0 : settings()->setDefaultValue(AUDIO_OUTPUT_DEVICE_ID_KEY, Val(DEFAULT_DEVICE_ID));
74 0 : settings()->valueChanged(AUDIO_OUTPUT_DEVICE_ID_KEY).onReceive(nullptr, [this](const Val&) {
75 0 : m_audioOutputDeviceIdChanged.notify();
76 0 : });
77 :
78 0 : settings()->setDefaultValue(AUDIO_SAMPLE_RATE_KEY, Val(static_cast<int>(DEFAULT_SAMPLE_RATE)));
79 0 : settings()->setCanBeManuallyEdited(AUDIO_SAMPLE_RATE_KEY, false, Val(44100), Val(192000));
80 0 : settings()->valueChanged(AUDIO_SAMPLE_RATE_KEY).onReceive(nullptr, [this](const Val&) {
81 0 : m_driverSampleRateChanged.notify();
82 0 : });
83 :
84 0 : settings()->setDefaultValue(USER_SOUNDFONTS_PATHS, Val(globalConfiguration()->userDataPath() + "/SoundFonts"));
85 0 : settings()->valueChanged(USER_SOUNDFONTS_PATHS).onReceive(nullptr, [this](const Val&) {
86 0 : m_soundFontDirsChanged.send(soundFontDirectories());
87 0 : });
88 :
89 0 : for (const auto& path : userSoundFontDirectories()) {
90 0 : fileSystem()->makePath(path);
91 0 : }
92 :
93 0 : settings()->setDefaultValue(AUDIO_MEASURE_INPUT_LAG, Val(false));
94 :
95 0 : settings()->setDefaultValue(ONLINE_SOUNDS_PROCESS_IN_BACKGROUND, Val(true));
96 0 : settings()->valueChanged(ONLINE_SOUNDS_PROCESS_IN_BACKGROUND).onReceive(nullptr, [this](const Val& val) {
97 0 : m_autoProcessOnlineSoundsInBackgroundChanged.send(val.toBool());
98 0 : });
99 :
100 0 : settings()->setDefaultValue(USE_SOUNDFONT_LOWPASS_FILTER, Val(true));
101 0 : settings()->valueChanged(USE_SOUNDFONT_LOWPASS_FILTER).onReceive(nullptr, [this](const Val& val) {
102 0 : m_useSoundFontLowPassFilterChanged.send(val.toBool());
103 0 : });
104 0 : }
105 :
106 0 : AudioEngineConfig AudioConfiguration::engineConfig() const
107 : {
108 0 : AudioEngineConfig conf;
109 0 : conf.autoProcessOnlineSoundsInBackground = autoProcessOnlineSoundsInBackground();
110 0 : conf.isLazyProcessingOfOnlineSoundsEnabled = conf.autoProcessOnlineSoundsInBackground;
111 0 : conf.useSoundFontLowPassFilter = useSoundFontLowPassFilter();
112 0 : return conf;
113 : }
114 :
115 0 : void AudioConfiguration::onEngineConfigChanged()
116 : {
117 0 : rpcChannel()->send(rpc::make_notification(rpc::GLOBAL_CTX_ID, rpc::MsgCode::EngineConfigChanged, rpc::RpcPacker::pack(engineConfig())));
118 0 : }
119 :
120 0 : std::string AudioConfiguration::defaultAudioDriverName() const
121 : {
122 0 : return settings()->defaultValue(AUDIO_DRIVER_KEY).toString();
123 : }
124 :
125 0 : std::string AudioConfiguration::currentAudioDriverName() const
126 : {
127 0 : return settings()->value(AUDIO_DRIVER_KEY).toString();
128 : }
129 :
130 0 : void AudioConfiguration::setCurrentAudioDriverName(const std::string& name)
131 : {
132 0 : settings()->setSharedValue(AUDIO_DRIVER_KEY, Val(name));
133 0 : }
134 :
135 0 : async::Notification AudioConfiguration::currentAudioDriverChanged() const
136 : {
137 0 : return m_currentAudioDriverChanged;
138 : }
139 :
140 0 : std::string AudioConfiguration::audioOutputDeviceId() const
141 : {
142 0 : return settings()->value(AUDIO_OUTPUT_DEVICE_ID_KEY).toString();
143 : }
144 :
145 0 : void AudioConfiguration::setAudioOutputDeviceId(const std::string& deviceId)
146 : {
147 0 : settings()->setSharedValue(AUDIO_OUTPUT_DEVICE_ID_KEY, Val(deviceId));
148 0 : }
149 :
150 0 : async::Notification AudioConfiguration::audioOutputDeviceIdChanged() const
151 : {
152 0 : return m_audioOutputDeviceIdChanged;
153 : }
154 :
155 0 : audioch_t AudioConfiguration::audioChannelsCount() const
156 : {
157 0 : return AUDIO_CHANNELS;
158 : }
159 :
160 0 : unsigned int AudioConfiguration::driverBufferSize() const
161 : {
162 0 : return settings()->value(AUDIO_BUFFER_SIZE_KEY).toInt();
163 : }
164 :
165 0 : void AudioConfiguration::setDriverBufferSize(unsigned int size)
166 : {
167 0 : settings()->setSharedValue(AUDIO_BUFFER_SIZE_KEY, Val(static_cast<int>(size)));
168 0 : }
169 :
170 0 : async::Notification AudioConfiguration::driverBufferSizeChanged() const
171 : {
172 0 : return m_driverBufferSizeChanged;
173 : }
174 :
175 0 : unsigned int AudioConfiguration::sampleRate() const
176 : {
177 0 : return settings()->value(AUDIO_SAMPLE_RATE_KEY).toInt();
178 : }
179 :
180 0 : void AudioConfiguration::setSampleRate(unsigned int sampleRate)
181 : {
182 0 : settings()->setSharedValue(AUDIO_SAMPLE_RATE_KEY, Val(static_cast<int>(sampleRate)));
183 0 : }
184 :
185 0 : async::Notification AudioConfiguration::sampleRateChanged() const
186 : {
187 0 : return m_driverSampleRateChanged;
188 : }
189 :
190 0 : OutputSpec AudioConfiguration::defaultOutputSpec() const
191 : {
192 0 : OutputSpec spec;
193 0 : spec.sampleRate = DEFAULT_SAMPLE_RATE;
194 0 : spec.samplesPerChannel = DEFAULT_BUFFER_SIZE;
195 0 : spec.audioChannelCount = AUDIO_CHANNELS;
196 0 : return spec;
197 : }
198 :
199 0 : OutputSpec AudioConfiguration::desiredOutputSpec() const
200 : {
201 0 : OutputSpec spec;
202 0 : spec.sampleRate = sampleRate();
203 0 : spec.samplesPerChannel = driverBufferSize();
204 0 : spec.audioChannelCount = audioChannelsCount();
205 0 : return spec;
206 : }
207 :
208 0 : io::paths_t AudioConfiguration::soundFontDirectories() const
209 : {
210 0 : io::paths_t paths = userSoundFontDirectories();
211 0 : paths.push_back(globalConfiguration()->appDataPath());
212 :
213 0 : return paths;
214 0 : }
215 :
216 0 : io::paths_t AudioConfiguration::userSoundFontDirectories() const
217 : {
218 0 : std::string pathsStr = settings()->value(USER_SOUNDFONTS_PATHS).toString();
219 0 : return io::pathsFromString(pathsStr);
220 0 : }
221 :
222 0 : void AudioConfiguration::setUserSoundFontDirectories(const io::paths_t& paths)
223 : {
224 0 : settings()->setSharedValue(USER_SOUNDFONTS_PATHS, Val(io::pathsToString(paths)));
225 0 : }
226 :
227 0 : async::Channel<io::paths_t> AudioConfiguration::soundFontDirectoriesChanged() const
228 : {
229 0 : return m_soundFontDirsChanged;
230 : }
231 :
232 0 : bool AudioConfiguration::autoProcessOnlineSoundsInBackground() const
233 : {
234 0 : return settings()->value(ONLINE_SOUNDS_PROCESS_IN_BACKGROUND).toBool();
235 : }
236 :
237 0 : void AudioConfiguration::setAutoProcessOnlineSoundsInBackground(bool value)
238 : {
239 0 : settings()->setSharedValue(ONLINE_SOUNDS_PROCESS_IN_BACKGROUND, Val(value));
240 :
241 0 : onEngineConfigChanged();
242 0 : }
243 :
244 0 : async::Channel<bool> AudioConfiguration::autoProcessOnlineSoundsInBackgroundChanged() const
245 : {
246 0 : return m_autoProcessOnlineSoundsInBackgroundChanged;
247 : }
248 :
249 0 : bool AudioConfiguration::useSoundFontLowPassFilter() const
250 : {
251 0 : return settings()->value(USE_SOUNDFONT_LOWPASS_FILTER).toBool();
252 : }
253 :
254 0 : void AudioConfiguration::setUseSoundFontLowPassFilter(bool value)
255 : {
256 0 : settings()->setSharedValue(USE_SOUNDFONT_LOWPASS_FILTER, Val(value));
257 :
258 0 : onEngineConfigChanged();
259 0 : }
260 :
261 0 : async::Channel<bool> AudioConfiguration::useSoundFontLowPassFilterChanged() const
262 : {
263 0 : return m_useSoundFontLowPassFilterChanged;
264 : }
265 :
266 0 : bool AudioConfiguration::shouldMeasureInputLag() const
267 : {
268 0 : return settings()->value(AUDIO_MEASURE_INPUT_LAG).toBool();
269 : }
|