Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 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 "event.h"
24 :
25 : #include "dom/note.h"
26 : #include "dom/sig.h"
27 :
28 : namespace mu::engraving {
29 : //---------------------------------------------------------
30 : // Event::Event
31 : //---------------------------------------------------------
32 :
33 0 : Event::Event()
34 : {
35 0 : _type = 0;
36 0 : _ontime = -1;
37 0 : _noquantOntime = 0;
38 0 : _noquantDuration = 0;
39 0 : _channel = 0;
40 0 : _a = 0;
41 0 : _b = 0;
42 0 : _duration = 0;
43 0 : _tpc = 0;
44 0 : _voice = 0;
45 0 : _edata = 0;
46 0 : _len = 0;
47 0 : _metaType = 0;
48 0 : _note = 0;
49 0 : _tuning = 0.0;
50 0 : }
51 :
52 3 : Event::Event(int t)
53 : {
54 3 : _type = t;
55 3 : _ontime = -1;
56 3 : _noquantOntime = 0;
57 3 : _noquantDuration = 0;
58 3 : _channel = 0;
59 3 : _a = 0;
60 3 : _b = 0;
61 3 : _duration = 0;
62 3 : _tpc = 0;
63 3 : _voice = 0;
64 3 : _edata = 0;
65 3 : _len = 0;
66 3 : _metaType = 0;
67 3 : _note = 0;
68 3 : _tuning = 0.0;
69 3 : }
70 :
71 4 : Event::Event(const Event& e)
72 4 : : PlayEvent(e)
73 : {
74 4 : _type = e._type;
75 4 : _ontime = e._ontime;
76 4 : _noquantOntime = e._noquantOntime;
77 4 : _noquantDuration = e._noquantDuration;
78 4 : _channel = e._channel;
79 4 : _a = e._a;
80 4 : _b = e._b;
81 4 : _duration = e._duration;
82 4 : _tpc = e._tpc;
83 4 : _voice = e._voice;
84 4 : _notes = e._notes;
85 4 : if (e._edata) {
86 0 : _edata = new unsigned char[e._len + 1]; // don’t forget trailing zero
87 0 : memcpy(_edata, e._edata, e._len + 1);
88 : } else {
89 4 : _edata = 0;
90 : }
91 4 : _len = e._len;
92 4 : _metaType = e._metaType;
93 4 : _note = e._note;
94 4 : _tuning = e._tuning;
95 4 : }
96 :
97 5 : Event::~Event()
98 : {
99 5 : delete[] _edata;
100 5 : }
101 :
102 : //---------------------------------------------------------
103 : // NPlayEvent::NPlayEvent (beatType2metronomeEvent)
104 : //---------------------------------------------------------
105 :
106 0 : NPlayEvent::NPlayEvent(BeatType beatType)
107 : {
108 0 : setType(ME_TICK2);
109 0 : setVelo(127);
110 0 : switch (beatType) {
111 0 : case BeatType::DOWNBEAT:
112 0 : setType(ME_TICK1);
113 0 : break;
114 0 : case BeatType::SIMPLE_STRESSED:
115 : case BeatType::COMPOUND_STRESSED:
116 : // use defaults
117 0 : break;
118 0 : case BeatType::SIMPLE_UNSTRESSED:
119 : case BeatType::COMPOUND_UNSTRESSED:
120 0 : setVelo(80);
121 0 : break;
122 0 : case BeatType::COMPOUND_SUBBEAT:
123 0 : setVelo(25);
124 0 : break;
125 0 : case BeatType::SUBBEAT:
126 0 : setVelo(15);
127 0 : break;
128 : }
129 0 : }
130 :
131 : //---------------------------------------------------------
132 : // isMuted
133 : //---------------------------------------------------------
134 :
135 1080 : bool NPlayEvent::isMuted() const
136 : {
137 : //! TODO
138 :
139 : // const Note* n = note();
140 : // if (n) {
141 : // MasterScore* cs = n->masterScore();
142 : // Staff* staff = n->staff();
143 : // Instrument* instr = staff->part()->instrument(n->tick());
144 : // const Channel* a = instr->playbackChannel(n->subchannel(), cs);
145 : // return a->mute() || a->soloMute() || !staff->playbackVoice(n->voice());
146 : // }
147 :
148 : // const Harmony* h = harmony();
149 : // if (h) {
150 : // const Channel* hCh = h->part()->harmonyChannel();
151 : // if (hCh) { //if there is a harmony channel
152 : // const Channel* pCh = h->masterScore()->playbackChannel(hCh);
153 : // return pCh->mute() || pCh->soloMute();
154 : // }
155 : // }
156 :
157 1080 : return false;
158 : }
159 :
160 : //---------------------------------------------------------
161 : // dump
162 : //---------------------------------------------------------
163 :
164 0 : void Event::dump() const
165 : {
166 0 : printf("event ");
167 0 : switch (_type) {
168 0 : case ME_NOTEON: printf("noteon ");
169 0 : break;
170 0 : case ME_CONTROLLER: printf("controller");
171 0 : break;
172 0 : case ME_PROGRAM: printf("program ");
173 0 : break;
174 0 : default: printf("0x%02x ", _type);
175 0 : break;
176 : }
177 0 : printf(" 0x%02x 0x%02x\n", _a, _b);
178 0 : }
179 :
180 0 : bool Event::operator==(const Event&) const
181 : {
182 0 : return false; // TODO
183 : }
184 :
185 : //---------------------------------------------------------
186 : // insert
187 : //---------------------------------------------------------
188 :
189 0 : void EventList::insert(const Event& e)
190 : {
191 0 : int ontime = e.ontime();
192 0 : if (!empty() && back().ontime() > ontime) {
193 0 : for (auto i = begin(); i != end(); ++i) {
194 0 : if (i->ontime() > ontime) {
195 0 : std::vector<Event>::insert(i, e);
196 0 : return;
197 : }
198 : }
199 : }
200 0 : push_back(e);
201 : }
202 :
203 13355 : EventsHolder::events_multimap_t& EventsHolder::operator[](std::size_t idx)
204 : {
205 13355 : if (size() == 0) {
206 204 : _channels.emplace_back();
207 : }
208 13355 : if (idx >= size()) {
209 69 : auto diff = idx - size();
210 : do {
211 306 : _channels.emplace_back();
212 306 : } while (diff-- != 0);
213 : }
214 13355 : return _channels[idx];
215 : }
216 :
217 53 : const EventsHolder::events_multimap_t& EventsHolder::operator[](std::size_t idx) const
218 : {
219 : // Since EventsHolder acts more like a vector
220 : // Using const subscript operator for a nonexistent element is UB
221 : /*
222 : * cppreference.com
223 : * Unlike std::map::operator[], this operator never inserts a new element into the container.
224 : * Accessing a nonexistent element through this operator is undefined behavior.
225 : */
226 53 : assert(idx < size());
227 53 : return _channels[idx];
228 : }
229 :
230 80 : void EventsHolder::mergePitchWheelEvents(EventsHolder& pitchWheelEvents)
231 : {
232 182 : for (size_t i = 0; i < size(); ++i) {
233 1365 : for (const auto& eventPair : _channels[i]) {
234 1263 : const auto& event = eventPair.second;
235 1263 : const auto& tick = eventPair.first;
236 1263 : if (event.type() == ME_NOTEON && event.velo() != 0) {
237 505 : const auto& pwEvent = muse::findLess(pitchWheelEvents[i], tick);
238 505 : if (pwEvent != pitchWheelEvents[i].end()
239 505 : && pwEvent->second.type() == ME_PITCHBEND) {
240 20 : PitchWheelSpecs specs;
241 20 : NPlayEvent pwReset(ME_PITCHBEND, (uint8_t)i, specs.mLimit % 128, specs.mLimit / 128);
242 20 : pwReset.setOriginatingStaff(pwEvent->second.getOriginatingStaff());
243 :
244 20 : int tickForPwReset = 0;
245 20 : if (tick - specs.mStep > pwEvent->first) {
246 15 : tickForPwReset = tick - specs.mStep;
247 : } else {
248 5 : tickForPwReset = (tick + pwEvent->first) / 2;
249 : }
250 :
251 20 : _channels[i].insert(std::pair<int, NPlayEvent>(tickForPwReset, pwReset));
252 : }
253 : }
254 : }
255 102 : _channels[i].merge(pitchWheelEvents[i]);
256 : }
257 80 : }
258 :
259 : //---------------------------------------------------------
260 : // class EventsHolder::fixupMIDI
261 : //---------------------------------------------------------
262 :
263 79 : void EventsHolder::fixupMIDI()
264 : {
265 : /* track info for each of the 128 possible MIDI notes */
266 : struct channelInfo {
267 : /* which event the first ME_NOTEON came from */
268 : NPlayEvent* event[128];
269 : /* how often is the note on right now? */
270 : unsigned short nowPlaying[128];
271 : };
272 :
273 : /* track info for each channel (on the heap, 0-initialised) */
274 79 : auto* info = (struct channelInfo*)calloc(size() + 1, sizeof(struct channelInfo));
275 :
276 180 : for (auto& mm : _channels) {
277 101 : auto it = mm.begin();
278 1360 : while (it != mm.end()) {
279 1259 : NPlayEvent& event = it->second;
280 : /* ME_NOTEOFF is never emitted, no need to check for it */
281 1259 : if (event.type() == ME_NOTEON) {
282 1006 : uint8_t np = info[event.channel()].nowPlaying[event.pitch()];
283 1006 : if (event.velo() == 0) {
284 : /* already off (should not happen) or still playing? */
285 503 : if (np == 0 || --np > 0) {
286 1 : event.setDiscard(1);
287 : } else {
288 : /* hoist NOTEOFF to same track as NOTEON */
289 502 : event.setOriginatingStaff(info[event.channel()].event[event.pitch()]->getOriginatingStaff());
290 : }
291 : } else {
292 503 : if (++np > 1) {
293 : /* restrike, possibly on different track */
294 1 : event.setDiscard(info[event.channel()].event[event.pitch()]->getOriginatingStaff() + 1);
295 : }
296 503 : info[event.channel()].event[event.pitch()] = &event;
297 : }
298 1006 : info[event.channel()].nowPlaying[event.pitch()] = np;
299 : }
300 :
301 1259 : ++it;
302 : }
303 : }
304 :
305 79 : free((void*)info);
306 79 : }
307 : }
|