• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / score / 30826105710

03 Aug 2026 03:08PM UTC coverage: 15.264%. Remained the same
30826105710

Pull #1975

github

web-flow
Merge a8c35e79e into 192676568
Pull Request #1975: audio: add a native ASIO backend on Windows

1 of 15 new or added lines in 3 files covered. (6.67%)

30464 of 199583 relevant lines covered (15.26%)

1075.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/src/plugins/score-plugin-audio/Audio/Settings/Model.cpp
1
#include <Audio/DummyInterface.hpp>
2
#include <Audio/Settings/Model.hpp>
3

4
#include <score/application/GUIApplicationContext.hpp>
5

6
#include <optional>
7
namespace Audio::Settings
8
{
9
namespace Parameters
10
{
11
// portaudio is the default
12
SETTINGS_PARAMETER_IMPL(Driver)
37✔
13
{
37✔
14
  QStringLiteral("Audio/Driver"),
37✔
15
#if defined(_WIN32)
16
      Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
17
          "2838b52b-9c0c-466e-a2b0-8c6d8cb8fc6d")} // WASAPI (miniaudio)
18
#elif defined(__APPLE__)
19
    Audio::AudioFactory::ConcreteKey{
20
        score::uuids::string_generator::compute("85115103-694a-4a3b-9274-76ef47aec5a9")}
21
#elif defined(__linux__)
22
      Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
37✔
23
          "687d49cf-b58d-430f-8358-ec02cb50be36")} // PipeWire
24
#elif defined(__EMSCRIPTEN__)
25
      Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
26
          "a2e8b688-521c-4755-b0b2-4e3d01807b8e")} // Web Audio (MiniAudio)
27
#else
28
      Audio::AudioFactory::ConcreteKey
29
  {
30
    score::uuids::string_generator::compute("e7543875-3b22-457c-bf41-75504637686f")
31
  }
32
#endif
33
};
34
SETTINGS_PARAMETER_IMPL(InputNames){QStringLiteral("Audio/InputNames"), {}};
37✔
35
SETTINGS_PARAMETER_IMPL(OutputNames){QStringLiteral("Audio/OutputNames"), {}};
37✔
36
SETTINGS_PARAMETER_IMPL(CardIn){QStringLiteral("Audio/CardIn"), ""};
37✔
37
SETTINGS_PARAMETER_IMPL(CardOut){QStringLiteral("Audio/CardOut"), ""};
37✔
38
SETTINGS_PARAMETER_IMPL(BufferSize){QStringLiteral("Audio/BufferSize"), 512};
37✔
39
SETTINGS_PARAMETER_IMPL(Rate){QStringLiteral("Audio/SamplingRate"), 44100};
37✔
40
SETTINGS_PARAMETER_IMPL(DefaultIn){QStringLiteral("Audio/DefaultIn"), 2};
37✔
41
SETTINGS_PARAMETER_IMPL(DefaultOut){QStringLiteral("Audio/DefaultOut"), 2};
37✔
42
SETTINGS_PARAMETER_IMPL(AutoStereo){QStringLiteral("Audio/AutoStereo"), true};
37✔
43
SETTINGS_PARAMETER_IMPL(AutoConnect){QStringLiteral("Audio/AutoConnect"), true};
37✔
44
SETTINGS_PARAMETER_IMPL(JackTransport){
37✔
45
    QStringLiteral("Audio/JackTransport"), ExternalTransport::None};
37✔
46

47
static auto list()
39✔
48
{
49
  return std::tie(
39✔
50
      Rate, InputNames, OutputNames, CardIn, CardOut, BufferSize, DefaultIn, DefaultOut,
51
      AutoStereo, AutoConnect, JackTransport, Driver);
52
}
53
}
54

55
// Maps the SCORE_AUDIO_BACKEND environment variable to a concrete driver key.
56
// Used both at startup (so headless/CI/test runs can force a backend such as
57
// "dummy") and from the settings GUI. Returns std::nullopt when the variable is
58
// unset or unrecognized.
59
static std::optional<Audio::AudioFactory::ConcreteKey> driverFromEnv()
78✔
60
{
61
  auto env = qEnvironmentVariable("SCORE_AUDIO_BACKEND").toLower();
78✔
62
  if(env.isEmpty())
78✔
63
    return std::nullopt;
×
64

65
  QByteArray uid;
78✔
66
  if(env == "dummy")
78✔
67
    uid = "13dabcc3-9cda-422f-a8c7-5fef5c220677";
78✔
68
  else if(env == "jack")
×
69
    uid = "7ff2af00-f2f5-4930-beec-0e2d21eda195";
×
70
  else if(env == "sdl")
×
71
    uid = "28b88e91-c5f0-4f13-834f-aa333d14aa81";
×
72
  else if(env == "pipewire")
×
73
    uid = "687d49cf-b58d-430f-8358-ec02cb50be36";
×
74
  else if(env == "coreaudio")
×
75
    uid = "85115103-694a-4a3b-9274-76ef47aec5a9";
×
76
  else if(env == "alsa")
×
77
    uid = "a390218a-a951-4cda-b4ee-c41d2df44236";
×
78
  else if(env == "alsa_portaudio")
×
79
    uid = "3533ee88-9a8d-486c-b20b-6c966cf4eaa0";
×
80
  else if(env == "alsa_miniaudio")
×
81
    uid = "e0c533da-a1f4-4795-90b5-a805cdfcb79f";
×
82
  else if(env == "wasapi_miniaudio")
×
83
    uid = "2838b52b-9c0c-466e-a2b0-8c6d8cb8fc6d";
×
NEW
84
  else if(env == "asio")
×
NEW
85
    uid = "2d21a3aa-f108-4e05-a3a0-8fd6b150bda5";
×
86

87
  if(uid.isEmpty())
78✔
88
    return std::nullopt;
×
89

90
  const char* data = uid.data();
78✔
91
  using uid_t = const char(&)[37];
92
  return Audio::AudioFactory::ConcreteKey{
78✔
93
      score::uuids::string_generator::compute((uid_t)*data)};
78✔
94
}
78✔
95

96
Model::Model(
39✔
97
    const UuidKey<score::SettingsDelegateFactory>& k, QSettings& set,
98
    const score::ApplicationContext& ctx)
99
    : score::SettingsDelegateModel{k, nullptr}
39✔
100
{
39✔
101
  score::setupDefaultSettings(set, Parameters::list(), *this);
39✔
102
  using namespace std::literals;
103
  if(m_Driver
78✔
104
     == Audio::AudioFactory::ConcreteKey::fromString(
39✔
105
         "85115103-694a-4a3b-9274-76ef47aec5a9"s))
39✔
106
  {
107
    m_Driver = Parameters::Driver.def;
×
108
  }
×
109

110
  // Allow forcing the audio backend at startup, e.g. SCORE_AUDIO_BACKEND=dummy
111
  // for headless / CI / test runs.
112
  if(auto k = driverFromEnv())
39✔
113
    m_Driver = *k;
39✔
114
}
×
115

116
Audio::AudioFactory::ConcreteKey Model::getDriver() const
98✔
117
{
118
  return m_Driver;
98✔
119
}
120

121
void Model::initDriver(Audio::AudioFactory::ConcreteKey val)
39✔
122
{
123
  if(auto k = driverFromEnv())
39✔
124
    val = *k;
39✔
125

126
  // Reset to default in case of invalid parameters.
127
  auto& ctx = score::AppContext();
39✔
128
  auto& factories = ctx.interfaces<AudioFactoryList>();
39✔
129
  auto iface = factories.get(val);
39✔
130
  if(!iface)
39✔
131
  {
132
    val = Parameters::Driver.def;
×
133
    iface = factories.get(val);
×
134
    if(!iface)
×
135
    {
136
      val = DummyFactory::static_concreteKey();
×
137
      iface = factories.get(val);
×
138
    }
×
139
  }
×
140

141
  if(val == m_Driver)
39✔
142
    return;
×
143

144
  m_Driver = val;
39✔
145

146
  // SDL
147
  if(m_Driver
78✔
148
     == Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
39✔
149
         "28b88e91-c5f0-4f13-834f-aa333d14aa81")})
150
  {
151
    if(m_Rate != 48000)
×
152
    {
153
      m_Rate = 48000;
×
154
      RateChanged(m_Rate);
×
155
    }
×
156
    if(m_BufferSize != 1024)
×
157
    {
158
      m_BufferSize = 1024;
×
159
      BufferSizeChanged(m_BufferSize);
×
160
    }
×
161
  }
×
162

163
#if !defined(__EMSCRIPTEN__)
164
  // Special case for dummy driver: set reasonable values
165
  if(m_Driver
78✔
166
     == Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
39✔
167
         "13dabcc3-9cda-422f-a8c7-5fef5c220677")})
168
  {
169
    if(m_Rate < 1 || m_Rate > 48 * 384000)
39✔
170
    {
171
      m_Rate = 44100;
×
172
      RateChanged(m_Rate);
×
173
    }
×
174
    if(m_BufferSize < 1 || m_BufferSize > 32768 * 8)
39✔
175
    {
176
      m_BufferSize = 128;
×
177
      BufferSizeChanged(m_BufferSize);
×
178
    }
×
179
  }
39✔
180
#endif
181
  iface->initialize(*this, ctx);
39✔
182
}
39✔
183
void Model::setDriver(Audio::AudioFactory::ConcreteKey val)
×
184
{
185
  // Reset to default in case of invalid parameters.
186
  auto& ctx = score::AppContext();
×
187
  auto& factories = ctx.interfaces<AudioFactoryList>();
×
188
  auto iface = factories.get(val);
×
189
  if(!iface)
×
190
  {
191
    val = Parameters::Driver.def;
×
192
    iface = factories.get(val);
×
193
    if(!iface)
×
194
    {
195
      val = DummyFactory::static_concreteKey();
×
196
      iface = factories.get(val);
×
197
    }
×
198
  }
×
199

200
  if(val == m_Driver)
×
201
    return;
×
202

203
  m_Driver = val;
×
204

205
  // SDL
206
  if(m_Driver
×
207
     == Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
×
208
         "28b88e91-c5f0-4f13-834f-aa333d14aa81")})
209
  {
210
    setRate(48000);
×
211
    setBufferSize(1024);
×
212
  }
×
213

214
#if !defined(__EMSCRIPTEN__)
215
  QSettings s;
×
216
  s.setValue(Parameters::Driver.key, QVariant::fromValue(m_Driver));
×
217

218
  // Special case for dummy driver: set reasonable values
219
  if(m_Driver
×
220
     == Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
×
221
         "13dabcc3-9cda-422f-a8c7-5fef5c220677")})
222
  {
223
    m_Rate = 44100;
×
224
    s.setValue(Parameters::Rate.key, QVariant::fromValue(m_Rate));
×
225

226
    m_BufferSize = 1024;
×
227
    s.setValue(Parameters::BufferSize.key, QVariant::fromValue(m_BufferSize));
×
228
  }
×
229
#endif
230
  iface->initialize(*this, ctx);
×
231
}
×
232

233
int Model::getRate() const
164✔
234
{
235
  return m_Rate;
164✔
236
}
237

238
void Model::initRate(int val)
39✔
239
{
240
  if(val <= 0)
39✔
241
    val = 44100;
×
242
  if(val == m_Rate)
39✔
243
    return;
×
244

245
  m_Rate = val;
39✔
246
}
39✔
247

248
void Model::setRate(int val)
20✔
249
{
250
  if(val <= 0)
20✔
251
    val = 44100;
×
252
  if(val == m_Rate)
20✔
253
    return;
20✔
254

255
  m_Rate = val;
×
256

257
#if !defined(__EMSCRIPTEN__)
258
  QSettings s;
×
259
  s.setValue(Parameters::Rate.key, QVariant::fromValue(m_Rate));
×
260
#endif
261
  RateChanged(val);
×
262
}
20✔
263

264
int Model::getBufferSize() const
60✔
265
{
266
  return m_BufferSize;
60✔
267
}
268

269
void Model::initBufferSize(int val)
39✔
270
{
271
  if(val <= 0)
39✔
272
    val = 512;
×
273
  if(val == m_BufferSize)
39✔
274
    return;
×
275

276
  m_BufferSize = val;
39✔
277
}
39✔
278

279
void Model::setBufferSize(int val)
20✔
280
{
281
  if(val <= 0)
20✔
282
    val = 512;
×
283
  if(val == m_BufferSize)
20✔
284
    return;
20✔
285

286
  m_BufferSize = val;
×
287

288
#if !defined(__EMSCRIPTEN__)
289
  QSettings s;
×
290
  s.setValue(Parameters::BufferSize.key, QVariant::fromValue(m_BufferSize));
×
291
#endif
292
  BufferSizeChanged(val);
×
293
}
20✔
294

295
SCORE_SETTINGS_PARAMETER_CPP(QStringList, Model, InputNames)
39✔
296
SCORE_SETTINGS_PARAMETER_CPP(QStringList, Model, OutputNames)
39✔
297
SCORE_SETTINGS_PARAMETER_CPP(QString, Model, CardIn)
39✔
298
SCORE_SETTINGS_PARAMETER_CPP(QString, Model, CardOut)
39✔
299
SCORE_SETTINGS_PARAMETER_CPP(int, Model, DefaultIn)
39✔
300
SCORE_SETTINGS_PARAMETER_CPP(int, Model, DefaultOut)
39✔
301
SCORE_SETTINGS_PARAMETER_CPP(bool, Model, AutoStereo)
39✔
302
SCORE_SETTINGS_PARAMETER_CPP(bool, Model, AutoConnect)
39✔
303
SCORE_SETTINGS_PARAMETER_CPP(Audio::Settings::ExternalTransport, Model, JackTransport)
39✔
304
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc