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 :
23 : #include "eventaudionode.h"
24 :
25 : #include "audio/common/audiosanitizer.h"
26 :
27 : #include "log.h"
28 :
29 : using namespace muse;
30 : using namespace muse::audio;
31 : using namespace muse::audio::engine;
32 : using namespace muse::audio::synth;
33 : using namespace muse::mpe;
34 :
35 0 : EventAudioNode::EventAudioNode(TrackId trackId, const mpe::PlaybackData& playbackData,
36 0 : OnOffStreamEventsReceived onOffStreamReceived)
37 0 : : m_trackId(trackId), m_playbackData(playbackData)
38 : {
39 : ONLY_AUDIO_ENGINE_THREAD;
40 :
41 0 : if (onOffStreamReceived) {
42 0 : m_playbackData.offStream.onReceive(this, [onOffStreamReceived](const PlaybackEventsMap&,
43 : bool) {
44 0 : onOffStreamReceived();
45 0 : });
46 : }
47 0 : }
48 :
49 0 : EventAudioNode::~EventAudioNode()
50 : {
51 0 : m_playbackData.offStream.disconnect(this);
52 0 : }
53 :
54 0 : void EventAudioNode::onModeChanged(const ProcessMode mode)
55 : {
56 : ONLY_AUDIO_ENGINE_THREAD;
57 :
58 0 : if (!m_synth) {
59 0 : return;
60 : }
61 :
62 0 : m_synth->setMode(mode);
63 0 : m_synth->flushSound();
64 : }
65 :
66 0 : void EventAudioNode::onOutputSpecChanged(const OutputSpec& spec)
67 : {
68 : ONLY_AUDIO_ENGINE_THREAD;
69 0 : if (!m_synth) {
70 0 : return;
71 : }
72 :
73 0 : m_synth->setOutputSpec(spec);
74 : }
75 :
76 0 : void EventAudioNode::doSelfProcess(float* buffer, samples_t samplesPerChannel)
77 : {
78 : ONLY_AUDIO_PROC_THREAD;
79 0 : if (!m_synth) {
80 0 : return;
81 : }
82 :
83 0 : m_synth->process(buffer, samplesPerChannel);
84 : }
85 :
86 0 : void EventAudioNode::seek(const TimePosition& position, const bool flushSound)
87 : {
88 : ONLY_AUDIO_ENGINE_THREAD;
89 :
90 0 : IF_ASSERT_FAILED(m_synth) {
91 0 : return;
92 : }
93 :
94 0 : if (m_synth->playbackPosition() == position) {
95 0 : return;
96 : }
97 :
98 0 : m_synth->setPlaybackPosition(position);
99 :
100 0 : if (flushSound) {
101 0 : m_synth->flushSound();
102 : }
103 : }
104 :
105 0 : void EventAudioNode::flush()
106 : {
107 : ONLY_AUDIO_ENGINE_THREAD;
108 :
109 0 : IF_ASSERT_FAILED(m_synth) {
110 0 : return;
111 : }
112 :
113 0 : m_synth->flushSound();
114 : }
115 :
116 0 : const AudioInputParams& EventAudioNode::inputParams() const
117 : {
118 0 : return m_params;
119 : }
120 :
121 0 : void EventAudioNode::applyInputParams(const AudioInputParams& requiredParams)
122 : {
123 0 : IF_ASSERT_FAILED(m_outputSpec.isValid()) {
124 0 : return;
125 : }
126 :
127 0 : if (m_params.isValid() && m_params == requiredParams) {
128 0 : return;
129 : }
130 :
131 0 : SynthCtx ctx = currentSynthCtx();
132 :
133 0 : if (m_synth) {
134 0 : m_playbackData = m_synth->playbackData();
135 : }
136 :
137 0 : RetVal<synth::ISynthesizerPtr> synth = audioFactory()->makeSynth(m_trackId, requiredParams, m_playbackData.setupData);
138 :
139 0 : if (!synth.ret) {
140 0 : synth = audioFactory()->makeDefaultSynth(m_trackId);
141 0 : IF_ASSERT_FAILED(synth.val) {
142 0 : LOGE() << "Default synth not found!";
143 0 : return;
144 : }
145 : }
146 :
147 0 : m_synth = synth.val;
148 :
149 0 : m_synth->paramsChanged().onReceive(this, [this](const AudioInputParams& params) {
150 0 : m_paramsChanges.send(params);
151 0 : });
152 :
153 0 : setupSource();
154 :
155 0 : if (ctx.isValid()) {
156 0 : restoreSynthCtx(ctx);
157 : } else {
158 0 : m_synth->setMode(ProcessMode::Idle);
159 : }
160 :
161 0 : setName(std::string("Source[") + m_synth->name() + "]");
162 :
163 0 : m_params = m_synth->params();
164 0 : m_paramsChanges.send(m_params);
165 0 : }
166 :
167 0 : async::Channel<AudioInputParams> EventAudioNode::inputParamsChanged() const
168 : {
169 0 : return m_paramsChanges;
170 : }
171 :
172 0 : void EventAudioNode::prepareToPlay()
173 : {
174 : ONLY_AUDIO_ENGINE_THREAD;
175 :
176 0 : IF_ASSERT_FAILED(m_synth) {
177 0 : return;
178 : }
179 :
180 0 : m_synth->prepareToPlay();
181 : }
182 :
183 0 : bool EventAudioNode::readyToPlay() const
184 : {
185 : ONLY_AUDIO_ENGINE_THREAD;
186 :
187 0 : IF_ASSERT_FAILED(m_synth) {
188 0 : return false;
189 : }
190 :
191 0 : return m_synth->readyToPlay();
192 : }
193 :
194 0 : async::Notification EventAudioNode::readyToPlayChanged() const
195 : {
196 : ONLY_AUDIO_ENGINE_THREAD;
197 :
198 0 : IF_ASSERT_FAILED(m_synth) {
199 0 : return {};
200 : }
201 :
202 0 : return m_synth->readyToPlayChanged();
203 : }
204 :
205 0 : bool EventAudioNode::hasPendingChunks() const
206 : {
207 : ONLY_AUDIO_ENGINE_THREAD;
208 :
209 0 : IF_ASSERT_FAILED(m_synth) {
210 0 : return false;
211 : }
212 :
213 0 : return m_synth->hasPendingChunks();
214 : }
215 :
216 0 : void EventAudioNode::processInput()
217 : {
218 : ONLY_AUDIO_ENGINE_THREAD;
219 :
220 0 : IF_ASSERT_FAILED(m_synth) {
221 0 : return;
222 : }
223 :
224 0 : m_synth->processInput();
225 : }
226 :
227 0 : InputProcessingProgress EventAudioNode::inputProcessingProgress() const
228 : {
229 : ONLY_AUDIO_ENGINE_THREAD;
230 :
231 0 : IF_ASSERT_FAILED(m_synth) {
232 0 : return {};
233 : }
234 :
235 0 : return m_synth->inputProcessingProgress();
236 0 : }
237 :
238 0 : void EventAudioNode::clearCache()
239 : {
240 : ONLY_AUDIO_ENGINE_THREAD;
241 :
242 0 : IF_ASSERT_FAILED(m_synth) {
243 0 : return;
244 : }
245 :
246 0 : m_synth->clearCache();
247 : }
248 :
249 0 : EventAudioNode::SynthCtx EventAudioNode::currentSynthCtx() const
250 : {
251 0 : if (!m_synth) {
252 0 : return SynthCtx();
253 : }
254 :
255 0 : return { m_synth->mode(), m_synth->playbackPosition() };
256 : }
257 :
258 0 : void EventAudioNode::restoreSynthCtx(const SynthCtx& ctx)
259 : {
260 0 : m_synth->setPlaybackPosition(ctx.playbackPosition);
261 0 : m_synth->setMode(ctx.mode);
262 0 : }
263 :
264 0 : void EventAudioNode::setupSource()
265 : {
266 : ONLY_AUDIO_ENGINE_THREAD;
267 :
268 0 : IF_ASSERT_FAILED(m_synth) {
269 0 : return;
270 : }
271 :
272 0 : m_synth->setOutputSpec(m_outputSpec);
273 0 : m_synth->setup(m_playbackData);
274 : }
|