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

ossia / score / 30317766880

28 Jul 2026 12:35AM UTC coverage: 15.321% (+0.02%) from 15.298%
30317766880

push

github

jcelerier
ci(wasm): ship the release asset with the binary uncompressed

e7a498a gzipped the binary because ci/wasm.deploy.sh pushes site/ into
the score-web git repository, which GitHub caps at 100 MiB. The release
bundle is zipped from that same site/, so the asset picked up the
compression too -- but release assets have no such limit, and
tools/create-app-wasm.sh needs the plain ossia-score.wasm.

Packaging a web app with --release continuous currently fails with
"cp: cannot stat .../ossia-score.wasm", exit 1.

The git push keeps the compressed binary. The loader picks its path
from the gzip magic rather than the file name, so either works.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VxtUwsfk4JN46WropbwfqC

30450 of 198751 relevant lines covered (15.32%)

997.54 hits per line

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

61.71
/src/plugins/score-plugin-engine/Engine/ApplicationPlugin.cpp
1
//// This is an open source non-commercial project. Dear PVS-Studio, please
2
/// check / it. PVS-Studio Static Code Analyzer for C, C++ and C#:
3
/// http://www.viva64.com
4
#include "ApplicationPlugin.hpp"
5

6
#include <Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp>
7
#include <Explorer/Settings/ExplorerModel.hpp>
8

9
#include <Scenario/Application/ScenarioActions.hpp>
10
#include <Scenario/Application/ScenarioApplicationPlugin.hpp>
11
#include <Scenario/Inspector/Interval/SpeedSlider.hpp>
12
#include <Scenario/Settings/ScenarioSettingsModel.hpp>
13

14
#include <Execution/DocumentPlugin.hpp>
15
#include <LocalTree/Device/LocalProtocolFactory.hpp>
16
#include <LocalTree/LocalTreeDocumentPlugin.hpp>
17

18
#include <score/actions/ActionManager.hpp>
19
#include <score/actions/ToolbarManager.hpp>
20
#include <score/plugins/documentdelegate/plugin/DocumentPluginCreator.hpp>
21
#include <score/tools/Bind.hpp>
22
#include <score/widgets/HelpInteraction.hpp>
23
#include <score/widgets/SetIcons.hpp>
24
#include <score/widgets/TimeSpinBox.hpp>
25

26
#include <Process/ApplicationPlugin.hpp>
27
#include <core/application/ApplicationInterface.hpp>
28
#include <core/application/ApplicationSettings.hpp>
29
#include <core/presenter/DocumentManager.hpp>
30

31
#include <ossia-qt/invoke.hpp>
32

33
#include <QCommandLineParser>
34
#include <QLabel>
35
#include <QMainWindow>
36
#include <QTabWidget>
37
#include <QTimer>
38
#include <QToolBar>
39

40
#include <wobjectimpl.h>
41

42
namespace Engine
43
{
44
ApplicationPlugin::ApplicationPlugin(const score::GUIApplicationContext& ctx)
36✔
45
    : score::GUIApplicationPlugin{ctx}
36✔
46
    , m_playActions{*this, ctx}
47
    , m_execution{ctx}
48
{
36✔
49
  if(ctx.applicationSettings.gui)
36✔
50
  {
51
    auto& ctrl = ctx
36✔
52
            .applicationPlugin<Process::ApplicationPlugin>();
36✔
53
    m_playActions.setupContextMenu(ctrl.layerContextMenuRegistrar());
36✔
54
  }
36✔
55

56
  {
57
    // Command-line options for the local device tree default ports.
58
    // CLI flag wins, then $SCORE_LOCAL_{OSC,WS}_PORT, then 6666 / 9999.
59
    QCommandLineParser parser;
36✔
60

61
    QCommandLineOption osc_port_opt(
36✔
62
        "local-osc-port",
36✔
63
        QCoreApplication::translate("engine", "Local device tree OSC port"), "port");
36✔
64
    parser.addOption(osc_port_opt);
36✔
65
    QCommandLineOption ws_port_opt(
36✔
66
        "local-ws-port",
36✔
67
        QCoreApplication::translate("engine", "Local device tree WebSocket port"),
36✔
68
        "port");
36✔
69
    parser.addOption(ws_port_opt);
36✔
70

71
    parser.parse(ctx.applicationSettings.arguments);
36✔
72

73
    using Protocols::LocalProtocolFactory;
74
    if(parser.isSet(osc_port_opt))
36✔
75
      LocalProtocolFactory::defaultOscPort = parser.value(osc_port_opt).toInt();
×
76
    else if(qEnvironmentVariableIsSet("SCORE_LOCAL_OSC_PORT"))
36✔
77
      LocalProtocolFactory::defaultOscPort
×
78
          = qEnvironmentVariableIntValue("SCORE_LOCAL_OSC_PORT");
×
79

80
    if(parser.isSet(ws_port_opt))
36✔
81
      LocalProtocolFactory::defaultWsPort = parser.value(ws_port_opt).toInt();
×
82
    else if(qEnvironmentVariableIsSet("SCORE_LOCAL_WS_PORT"))
36✔
83
      LocalProtocolFactory::defaultWsPort
×
84
          = qEnvironmentVariableIntValue("SCORE_LOCAL_WS_PORT");
×
85
  }
36✔
86
}
×
87

88
ApplicationPlugin::~ApplicationPlugin()
72✔
89
{
36✔
90
  // The scenarios playing should already have been stopped by virtue of
91
  // aboutToClose.
92
}
72✔
93

94
void ApplicationPlugin::afterStartup()
×
95
{
96
  if(!context.documents.documents().empty())
×
97
  {
98
    if(context.applicationSettings.autoplay)
×
99
    {
100
      // TODO what happens if we load multiple documents ?
101
      QTimer::singleShot(
×
102
          (1 + context.applicationSettings.waitAfterLoad) * 1000, &m_execution,
×
103
          [this] { m_execution.request_play_local(true); });
×
104
    }
×
105
  }
×
106
}
×
107

108
void ApplicationPlugin::initialize()
36✔
109
{
110
  // Update the clock widget
111
  // See TransportActions::makeGUIElements
112
  auto& toolbars = this->context.toolbars.get();
36✔
113
  auto transport_toolbar = toolbars.find(StringKey<score::Toolbar>("Transport"));
36✔
114
  if(transport_toolbar != toolbars.end())
36✔
115
  {
116
    const auto& tb = transport_toolbar->second.toolbar();
36✔
117
    if(tb)
36✔
118
    {
119
      auto cld = tb->children();
36✔
120
      if(!cld.empty())
36✔
121
      {
122
        auto label = tb->findChild<QLabel*>("TimeLabel");
36✔
123
        if(label)
36✔
124
          setupTimingWidget(label);
36✔
125

126
        m_speedSlider = dynamic_cast<Scenario::SpeedWidget*>(cld.back());
36✔
127
      }
36✔
128
    }
36✔
129
  }
36✔
130

131
  if(m_musicalAct)
36✔
132
  {
133
    auto& settings = this->context.settings<Scenario::Settings::Model>();
36✔
134
    m_musicalAct->setChecked(settings.getMeasureBars());
36✔
135

136
    score::setGlobalTimeMode(
36✔
137
        settings.getMeasureBars() ? score::TimeMode::Bars : score::TimeMode::Seconds);
36✔
138

139
    connect(m_musicalAct, &QAction::toggled, this, [this](bool ok) {
36✔
140
      auto& settings = this->context.settings<Scenario::Settings::Model>();
×
141
      settings.setMeasureBars(ok);
×
142
      settings.setMagneticMeasures(ok);
×
143
      score::setGlobalTimeMode(ok ? score::TimeMode::Bars : score::TimeMode::Seconds);
×
144

145
      //if (auto doc = this->currentDocument())
146
      //{
147
      //  auto& mod = doc->model().modelDelegate();
148
      //  auto scenar = dynamic_cast<Scenario::ScenarioDocumentModel*>(&mod);
149
      //  if (scenar)
150
      //  {
151
      //    auto& itv = scenar->baseInterval();
152
      //    itv.setHasTimeSignature(ok);
153
      //  }
154
      //}
155
    });
×
156
  }
36✔
157

158
  m_execution.init_transport();
36✔
159
}
36✔
160

161
QWidget* ApplicationPlugin::setupTimingWidget(QLabel* time_label)
36✔
162
{
163
  score::setHelp(time_label, tr("Elapsed time since the beginning of playback"));
36✔
164

165
  auto c = connect(
36✔
166
      &execution_ui_clock_timer, &QTimer::timeout, time_label, [this, time_label] {
79✔
167
    auto t = m_execution.execution_time();
43✔
168
    if(t == TimeVal::zero())
43✔
169
    {
170
      time_label->setText(QStringLiteral("00:00:00.000"));
43✔
171
    }
43✔
172
    else
173
    {
174
      const double one_hour_in_ms = 3600 * 1000;
×
175
      const double one_minute_in_ms = 60000;
×
176
      const double one_second_in_ms = 1000;
×
177
      int64_t ms = t.impl / ossia::flicks_per_millisecond<double>;
×
178
      int64_t hours = ms / one_hour_in_ms;
×
179
      ms -= hours * one_hour_in_ms;
×
180
      int64_t minutes = ms / one_minute_in_ms;
×
181
      ms -= minutes * one_minute_in_ms;
×
182
      int64_t seconds = ms / one_second_in_ms;
×
183
      ms -= seconds * one_second_in_ms;
×
184

185
      time_label->setText(QStringLiteral("%1:%2:%3.%4")
×
186
                              .arg(hours, 2, 10, QLatin1Char('0'))
×
187
                              .arg(minutes, 2, 10, QLatin1Char('0'))
×
188
                              .arg(seconds, 2, 10, QLatin1Char('0'))
×
189
                              .arg(ms, 3, 10, QLatin1Char('0')));
×
190
    }
191
  });
43✔
192
  execution_ui_clock_timer.start(1000 / 20);
36✔
193
  return time_label;
36✔
194
}
36✔
195

196
score::GUIElements ApplicationPlugin::makeGUIElements()
36✔
197
{
198
  GUIElements e;
36✔
199

200
  auto& toolbars = e.toolbars;
36✔
201

202
  toolbars.reserve(4);
36✔
203

204
  // The toolbar with the interval controls
205
  {
206
    auto ui_toolbar = new QToolBar(tr("Interval"));
36✔
207
    toolbars.emplace_back(
72✔
208
        ui_toolbar, StringKey<score::Toolbar>("UISetup"), Qt::BottomToolBarArea, 10);
36✔
209

210
    {
211
      auto timeline_act = new QAction{tr("Timeline interval"), ui_toolbar};
36✔
212
      timeline_act->setCheckable(true);
36✔
213
      timeline_act->setChecked(false);
36✔
214
      timeline_act->setShortcut(QKeySequence("Ctrl+Alt+N"));
36✔
215
      score::setHelp(timeline_act, tr("Change between nodal and timeline mode"));
36✔
216
      setIcons(
36✔
217
          timeline_act, QStringLiteral(":/icons/nodal_on.png"),
36✔
218
          QStringLiteral(":/icons/nodal_hover.png"),
36✔
219
          QStringLiteral(":/icons/nodal_on.png"),
36✔
220
          QStringLiteral(":/icons/nodal_disabled.png"));
36✔
221

222
      connect(timeline_act, &QAction::toggled, this, [timeline_act](bool checked) {
41✔
223
        if(!checked)
5✔
224
        {
225
          setIcons(
×
226
              timeline_act, QStringLiteral(":/icons/timeline_on.png"),
×
227
              QStringLiteral(":/icons/timeline_hover.png"),
×
228
              QStringLiteral(":/icons/timeline_on.png"),
×
229
              QStringLiteral(":/icons/timeline_disabled.png"));
×
230
        }
×
231
        else
232
        {
233
          setIcons(
5✔
234
              timeline_act, QStringLiteral(":/icons/nodal_on.png"),
5✔
235
              QStringLiteral(":/icons/nodal_hover.png"),
5✔
236
              QStringLiteral(":/icons/nodal_on.png"),
5✔
237
              QStringLiteral(":/icons/nodal_disabled.png"));
5✔
238
        }
239
      });
5✔
240
      ui_toolbar->addAction(timeline_act);
36✔
241
    }
242

243
    {
244
      m_musicalAct = new QAction{tr("Enable musical mode"), this};
36✔
245
      m_musicalAct->setCheckable(true);
36✔
246
      score::setHelp(m_musicalAct, tr("Enable musical mode"));
36✔
247
      setIcons(
36✔
248
          m_musicalAct, QStringLiteral(":/icons/music_on.png"),
36✔
249
          QStringLiteral(":/icons/music_hover.png"),
36✔
250
          QStringLiteral(":/icons/music_off.png"),
36✔
251
          QStringLiteral(":/icons/music_disabled.png"));
36✔
252

253
      ui_toolbar->addAction(m_musicalAct);
36✔
254
    }
255

256
    {
257
      auto show_cables_act = context.actions.action<Actions::ShowCables>();
36✔
258
      ui_toolbar->addAction(show_cables_act.action());
36✔
259
    }
36✔
260
  }
261

262
  return e;
36✔
263
}
36✔
264

265
void ApplicationPlugin::on_initDocument(score::Document& doc)
20✔
266
{
267
  score::addDocumentPlugin<LocalTree::DocumentPlugin>(doc);
20✔
268
}
20✔
269

270
void ApplicationPlugin::on_createdDocument(score::Document& doc)
20✔
271
{
272
  LocalTree::DocumentPlugin* lt = doc.context().findPlugin<LocalTree::DocumentPlugin>();
20✔
273
  if(lt)
20✔
274
  {
275
    lt->init();
20✔
276
    initLocalTreeNodes(*lt);
20✔
277
  }
20✔
278
  score::addDocumentPlugin<Execution::DocumentPlugin>(doc);
20✔
279
}
20✔
280

281
void ApplicationPlugin::on_documentChanged(
39✔
282
    score::Document* olddoc, score::Document* newdoc)
283
{
284
  if(olddoc)
39✔
285
  {
286
    // Disable the local tree for this document by removing
287
    // the node temporarily
288
    /*
289
    auto& doc_plugin = olddoc->context().plugin<DeviceDocumentPlugin>();
290
    doc_plugin.setConnection(false);
291
    */
292

293
    if(m_speedSlider)
20✔
294
      m_speedSlider->unsetInterval();
20✔
295
    // TODO check whether the widget gets deleted
296
  }
20✔
297

298
  if(newdoc)
39✔
299
  {
300
    // Enable the local tree for this document.
301

302
    /*
303
    auto& doc_plugin = newdoc->context().plugin<DeviceDocumentPlugin>();
304
    doc_plugin.setConnection(true);
305
    */
306

307
    // Setup speed toolbar
308
    auto& root = score::IDocument::get<Scenario::ScenarioDocumentModel>(*newdoc);
20✔
309

310
    if(context.applicationSettings.gui)
20✔
311
    {
312
      if(m_speedSlider)
20✔
313
        m_speedSlider->setInterval(root.baseInterval());
20✔
314
    }
20✔
315

316
    // Setup audio & devices
317
    auto& doc_plugin = newdoc->context().plugin<Explorer::DeviceDocumentPlugin>();
20✔
318
    auto* set = newdoc->context().findPlugin<Explorer::ProjectSettings::Model>();
20✔
319
    if(set)
20✔
320
    {
321
      if(set->getReconnectOnStart())
20✔
322
      {
323
        auto& list = doc_plugin.list();
×
324
        list.apply([&](Device::DeviceInterface& dev) {
×
325
          if(&dev != list.audioDevice() && &dev != list.localDevice())
×
326
            dev.reconnect();
×
327
        });
×
328

329
        if(set->getRefreshOnStart())
×
330
        {
331
          list.apply([&](Device::DeviceInterface& dev) {
×
332
            if(&dev != list.audioDevice() && &dev != list.localDevice())
×
333
              if(dev.connected())
×
334
              {
335
                auto old_name = dev.name();
×
336
                auto new_node = dev.refresh();
×
337

338
                auto& explorer = doc_plugin.explorer();
×
339
                const auto& cld = explorer.rootNode().children();
×
340
                for(auto it = cld.begin(); it != cld.end(); ++it)
×
341
                {
342
                  auto ds = it->get<Device::DeviceSettings>();
×
343
                  if(ds.name == old_name)
×
344
                  {
345
                    explorer.removeNode(it);
×
346
                    break;
×
347
                  }
348
                }
×
349

350
                explorer.addDevice(std::move(new_node));
×
351
              }
×
352
          });
×
353
        }
×
354
      }
×
355
    }
20✔
356
  }
20✔
357
}
39✔
358

359
void ApplicationPlugin::prepareNewDocument()
27✔
360
{
361
  execution().request_stop();
27✔
362
  // TODO what if JACK is stuck? force-stop after some time ?
363
}
27✔
364

365
void ApplicationPlugin::initLocalTreeNodes(LocalTree::DocumentPlugin& lt)
20✔
366
{
367
  auto& appplug = *this;
20✔
368
  auto& root = lt.device().get_root_node();
20✔
369

370
  {
371
    auto n = root.create_child("running");
20✔
372
    auto p = n->create_parameter(ossia::val_type::BOOL);
20✔
373
    p->set_value(false);
20✔
374
    p->set_access(ossia::access_mode::GET);
20✔
375

376
    if(context.applicationSettings.gui)
20✔
377
    {
378
      auto& play_action = appplug.context.actions.action<Actions::Play>();
20✔
379
      connect(
20✔
380
          play_action.action(), &QAction::toggled, &lt, [p] { p->push_value(true); });
20✔
381

382
      auto& stop_action = context.actions.action<Actions::Stop>();
20✔
383
      connect(
20✔
384
          stop_action.action(), &QAction::toggled, &lt, [p] { p->push_value(false); });
20✔
385
    }
20✔
386
  }
387
  {
388
    auto local_play_node = root.create_child("play");
20✔
389
    auto local_play_address = local_play_node->create_parameter(ossia::val_type::BOOL);
20✔
390
    local_play_address->set_value(bool{false});
20✔
391
    local_play_address->set_access(ossia::access_mode::SET);
20✔
392
    local_play_address->add_callback([&](const ossia::value& v) {
20✔
393
      ossia::qt::run_async(this, [this, v] {
×
394
        if(auto val = v.target<bool>())
×
395
        {
396
          execution().request_play_from_localtree(*val);
×
397
        }
×
398
      });
×
399
    });
×
400
  }
401

402
  {
403
    auto local_play_node = root.create_child("global_play");
20✔
404
    auto local_play_address = local_play_node->create_parameter(ossia::val_type::BOOL);
20✔
405
    local_play_address->set_value(bool{false});
20✔
406
    local_play_address->set_access(ossia::access_mode::SET);
20✔
407
    local_play_address->add_callback([&](const ossia::value& v) {
20✔
408
      ossia::qt::run_async(this, [this, v] {
×
409
        if(auto val = v.target<bool>())
×
410
        {
411
          execution().request_play_global_from_localtree(*val);
×
412
        }
×
413
      });
×
414
    });
×
415
  }
416

417
  {
418
    auto local_transport_node = root.create_child("transport");
20✔
419
    auto local_transport_address
20✔
420
        = local_transport_node->create_parameter(ossia::val_type::FLOAT);
20✔
421
    local_transport_address->set_value(bool{false});
20✔
422
    local_transport_address->set_access(ossia::access_mode::SET);
20✔
423
    local_transport_address->set_unit(ossia::millisecond_u{});
20✔
424
    local_transport_address->add_callback([&](const ossia::value& v) {
20✔
425
      ossia::qt::run_async(this, [this, v] {
×
426
        execution().request_transport_from_localtree(
×
427
            TimeVal::fromMsecs(ossia::convert<float>(v)));
×
428
      });
×
429
    });
×
430
  }
431

432
  {
433
    auto local_stop_node = root.create_child("stop");
20✔
434
    auto local_stop_address
20✔
435
        = local_stop_node->create_parameter(ossia::val_type::IMPULSE);
20✔
436
    local_stop_address->set_value(ossia::impulse{});
20✔
437
    local_stop_address->set_access(ossia::access_mode::SET);
20✔
438
    local_stop_address->add_callback([&](const ossia::value&) {
20✔
439
      ossia::qt::run_async(this, [this] { execution().request_stop_from_localtree(); });
×
440
    });
×
441
  }
442

443
  {
444
    auto local_stop_node = root.create_child("reinit");
20✔
445
    auto local_stop_address
20✔
446
        = local_stop_node->create_parameter(ossia::val_type::IMPULSE);
20✔
447
    local_stop_address->set_value(ossia::impulse{});
20✔
448
    local_stop_address->set_access(ossia::access_mode::SET);
20✔
449
    local_stop_address->add_callback([&](const ossia::value&) {
20✔
450
      ossia::qt::run_async(
×
451
          this, [this] { execution().request_reinitialize_from_localtree(); });
×
452
    });
×
453
  }
454
  {
455
    auto node = root.create_child("exit");
20✔
456
    auto address = node->create_parameter(ossia::val_type::STRING);
20✔
457
    address->set_value(std::string{});
20✔
458
    address->set_access(ossia::access_mode::SET);
20✔
459
    address->add_callback([&](const ossia::value& v) {
20✔
460
      bool force = ossia::convert<std::string>(v) == "force";
×
461
      ossia::qt::run_async(this, [this, force] {
×
462
        execution().request_stop_from_localtree();
×
463

464
        QTimer::singleShot(500, [force] {
×
465
          if(force)
×
466
          {
467
            for(auto& doc : score::GUIAppContext().docManager.documents())
×
468
            {
469
              doc->commandStack().markCurrentIndexAsSaved();
×
470
            }
471
          }
×
472

473
          score::GUIApplicationInterface::instance().forceExit();
×
474
        });
×
475
      });
×
476
    });
×
477
  }
478

479
  {
480
    auto node = root.create_child("document");
20✔
481
    auto address = node->create_parameter(ossia::val_type::INT);
20✔
482
    address->set_value(0);
20✔
483
    address->set_access(ossia::access_mode::BI);
20✔
484
    address->add_callback([&](const ossia::value& v) {
20✔
485
      int val = v.get<int>();
×
486
      ossia::qt::run_async(this, [this, val] {
×
487
        if(context.applicationSettings.gui)
×
488
        {
489
          QTabWidget* docs = context.mainWindow->centralWidget()->findChild<QTabWidget*>(
×
490
              "Documents", Qt::FindDirectChildrenOnly);
×
491
          SCORE_ASSERT(docs);
×
492
          if(docs)
×
493
          {
494
            docs->setCurrentIndex(std::clamp(val, 0, docs->count() - 1));
×
495
          }
×
496
        }
×
497
      });
×
498
    });
×
499
  }
500

501
  {
502
    auto node = root.create_child("reconnect");
20✔
503
    auto address = node->create_parameter(ossia::val_type::STRING);
20✔
504
    address->set_value("");
20✔
505
    address->set_access(ossia::access_mode::BI);
20✔
506
    address->add_callback([&](const ossia::value& v) {
20✔
507
      auto val = QString::fromStdString(v.get<std::string>());
×
508
      ossia::qt::run_async(this, [this, device = std::move(val)] {
×
509
        auto doc = currentDocument();
×
510
        if(!doc)
×
511
          return;
×
512

513
        auto& plug = doc->context().plugin<Explorer::DeviceDocumentPlugin>();
×
514
        plug.reconnect(device);
×
515
      });
×
516
    });
×
517
  }
518
// FIXME
519
#if 0
520
  {
521
    auto settings = root.create_child("settings");
522
    auto audio = settings->create_child("audio");
523
    {
524
      {
525
        auto node = audio->create_child("backend");
526
        auto address = node->create_parameter(ossia::val_type::STRING);
527
        address->add_callback([&](const ossia::value& v) {
528
          QString val = QString::fromStdString(v.get<std::string>());
529
          ossia::qt::run_async(this, [this, val] {
530
            auto& set = score::AppContext().settings<Audio::Settings::Model>();
531
          });
532
        });
533
      }
534

535
      {
536
        auto node = audio->create_child("buffer_size");
537
        auto address = node->create_parameter(ossia::val_type::INT);
538
        address->add_callback([&](const ossia::value& v) {
539
          int val = v.get<int>();
540
          ossia::qt::run_async(this, [this, val] {
541
            auto& set = score::AppContext().settings<Audio::Settings::Model>();
542
            set.setBufferSize(val);
543
          });
544
        });
545
      }
546

547
      {
548
        auto node = audio->create_child("rate");
549
        auto address = node->create_parameter(ossia::val_type::INT);
550
        address->add_callback([&](const ossia::value& v) {
551
          int val = v.get<int>();
552
          ossia::qt::run_async(this, [this, val] {
553
            auto& set = score::AppContext().settings<Audio::Settings::Model>();
554
            set.setRate(val);
555
          });
556
        });
557
      }
558
    }
559
  }
560
#endif
561
}
20✔
562
}
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