diff options
author | Bad Diode <bd@badd10de.dev> | 2023-02-09 13:42:46 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2023-02-09 13:42:46 +0100 |
commit | 79b116d19fa4de2f7b5450acfe77a54524505b7d (patch) | |
tree | 6e06959a8a069a2d5da822b1c5fa3d149d26171a /src/app.c | |
parent | 8fc15953b2c10a8f06169b4ccbc6b16c86b205b2 (diff) | |
download | launchpad-polymaker-79b116d19fa4de2f7b5450acfe77a54524505b7d.tar.gz launchpad-polymaker-79b116d19fa4de2f7b5450acfe77a54524505b7d.zip |
Enable bypass and bugfixes
Diffstat (limited to 'src/app.c')
-rw-r--r-- | src/app.c | 115 |
1 files changed, 83 insertions, 32 deletions
@@ -35,12 +35,16 @@ | |||
35 | // Housekeeping and debugging. | 35 | // Housekeeping and debugging. |
36 | u16 frame = 0; | 36 | u16 frame = 0; |
37 | u16 n_voices = 0; | 37 | u16 n_voices = 0; |
38 | u8 active = 1; | ||
39 | u8 ch_min = 4; | ||
40 | u8 ch_max = 8; | ||
38 | 41 | ||
39 | typedef struct Voice { | 42 | typedef struct Voice { |
40 | u8 active; | 43 | u8 active; |
41 | u8 channel; | 44 | u8 channel; |
42 | u8 d1; | 45 | u8 d1; |
43 | u8 d2; | 46 | u8 d2; |
47 | u8 port; | ||
44 | } Voice; | 48 | } Voice; |
45 | 49 | ||
46 | Voice voices[16] = {0}; | 50 | Voice voices[16] = {0}; |
@@ -134,76 +138,112 @@ u16 font_numbers[10] = { | |||
134 | 0xF792, | 138 | 0xF792, |
135 | }; | 139 | }; |
136 | 140 | ||
141 | enum Buttons { | ||
142 | POLY_PAD_ACTIVE = 11, | ||
143 | }; | ||
144 | |||
137 | void | 145 | void |
138 | app_surface_event(u8 type, u8 index, u8 value) { | 146 | app_surface_event(u8 type, u8 index, u8 value) { |
139 | // switch (type) { | 147 | switch (type) { |
140 | // case TYPEPAD: { | 148 | case TYPEPAD: { |
141 | // // toggle it and store it off, so we can save to flash if we want to | 149 | if (value && index == POLY_PAD_ACTIVE) { |
142 | // if (value) { | 150 | // Stop existing playing notes. |
143 | // buttons[index] = MAXLED * !buttons[index]; | 151 | for (u8 i = 0; i < 16; i++) { |
144 | // } | 152 | Voice *voice = &voices[i]; |
145 | 153 | if (voice->active) { | |
146 | // // example - light / extinguish pad LEDs | 154 | voice->active = 0; |
147 | // hal_plot_led(TYPEPAD, index, 0, 0, buttons[index]); | 155 | hal_send_midi( |
148 | 156 | voice->port, | |
149 | // // example - send MIDI | 157 | NOTEOFF | voice->channel, |
150 | // hal_send_midi(DINMIDI, NOTEON | 0, index, value); | 158 | voice->d1, |
151 | // } break; | 159 | voice->d2); |
152 | // case TYPESETUP: { | 160 | } |
153 | // if (value) { | 161 | } |
154 | // // Pressing the setup button will save the current buttons/pad | 162 | n_voices = 0; |
155 | // // state to the flash. The flash memory is USER_AREA_SIZE bytes | 163 | active = !active; |
156 | // // long and can be organized however we need. | 164 | } |
157 | // hal_write_flash(0, buttons, BUTTON_COUNT); | 165 | // // toggle it and store it off, so we can save to flash if we want to |
158 | // } | 166 | // if (value) { |
159 | // } break; | 167 | // buttons[index] = MAXLED * !buttons[index]; |
160 | // } | 168 | // } |
169 | |||
170 | // // example - light / extinguish pad LEDs | ||
171 | // hal_plot_led(TYPEPAD, index, 0, 0, buttons[index]); | ||
172 | |||
173 | // // example - send MIDI | ||
174 | // hal_send_midi(DINMIDI, NOTEON | 0, index, value); | ||
175 | } break; | ||
176 | case TYPESETUP: { | ||
177 | // if (value) { | ||
178 | // // Pressing the setup button will save the current buttons/pad | ||
179 | // // state to the flash. The flash memory is USER_AREA_SIZE bytes | ||
180 | // // long and can be organized however we need. | ||
181 | // hal_write_flash(0, buttons, BUTTON_COUNT); | ||
182 | // } | ||
183 | } break; | ||
184 | } | ||
161 | } | 185 | } |
162 | 186 | ||
163 | void | 187 | void |
164 | app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { | 188 | app_midi_event(u8 port, u8 status, u8 d1, u8 d2) { |
189 | if (!active) { | ||
190 | hal_send_midi(port, status, d1, d2); | ||
191 | return; | ||
192 | } | ||
165 | u8 channel = status & 0x0F; | 193 | u8 channel = status & 0x0F; |
166 | if ((status & 0xF0) == NOTEON) { | 194 | if ((status & 0xF0) == NOTEON) { |
195 | if (n_voices == (ch_max - ch_min)) { | ||
196 | return; | ||
197 | } | ||
198 | |||
167 | // Find if the note was already pressed. | 199 | // Find if the note was already pressed. |
168 | for (u8 i = 0; i < 16; i++) { | 200 | for (u8 i = ch_min; i < ch_max; i++) { |
169 | Voice *voice = &voices[i]; | 201 | Voice *voice = &voices[i]; |
170 | // Register voice. | 202 | // Stop voice if needed. |
171 | if (voice->active && voice->d1 == d1) { | 203 | if (voice->active && voice->d1 == d1) { |
172 | voice->active = 0; | 204 | voice->active = 0; |
173 | hal_send_midi(port, NOTEOFF | i, d1, d2); | 205 | hal_send_midi(voice->port, |
206 | NOTEOFF | voice->channel, | ||
207 | voice->d1, | ||
208 | voice->d2); | ||
174 | break; | 209 | break; |
175 | } | 210 | } |
176 | } | 211 | } |
177 | 212 | ||
178 | // Find next free voice slot. | 213 | // Find next free voice slot. |
179 | for (u8 i = 0; i < 16; i++) { | 214 | for (u8 i = ch_min; i < ch_max; i++) { |
180 | Voice *voice = &voices[i]; | 215 | Voice *voice = &voices[i]; |
181 | // Register voice. | 216 | // Register voice. |
182 | if (!voice->active) { | 217 | if (!voice->active) { |
183 | voice->active = 1; | 218 | voice->active = 1; |
219 | voice->port = port; | ||
184 | voice->channel = i; | 220 | voice->channel = i; |
185 | voice->d1 = d1; | 221 | voice->d1 = d1; |
186 | voice->d2 = d2; | 222 | voice->d2 = d2; |
187 | hal_send_midi(port, NOTEON | i, d1, d2); | 223 | hal_send_midi(voice->port, |
224 | NOTEON | voice->channel, | ||
225 | voice->d1, | ||
226 | voice->d2); | ||
188 | break; | 227 | break; |
189 | } | 228 | } |
190 | } | 229 | } |
230 | |||
191 | // TODO: if there are no free slots choose the oldest active one. | 231 | // TODO: if there are no free slots choose the oldest active one. |
192 | // TODO: - Send noteoff message for the previous active channel. | 232 | // TODO: - Send noteoff message for the previous active channel. |
193 | // TODO: send noteon message. | 233 | // TODO: send noteon message. |
234 | // TODO: Round robin scheduling? | ||
194 | n_voices++; | 235 | n_voices++; |
195 | } else if ((status & 0xF0) == NOTEOFF) { | 236 | } else if ((status & 0xF0) == NOTEOFF) { |
196 | for (u8 i = 0; i < 16; i++) { | 237 | for (u8 i = ch_min; i < ch_max; i++) { |
197 | Voice *voice = &voices[i]; | 238 | Voice *voice = &voices[i]; |
198 | // Register voice. | 239 | // Register voice. |
199 | if (voice->active && voice->d1 == d1) { | 240 | if (voice->active && voice->d1 == d1) { |
200 | voice->active = 0; | 241 | voice->active = 0; |
201 | hal_send_midi(port, NOTEOFF | i, d1, d2); | 242 | hal_send_midi(port, NOTEOFF | i, d1, d2); |
243 | n_voices--; | ||
202 | break; | 244 | break; |
203 | } | 245 | } |
204 | } | 246 | } |
205 | n_voices--; | ||
206 | // hal_send_midi(port, status, d1, d2); | ||
207 | } | 247 | } |
208 | } | 248 | } |
209 | 249 | ||
@@ -263,11 +303,22 @@ clear_pads(void) { | |||
263 | } | 303 | } |
264 | 304 | ||
265 | void | 305 | void |
306 | draw_poly_scene(void) { | ||
307 | print_number((n_voices / 10) % 10, MAXLED, MAXLED, MAXLED, 0, 0); | ||
308 | print_number( n_voices % 10, MAXLED, MAXLED, MAXLED, 4, 0); | ||
309 | |||
310 | if (active) { | ||
311 | hal_plot_led(TYPEPAD, 11, 0, MAXLED, 0); | ||
312 | } else { | ||
313 | hal_plot_led(TYPEPAD, 11, MAXLED, 0, 0); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | void | ||
266 | render(void) { | 318 | render(void) { |
267 | if (frame++ == 1000 / 10) { | 319 | if (frame++ == 1000 / 10) { |
268 | clear_pads(); | 320 | clear_pads(); |
269 | print_number((n_voices / 10) % 10, MAXLED, MAXLED, MAXLED, 0, 0); | 321 | draw_poly_scene(); |
270 | print_number( n_voices % 10, MAXLED, MAXLED, MAXLED, 4, 0); | ||
271 | frame = 0; | 322 | frame = 0; |
272 | } | 323 | } |
273 | } | 324 | } |