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 "enginecontroller.h"
23 :
24 : #include "global/modularity/ioc.h"
25 :
26 : #ifdef Q_OS_WIN
27 : #include "global/platform/win/waitabletimer.h"
28 : #endif
29 :
30 : #include "audio/common/audioutils.h"
31 : #include "audio/common/rpc/rpcpacker.h"
32 : #include "audio/common/audioerrors.h"
33 :
34 : #include "enginerpccontroller.h"
35 : #include "audioengine.h"
36 :
37 : #include "log.h"
38 :
39 : using namespace muse;
40 : using namespace muse::audio;
41 : using namespace muse::audio::engine;
42 : using namespace muse::audio::synth;
43 :
44 0 : EngineController::EngineController(std::shared_ptr<rpc::IRpcChannel> rpcChannel)
45 0 : : m_rpcChannel(rpcChannel)
46 : {
47 0 : m_rpcChannel->onRequest(rpc::GLOBAL_CTX_ID, rpc::MsgCode::EngineInit, [this](const rpc::Msg& msg) {
48 0 : OutputSpec spec;
49 0 : AudioEngineConfig conf;
50 :
51 0 : IF_ASSERT_FAILED(rpc::RpcPacker::unpack(msg.data, spec, conf)) {
52 0 : return make_response_ret(msg, make_ret(Err::InvalidRpcData));
53 : }
54 :
55 0 : init(spec, conf);
56 :
57 0 : return make_response_ret(msg, make_ok());
58 : });
59 :
60 0 : m_rpcChannel->onRequest(rpc::GLOBAL_CTX_ID, rpc::MsgCode::EngineDeinit, [this](const rpc::Msg& msg) {
61 0 : deinit();
62 0 : return make_response_ret(msg, make_ok());
63 : });
64 0 : }
65 :
66 0 : void EngineController::onStartRunning()
67 : {
68 0 : AudioEngine* aengine = dynamic_cast<AudioEngine*>(audioEngine().get());
69 0 : IF_ASSERT_FAILED(aengine) {
70 0 : return;
71 : }
72 :
73 : //! NOTE After sending a EngineRunning,
74 : //! we may receive RPC messages, such as for example load a soundfont.
75 : //! Therefore, we need to subscribe to RPC messages.
76 0 : m_rpcController = std::make_shared<EngineRpcController>(aengine);
77 0 : m_rpcController->init();
78 :
79 : //! NOTE We inform that the engine is running and can receive messages
80 : //! (it has not yet been initialized)
81 0 : m_rpcChannel->send(rpc::make_notification(rpc::GLOBAL_CTX_ID, rpc::MsgCode::EngineRunning));
82 : }
83 :
84 0 : void EngineController::init(const OutputSpec& outputSpec, const AudioEngineConfig& conf)
85 : {
86 : //! AUDIO THREAD
87 :
88 : //! NOTE These services are global, but EngineController is contextual...
89 : //! There are currently design issues, we need to figure out how to fix them.
90 0 : configuration()->setConfig(conf);
91 0 : synthResolver()->init(configuration()->defaultAudioInputParams(), outputSpec);
92 : // ------------------------------------------------------------
93 :
94 : // Setup audio engine
95 0 : audioEngine()->init(outputSpec);
96 :
97 0 : transportEventsDispatcher()->init();
98 0 : }
99 :
100 0 : void EngineController::deinit()
101 : {
102 : //! AUDIO THREAD
103 0 : m_rpcController->deinit();
104 0 : audioEngine()->deinit();
105 0 : }
106 :
107 0 : OutputSpec EngineController::outputSpec() const
108 : {
109 0 : return audioEngine()->outputSpec();
110 : }
111 :
112 0 : async::Channel<OutputSpec> EngineController::outputSpecChanged() const
113 : {
114 0 : return audioEngine()->outputSpecChanged();
115 : }
116 :
117 0 : void EngineController::process(float* stream, unsigned samplesPerChannel)
118 : {
119 0 : audioEngine()->process(stream, samplesPerChannel);
120 0 : }
|