-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmidi-song.cpp
More file actions
81 lines (74 loc) · 2.75 KB
/
midi-song.cpp
File metadata and controls
81 lines (74 loc) · 2.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "midi-song.h"
/* return true if the given event has a matching action and note for the params */
inline bool matchesEvent(MjMidi::event * p_event, uint8_t action, uint8_t note)
{
return p_event->action == action && p_event->note == note;
}
namespace MjMidi
{
/* Loop through events from current instant until an event is completed or the
end of the instant is reached or the end of the song is reached.
If none is completed in this attempt and the end of the instant or song is
reached, the song shall be reset.
If the final event is completed, the song's callback shall be fired, and the
song shall be reset. */
void Song::attempt(uint8_t action, uint8_t note)
{
bool songIsCompleteSoFar = true;
// loop through subsequent events in this song, breaking when there is an offset or song end
for (unsigned int i = this->i; i < n; i ++) {
// Failure (i.e. wrong midi event/note):
// terminate loop if the current event is offset from the current instant
// and this is not the first time in the loop and incomplete events are known
// to exist before index i.
if (p_events[i].offset && i != this->i && !songIsCompleteSoFar) {
if (failureCallback)
failureCallback();
reset();
return; // failure
}
// Neither failure nor success:
// move on to next event if the current one is already complete
if (p_events[i].complete)
continue;
// Success:
// mark the current event complete if it matches the input
if (matchesEvent(&p_events[i], action, note)) {
p_events[i].complete = true;
// update events index i if the song is complete so far
if (songIsCompleteSoFar) {
this->i = i + 1;
// recognize end of song if i == n
if (this->i >= n) {
if (completionCallback)
completionCallback();
reset();
}
}
return; // success
}
// at least one event in the current instant was incomplete and not matched
songIsCompleteSoFar = false;
}
}
/* Clear i. Clear .complete on all events */
void Song::reset()
{
this->i = 0;
for (unsigned int i = 0; i < this->n; i++) {
p_events[i].complete = false;
}
}
void Song::setCallbacks(void(*completionCallback)(void), void(*failureCallback)(void))
{
this->completionCallback = completionCallback;
this->failureCallback = failureCallback;
}
/* Call attempt on all of the Songs in this SongBank */
void SongBank::handleMidiEvent(uint8_t action, uint8_t note)
{
for (unsigned int i = 0; i < n; i++) {
pp_songs[i]->attempt(action, note);
}
}
}