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 : #pragma once
24 :
25 : #include <map>
26 : #include <set>
27 :
28 : #include "global/async/asyncable.h"
29 : #include "mpe/events.h"
30 :
31 : #include "audio/common/audiosanitizer.h"
32 : #include "audio/common/audiotypes.h"
33 :
34 : namespace muse::audio::engine {
35 : template<class ... Types>
36 : class AbstractEventSequencer : public async::Asyncable
37 : {
38 : public:
39 : using EventType = std::variant<Types...>;
40 : using EventSequence = std::vector<EventType>;
41 : using EventSequenceMap = std::map<msecs_t, EventSequence>;
42 :
43 : typedef typename EventSequenceMap::const_iterator SequenceIterator;
44 : typedef typename EventSequence::const_iterator EventIterator;
45 :
46 0 : AbstractEventSequencer()
47 0 : {
48 0 : resetAllIterators();
49 0 : }
50 :
51 0 : virtual ~AbstractEventSequencer()
52 : {
53 0 : m_playbackData.mainStream.disconnect(this);
54 0 : m_playbackData.offStream.disconnect(this);
55 0 : }
56 :
57 0 : void load(const mpe::PlaybackData& data)
58 : {
59 : ONLY_AUDIO_ENGINE_THREAD;
60 :
61 0 : m_playbackData = data;
62 :
63 0 : m_playbackData.mainStream.onReceive(this, [this](const mpe::PlaybackEventsMap& events,
64 : const mpe::DynamicAutomationLayers& dynamics) {
65 0 : m_playbackData.originEvents = events;
66 0 : m_playbackData.dynamics = dynamics;
67 0 : m_shouldUpdateMainStreamEvents = true;
68 :
69 0 : if (m_isActive || m_updateMainStreamWhenInactive) {
70 0 : updateMainStream();
71 : }
72 : });
73 :
74 0 : m_playbackData.offStream.onReceive(this, [this](const mpe::PlaybackEventsMap& events,
75 : bool flush) {
76 0 : if (flush) {
77 0 : flushOffstream();
78 : }
79 :
80 0 : updateOffStreamEvents(events);
81 : });
82 :
83 0 : updateMainStreamEvents(data.originEvents, data.dynamics);
84 0 : }
85 :
86 0 : const mpe::PlaybackData& playbackData() const
87 : {
88 0 : return m_playbackData;
89 : }
90 :
91 0 : void updateMainStream()
92 : {
93 0 : if (m_shouldUpdateMainStreamEvents) {
94 0 : updateMainStreamEvents(m_playbackData.originEvents, m_playbackData.dynamics);
95 0 : m_shouldUpdateMainStreamEvents = false;
96 : }
97 0 : }
98 :
99 0 : void setUpdateMainStreamWhenInactive(bool update)
100 : {
101 0 : m_updateMainStreamWhenInactive = update;
102 0 : }
103 :
104 0 : void flushOffstream()
105 : {
106 0 : if (m_offStreamEvents.empty()) {
107 0 : return;
108 : }
109 :
110 0 : m_offStreamEvents.clear();
111 0 : updateOffSequenceIterator();
112 :
113 0 : if (m_onOffStreamFlushed) {
114 0 : m_onOffStreamFlushed();
115 : }
116 : }
117 :
118 0 : void setActive(const bool active)
119 : {
120 0 : if (m_isActive == active) {
121 0 : return;
122 : }
123 :
124 0 : m_isActive = active;
125 :
126 0 : if (m_isActive) {
127 0 : updateMainStream();
128 : }
129 : }
130 :
131 0 : bool isActive() const
132 : {
133 0 : return m_isActive;
134 : }
135 :
136 0 : void setPlaybackPosition(const msecs_t newPlaybackPosition)
137 : {
138 : ONLY_AUDIO_ENGINE_THREAD;
139 :
140 0 : m_playbackPosition = newPlaybackPosition;
141 0 : resetAllIterators();
142 0 : }
143 :
144 0 : msecs_t playbackPosition() const
145 : {
146 : ONLY_AUDIO_ENGINE_THREAD;
147 :
148 0 : return m_playbackPosition;
149 : }
150 :
151 : using OnFlushedCallback = std::function<void ()>;
152 :
153 0 : void setOnOffStreamFlushed(OnFlushedCallback flushed)
154 : {
155 : ONLY_AUDIO_ENGINE_THREAD;
156 :
157 0 : m_onOffStreamFlushed = flushed;
158 0 : }
159 :
160 : void setOnMainStreamFlushed(OnFlushedCallback flushed)
161 : {
162 : ONLY_AUDIO_ENGINE_THREAD;
163 :
164 : m_onMainStreamFlushed = flushed;
165 : }
166 :
167 0 : EventSequenceMap movePlaybackForward(const msecs_t nextMsecs)
168 : {
169 : ONLY_AUDIO_ENGINE_THREAD;
170 :
171 0 : EventSequenceMap result;
172 :
173 0 : if (!m_isActive) {
174 0 : result.emplace(m_offstreamPosition, EventSequence());
175 :
176 0 : if (m_currentOffSequenceIt == m_offStreamEvents.cend()) {
177 0 : return result;
178 : }
179 :
180 0 : m_offstreamPosition += nextMsecs;
181 0 : handleOffStream(result);
182 :
183 0 : return result;
184 : }
185 :
186 : // Empty sequence means to continue the previous sequence
187 0 : result.emplace(m_playbackPosition, EventSequence());
188 0 : m_playbackPosition += nextMsecs;
189 :
190 0 : if (m_currentMainSequenceIt == m_mainStreamEvents.cend()) {
191 0 : return result;
192 : }
193 :
194 0 : handleMainStream(result);
195 :
196 0 : return result;
197 0 : }
198 :
199 : protected:
200 : virtual void updateMainStreamEvents(const mpe::PlaybackEventsMap& events, const mpe::DynamicAutomationLayers& dynamics) = 0;
201 : virtual void updateOffStreamEvents(const mpe::PlaybackEventsMap& events) = 0;
202 :
203 0 : void resetAllIterators()
204 : {
205 0 : updateMainSequenceIterator();
206 0 : updateOffSequenceIterator();
207 0 : }
208 :
209 0 : void updateMainSequenceIterator()
210 : {
211 0 : m_currentMainSequenceIt = m_mainStreamEvents.lower_bound(m_playbackPosition);
212 0 : }
213 :
214 0 : void updateOffSequenceIterator()
215 : {
216 0 : m_currentOffSequenceIt = m_offStreamEvents.cbegin();
217 0 : m_offstreamPosition = 0;
218 0 : }
219 :
220 0 : void handleMainStream(EventSequenceMap& result)
221 : {
222 0 : while (m_currentMainSequenceIt != m_mainStreamEvents.end()
223 0 : && m_currentMainSequenceIt->first <= m_playbackPosition) {
224 0 : EventSequence& sequence = result[m_currentMainSequenceIt->first];
225 0 : sequence.insert(sequence.end(), m_currentMainSequenceIt->second.cbegin(),
226 0 : m_currentMainSequenceIt->second.cend());
227 0 : m_currentMainSequenceIt = std::next(m_currentMainSequenceIt);
228 : }
229 0 : }
230 :
231 0 : void handleOffStream(EventSequenceMap& result)
232 : {
233 0 : if (m_offStreamEvents.empty()) {
234 0 : return;
235 : }
236 :
237 0 : while (m_currentOffSequenceIt != m_offStreamEvents.end()
238 0 : && m_currentOffSequenceIt->first <= m_offstreamPosition) {
239 0 : EventSequence& sequence = result[m_currentOffSequenceIt->first];
240 0 : sequence.insert(sequence.end(), std::make_move_iterator(m_currentOffSequenceIt->second.begin()),
241 0 : std::make_move_iterator(m_currentOffSequenceIt->second.end()));
242 0 : m_currentOffSequenceIt = m_offStreamEvents.erase(m_currentOffSequenceIt);
243 : }
244 :
245 0 : if (m_currentOffSequenceIt == m_offStreamEvents.end()) {
246 0 : m_offstreamPosition = 0;
247 : }
248 : }
249 :
250 : mutable msecs_t m_playbackPosition = 0;
251 : mutable msecs_t m_offstreamPosition = 0;
252 :
253 : SequenceIterator m_currentMainSequenceIt;
254 : SequenceIterator m_currentOffSequenceIt;
255 : EventSequenceMap m_mainStreamEvents;
256 : EventSequenceMap m_offStreamEvents;
257 :
258 : mpe::PlaybackData m_playbackData;
259 :
260 : bool m_isActive = false;
261 :
262 : OnFlushedCallback m_onOffStreamFlushed;
263 : OnFlushedCallback m_onMainStreamFlushed;
264 :
265 : private:
266 : bool m_shouldUpdateMainStreamEvents = false;
267 : bool m_updateMainStreamWhenInactive = false;
268 : };
269 : }
|