-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChannelState.hpp
245 lines (214 loc) · 7.62 KB
/
ChannelState.hpp
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#ifndef CHANNELSTATE_INCLUDED
#define CHANNELSTATE_INCLUDED
//#include <Arduino.h>
#include "MidiSetup.hpp"
#include "MidiEcho.h"
#define DEBUG_CHANNELSTATE false
static int channelcount = 0;
class ChannelState {
private:
#define HELD_NOTES_MAX 10 //(sizeof(held_notes)/sizeof(held_notes[0]))
int midi_root_pitch = MIDI_BASS_ROOT_PITCH;
//int held_notes_count = 0;
bool note_held = false;
// track pitches internally
void push_note (byte pitch) {
if (DEBUG_CHANNELSTATE) Serial.printf("channelstate push_note(%i)\r\n", pitch);
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (held_notes[i]==-1) { // free slot so add this new pitch
if (DEBUG_CHANNELSTATE) Serial.printf(" >adding note %i at %i\r\n", pitch, i);
held_notes[i] = pitch;
//held_notes_count++;
break;
} else if (held_notes[i]>pitch) { // insert
if (DEBUG_CHANNELSTATE) Serial.printf(" >inserting note %i at %i\r\n", pitch, i);
//for (int x = i+1 ; x < HELD_NOTES_MAX ; x++) {
for (int x = /*held_notes_count-1*/HELD_NOTES_MAX-1 ; x > i ; x--) {
if (DEBUG_CHANNELSTATE) Serial.printf(" >moving note %i at %i to %i\r\n", held_notes[x-1], x-1, x);
held_notes[x] = held_notes[x-1];
}
if (DEBUG_CHANNELSTATE) Serial.printf(" >and setting %i to %i\r\n", i, pitch);
held_notes[i] = pitch;
//held_notes_count++;
break;
} else if (held_notes[i]==pitch) {
break; // dont duplicate notes
}
}
// output debug info about multiple notes off sent
if (DEBUG_CHANNELSTATE) Serial.printf(" >channel notes_held after push_note: [");
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (DEBUG_CHANNELSTATE) Serial.printf("%s ", get_note_name(held_notes[i]).c_str());
}
if (DEBUG_CHANNELSTATE) Serial.println("]");
//auto_note_held = true;
//debug_notes_held();
}
void pop_note(byte pitch) {
if (DEBUG_CHANNELSTATE) Serial.printf("channelstate pop_note(%i)\r\n", pitch);
/*bool found = false;
bool found_held = false;
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (!found && held_notes[i]==pitch) { // found the note that's just gone off
found = true;
held_notes_count--;
} else {
found_held = true;
}
if (found && i+1 < HELD_NOTES_MAX) {
Serial.printf(" > found at %i, removing...\r\n", i);
held_notes[i] = held_notes[i+1];
//break;
}
}
if (found) {
held_notes[HELD_NOTES_MAX-1] = -1;
} else {
Serial.printf(" > didn't find pitch %i!\r\n", pitch);
}*/
#define DEBUG_POP_NOTE false
if (DEBUG_POP_NOTE) {
Serial.printf("Before\tpop_note algo, held is ");
debug_notes_held();
}
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (held_notes[i]==pitch) {
//if (DEBUG_CHANNELSTATE)
if (DEBUG_POP_NOTE) Serial.printf("\t\t\t> found pitch %i at %i, removing...\r\n", pitch, i);
//held_notes_count--;
for (int x = i ; x < HELD_NOTES_MAX-1 ; x++) {
if (DEBUG_POP_NOTE) Serial.printf("\t\t\t\tmoving pitch %i at %i to overwrite pitch %i at %i\r\n", held_notes[x+1], x+1, held_notes[x], x);
held_notes[x] = held_notes[x+1];
}
held_notes[HELD_NOTES_MAX-1] = -1;
//i--;
break;
}
}
if (DEBUG_POP_NOTE) {
Serial.printf("After\tpop_note algo, held is ");
debug_notes_held();
}
//auto_note_held = true;
//debug_notes_held();
}
int get_held_notes_count() {
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (held_notes[i]==-1) {
return i;
}
}
}
char debug_string[30];
const char* build_notes_held_string() {
String s = "";
int held_notes_count = 0;
bool found = false;
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (held_notes[i]!=-1) {
//sprintf(debug_string, "%s, ", get_note_name(held_notes[i]).c_str());
/*s += i + ":";
s += get_note_name(held_notes[i]);
s += " ";*/
//s = s + (i + ":" + get_note_name(held_notes[i]) + " ");
//s.concat((i + ":")); // + get_note_name(held_notes[i]) + " "));
s.concat(get_note_name(held_notes[i]));
s.concat(" ");
//Serial.printf("build_notes_held_string(): found held note at index %i: %i\r\n", i, held_notes[i]);
} else {
held_notes_count = i;
break;
}
}
//if (DEBUG_CHANNELSTATE)
sprintf(debug_string, "%s", s.c_str());
//if (held_notes_count>0)
// debug_string[strlen(debug_string)-1] = '\0';
return (char *)debug_string;
}
public:
int held_notes[HELD_NOTES_MAX] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
int get_root_note() {
//Serial.printf("in get_root_note in ChannelState number #%i got: %s\r\n", chanindex, debug_string);
if (is_note_held()) {
/*// find the lowest held note to use as root
int lowest = -1;
for (int i = 0 ; i < HELD_NOTES_MAX ; i++)
if (held_notes[i]!=-1 && held_notes[i] < lowest)
lowest = held_notes[i];
return lowest;*/
return held_notes[0];
} else {
//return MIDI_BASS_ROOT_PITCH;
//Serial.printf("Root is %i [%s]\n", midi_root_pitch, get_note_name(midi_root_pitch).c_str());
return midi_root_pitch;
}
}
// returns true if value was changed
bool set_midi_root_pitch(int pitch) {
int last_pitch = midi_root_pitch;
//if (midi_root_pitch==pitch) return;
//harmony.kill_notes();
midi_root_pitch = pitch;
return last_pitch!=midi_root_pitch;
}
// is specific pitch currently held?
bool is_note_held(int pitch) {
if (DEBUG_CHANNELSTATE) Serial.printf("is_note_held: testing '%i' against: ", pitch);
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (DEBUG_CHANNELSTATE) Serial.printf("%i ", held_notes[i]);
if (held_notes[i]==pitch) {
if (DEBUG_CHANNELSTATE) Serial.println("found");
return true;
}
}
if (DEBUG_CHANNELSTATE) Serial.print(" -- not found!!");
return false;
}
// is any note currently held?
bool is_note_held() {
return (held_notes[0]!=-1);
}
void handle_note_on(byte pitch, byte vel = 127) {
//Serial.printf("got autobass note %i!", pitch);
if (vel > 0) {
push_note(pitch);
}
//debug_notes_held();
build_notes_held_string();
}
void handle_note_off(byte pitch) {
pop_note(pitch);
//if (pitch==root)
// auto_note_held = false;
//debug_notes_held();
build_notes_held_string();
}
void handle_all_notes_off() {
if (is_note_held()) {
for (int i = 0 ; i < HELD_NOTES_MAX ; i++) {
if (held_notes[i]>-1)
held_notes[i] = -1;
else
break;
}
//held_notes_count = 0;
}
build_notes_held_string();
}
int *get_held_notes() {
return held_notes;
}
int get_sequence_held_note(int position) {
return held_notes[position % get_held_notes_count()];
}
void debug_notes_held() {
Serial.printf("\t\theld %i notes: [ %s ]\r\n", get_held_notes_count(), get_debug_notes_held());
//Serial.println(get_debug_notes_held());
}
const char* get_debug_notes_held() {
build_notes_held_string();
return (char *)debug_string;
}
};
#endif