-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNote.h
139 lines (126 loc) · 2.86 KB
/
Note.h
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#pragma once
enum NoteMode {
ATTACK = 0, SUSTAIN = 1, RELEASE = 2, TOBEREMOVED = 3
};
struct NoteData {
uint8_t note;
NoteMode mode;
};
template<uint8_t N> struct NoteManager {
NoteManager() {
//generate nodes
for (uint8_t i = 0; i < N; i++) {
noteNodes[i] = {
/*.noteData =*/ {0,ATTACK},
/*.previous =*/ noteNodes + (i-1),
/*.next =*/ noteNodes + (i+1)
};
}
head->previous = nullptr;
back->next = nullptr;
}
int addNote(uint8_t note) {
uint8_t& i = noteToNodeIndex[note];
if (!i) {
i = uint8_t(back - noteNodes + 1);
//take back node and change noteData.
auto& data = back->noteData;
//set noteToNodeIndex to 0
noteToNodeIndex[data.note] = 0;
data.note = note;
data.mode = ATTACK;
if (N > 1) {
//decouple from previous
NoteNode* oldPrevious = back->previous;
back->previous->next = nullptr;
back->previous = nullptr;
//attach back to front
head->previous = back;
back->next = head;
head = back;
//overwrite back
back = oldPrevious;
}
return i - 1;
} else {
//rehit note.
noteNodes[i - 1].noteData.mode = ATTACK;
return i - 1;
}
}
int removeNote(uint8_t note) {
if (uint8_t& i = noteToNodeIndex[note]) {
uint8_t oldNote = i;
NoteNode* current = noteNodes + (i - 1);
//set current note to 0.
i = 0;
//if note is still playing
if (current->noteData.note == note) {
current->noteData.note = 0;
if (N > 1) {
//attach node to back
if (current != back) {
//set next to nullptr;
NoteNode* oldNext = current->next;
current->next = nullptr;
//link current to back:
NoteNode* oldPrevious = current->previous;
current->previous = back;
back->next = current;
back = current;
//link oldNext to oldPrevious:
if (oldPrevious) {
oldPrevious->next = oldNext;
oldNext->previous = oldPrevious;
} else {
head = oldNext;
oldNext->previous = nullptr;
}
}
}
}
return oldNote - 1;
} else {
return -1;
}
}
struct NoteNode {
NoteData noteData;
NoteNode* previous;
NoteNode* next;
} noteNodes[N];
private:
NoteNode* head = noteNodes + 0;
NoteNode* back = noteNodes + N - 1;
uint8_t noteToNodeIndex[256] = { };
public:
template<typename F> void forEach(F&& func) {
for (uint8_t i = 0; i < N; i++) {
func(noteNodes[i].noteData);
}
}
template<typename F> void forEachPlayingNote(F&& func) {
for (uint8_t i = 0; i < N; i++) {
auto& d = noteNodes[i].noteData;
if (d.note) {
func(d);
}
}
}
NoteNode* first() {
return head;
}
NoteNode* last() {
return back;
}
NoteData* getNote(uint8_t note) {
if (uint8_t& i = noteToNodeIndex[note]) {
NoteNode* current = noteNodes + (i - 1);
//if note is still playing
if (current->noteData.note == note) {
return ¤t->noteData;
}
}
return nullptr;
}
};