aboutsummaryrefslogtreecommitdiff
path: root/quantum/audio/audio_arm.c
diff options
context:
space:
mode:
authorskullydazed <skullydazed@users.noreply.github.com>2017-09-29 16:17:30 -0700
committerGitHub <noreply@github.com>2017-09-29 16:17:30 -0700
commit5fd68266f5d90b2c7045f44f678d71b782907752 (patch)
tree443e70a3f0dcebadd39a0c96857130546cc690a7 /quantum/audio/audio_arm.c
parentb736f25e85171fceb06f01cf45a45f84dd0a4911 (diff)
downloadqmk_firmware-5fd68266f5d90b2c7045f44f678d71b782907752.tar.gz
qmk_firmware-5fd68266f5d90b2c7045f44f678d71b782907752.zip
Clueboard 60% support (#1746)
* initial clueboard_60 support * LED lighting support * fix the clueboard->clueboard_66 rename * Add layout support to clueboard_60 * Fix the 60_iso layout so it's actually iso * add a default keymap for AEK layout * fix clueboard_17 * Fixup the ISO layouts * Fix the `wait_ms()/wait_us()` definitions for chibios * Fix up the wait_ms/wait_us hack. Reduce stack size. * Add a missing #include "wait.h" * commit files that should have already been comitted
Diffstat (limited to 'quantum/audio/audio_arm.c')
-rw-r--r--quantum/audio/audio_arm.c606
1 files changed, 606 insertions, 0 deletions
diff --git a/quantum/audio/audio_arm.c b/quantum/audio/audio_arm.c
new file mode 100644
index 000000000..5ad0c86ec
--- /dev/null
+++ b/quantum/audio/audio_arm.c
@@ -0,0 +1,606 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "audio.h"
18#include "ch.h"
19#include "hal.h"
20
21#include <stdio.h>
22#include <string.h>
23#include "print.h"
24#include "keymap.h"
25
26#include "eeconfig.h"
27
28// -----------------------------------------------------------------------------
29
30int voices = 0;
31int voice_place = 0;
32float frequency = 0;
33float frequency_alt = 0;
34int volume = 0;
35long position = 0;
36
37float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
38int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
39bool sliding = false;
40
41float place = 0;
42
43uint8_t * sample;
44uint16_t sample_length = 0;
45
46bool playing_notes = false;
47bool playing_note = false;
48float note_frequency = 0;
49float note_length = 0;
50uint8_t note_tempo = TEMPO_DEFAULT;
51float note_timbre = TIMBRE_DEFAULT;
52uint16_t note_position = 0;
53float (* notes_pointer)[][2];
54uint16_t notes_count;
55bool notes_repeat;
56bool note_resting = false;
57
58uint8_t current_note = 0;
59uint8_t rest_counter = 0;
60
61#ifdef VIBRATO_ENABLE
62float vibrato_counter = 0;
63float vibrato_strength = .5;
64float vibrato_rate = 0.125;
65#endif
66
67float polyphony_rate = 0;
68
69static bool audio_initialized = false;
70
71audio_config_t audio_config;
72
73uint16_t envelope_index = 0;
74bool glissando = true;
75
76#ifndef STARTUP_SONG
77 #define STARTUP_SONG SONG(STARTUP_SOUND)
78#endif
79float startup_song[][2] = STARTUP_SONG;
80
81static void gpt_cb6(GPTDriver *gptp);
82static void gpt_cb7(GPTDriver *gptp);
83static void gpt_cb8(GPTDriver *gptp);
84
85/*
86 * GPT6 configuration.
87 */
88GPTConfig gpt6cfg1 = {
89 .frequency = 440,
90 .callback = gpt_cb6,
91 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
92 .dier = 0U
93};
94
95GPTConfig gpt7cfg1 = {
96 .frequency = 440,
97 .callback = gpt_cb7,
98 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
99 .dier = 0U
100};
101
102GPTConfig gpt8cfg1 = {
103 .frequency = 10,
104 .callback = gpt_cb8,
105 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
106 .dier = 0U
107};
108
109static void gpt_cb6(GPTDriver *gptp) {
110 palTogglePad(GPIOA, 4);
111}
112
113
114static void gpt_cb7(GPTDriver *gptp) {
115 palTogglePad(GPIOA, 5);
116}
117
118void audio_init()
119{
120
121 if (audio_initialized)
122 return;
123
124 // Check EEPROM
125 // if (!eeconfig_is_enabled())
126 // {
127 // eeconfig_init();
128 // }
129 // audio_config.raw = eeconfig_read_audio();
130 audio_config.enable = true;
131
132 palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);
133 palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL);
134
135 audio_initialized = true;
136
137 if (audio_config.enable) {
138 PLAY_SONG(startup_song);
139 }
140
141}
142
143void stop_all_notes()
144{
145 dprintf("audio stop all notes");
146
147 if (!audio_initialized) {
148 audio_init();
149 }
150 voices = 0;
151
152 gptStopTimer(&GPTD6);
153 gptStopTimer(&GPTD7);
154 gptStopTimer(&GPTD8);
155
156 playing_notes = false;
157 playing_note = false;
158 frequency = 0;
159 frequency_alt = 0;
160 volume = 0;
161
162 for (uint8_t i = 0; i < 8; i++)
163 {
164 frequencies[i] = 0;
165 volumes[i] = 0;
166 }
167}
168
169void stop_note(float freq)
170{
171 dprintf("audio stop note freq=%d", (int)freq);
172
173 if (playing_note) {
174 if (!audio_initialized) {
175 audio_init();
176 }
177 for (int i = 7; i >= 0; i--) {
178 if (frequencies[i] == freq) {
179 frequencies[i] = 0;
180 volumes[i] = 0;
181 for (int j = i; (j < 7); j++) {
182 frequencies[j] = frequencies[j+1];
183 frequencies[j+1] = 0;
184 volumes[j] = volumes[j+1];
185 volumes[j+1] = 0;
186 }
187 break;
188 }
189 }
190 voices--;
191 if (voices < 0)
192 voices = 0;
193 if (voice_place >= voices) {
194 voice_place = 0;
195 }
196 if (voices == 0) {
197 gptStopTimer(&GPTD6);
198 gptStopTimer(&GPTD7);
199 gptStopTimer(&GPTD8);
200 frequency = 0;
201 frequency_alt = 0;
202 volume = 0;
203 playing_note = false;
204 }
205 }
206}
207
208#ifdef VIBRATO_ENABLE
209
210float mod(float a, int b)
211{
212 float r = fmod(a, b);
213 return r < 0 ? r + b : r;
214}
215
216float vibrato(float average_freq) {
217 #ifdef VIBRATO_STRENGTH_ENABLE
218 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
219 #else
220 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
221 #endif
222 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH);
223 return vibrated_freq;
224}
225
226#endif
227
228static void restart_gpt6(void) {
229 // gptStopTimer(&GPTD6);
230
231 gptStart(&GPTD6, &gpt6cfg1);
232 gptStartContinuous(&GPTD6, 2U);
233}
234
235static void restart_gpt7(void) {
236 // gptStopTimer(&GPTD7);
237
238 gptStart(&GPTD7, &gpt7cfg1);
239 gptStartContinuous(&GPTD7, 2U);
240}
241
242static void gpt_cb8(GPTDriver *gptp) {
243 float freq;
244
245 if (playing_note) {
246 if (voices > 0) {
247
248 float freq_alt = 0;
249 if (voices > 1) {
250 if (polyphony_rate == 0) {
251 if (glissando) {
252 if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440/frequencies[voices - 2]/12/2)) {
253 frequency_alt = frequency_alt * pow(2, 440/frequency_alt/12/2);
254 } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440/frequencies[voices - 2]/12/2)) {
255 frequency_alt = frequency_alt * pow(2, -440/frequency_alt/12/2);
256 } else {
257 frequency_alt = frequencies[voices - 2];
258 }
259 } else {
260 frequency_alt = frequencies[voices - 2];
261 }
262
263 #ifdef VIBRATO_ENABLE
264 if (vibrato_strength > 0) {
265 freq_alt = vibrato(frequency_alt);
266 } else {
267 freq_alt = frequency_alt;
268 }
269 #else
270 freq_alt = frequency_alt;
271 #endif
272 }
273
274 if (envelope_index < 65535) {
275 envelope_index++;
276 }
277
278 freq_alt = voice_envelope(freq_alt);
279
280 if (freq_alt < 30.517578125) {
281 freq_alt = 30.52;
282 }
283
284 if (gpt6cfg1.frequency != (uint16_t)freq_alt) {
285 gpt6cfg1.frequency = freq_alt;
286 restart_gpt6();
287 }
288 //note_timbre;
289 } else {
290 // gptStopTimer(&GPTD6);
291 }
292
293 if (polyphony_rate > 0) {
294 if (voices > 1) {
295 voice_place %= voices;
296 if (place++ > (frequencies[voice_place] / polyphony_rate)) {
297 voice_place = (voice_place + 1) % voices;
298 place = 0.0;
299 }
300 }
301
302 #ifdef VIBRATO_ENABLE
303 if (vibrato_strength > 0) {
304 freq = vibrato(frequencies[voice_place]);
305 } else {
306 freq = frequencies[voice_place];
307 }
308 #else
309 freq = frequencies[voice_place];
310 #endif
311 } else {
312 if (glissando) {
313 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
314 frequency = frequency * pow(2, 440/frequency/12/2);
315 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
316 frequency = frequency * pow(2, -440/frequency/12/2);
317 } else {
318 frequency = frequencies[voices - 1];
319 }
320 } else {
321 frequency = frequencies[voices - 1];
322 }
323
324 #ifdef VIBRATO_ENABLE
325 if (vibrato_strength > 0) {
326 freq = vibrato(frequency);
327 } else {
328 freq = frequency;
329 }
330 #else
331 freq = frequency;
332 #endif
333 }
334
335 if (envelope_index < 65535) {
336 envelope_index++;
337 }
338
339 freq = voice_envelope(freq);
340
341 if (freq < 30.517578125) {
342 freq = 30.52;
343 }
344
345
346 if (gpt7cfg1.frequency != (uint16_t)freq) {
347 gpt7cfg1.frequency = freq;
348 restart_gpt7();
349 }
350 //note_timbre;
351 } else {
352 // gptStopTimer(&GPTD7);
353 }
354 }
355
356 if (playing_notes) {
357 if (note_frequency > 0) {
358 #ifdef VIBRATO_ENABLE
359 if (vibrato_strength > 0) {
360 freq = vibrato(note_frequency);
361 } else {
362 freq = note_frequency;
363 }
364 #else
365 freq = note_frequency;
366 #endif
367
368 if (envelope_index < 65535) {
369 envelope_index++;
370 }
371 freq = voice_envelope(freq);
372
373
374 if (gpt6cfg1.frequency != (uint16_t)freq) {
375 gpt6cfg1.frequency = freq;
376 restart_gpt6();
377 gpt7cfg1.frequency = freq;
378 restart_gpt7();
379 }
380 //note_timbre;
381 } else {
382 // gptStopTimer(&GPTD6);
383 // gptStopTimer(&GPTD7);
384 }
385
386 note_position++;
387 bool end_of_note = false;
388 if (gpt6cfg1.frequency > 0) {
389 if (!note_resting)
390 end_of_note = (note_position >= (note_length*16 - 1));
391 else
392 end_of_note = (note_position >= (note_length*16));
393 } else {
394 end_of_note = (note_position >= (note_length*16));
395 }
396
397 if (end_of_note) {
398 current_note++;
399 if (current_note >= notes_count) {
400 if (notes_repeat) {
401 current_note = 0;
402 } else {
403 gptStopTimer(&GPTD6);
404 gptStopTimer(&GPTD7);
405 // gptStopTimer(&GPTD8);
406 playing_notes = false;
407 return;
408 }
409 }
410 if (!note_resting) {
411 note_resting = true;
412 current_note--;
413 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
414 note_frequency = 0;
415 note_length = 1;
416 } else {
417 note_frequency = (*notes_pointer)[current_note][0];
418 note_length = 1;
419 }
420 } else {
421 note_resting = false;
422 envelope_index = 0;
423 note_frequency = (*notes_pointer)[current_note][0];
424 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
425 }
426
427 note_position = 0;
428 }
429 }
430
431 if (!audio_config.enable) {
432 playing_notes = false;
433 playing_note = false;
434 }
435}
436
437void play_note(float freq, int vol) {
438
439 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
440
441 if (!audio_initialized) {
442 audio_init();
443 }
444
445 if (audio_config.enable && voices < 8) {
446
447 // Cancel notes if notes are playing
448 if (playing_notes)
449 stop_all_notes();
450
451 playing_note = true;
452
453 envelope_index = 0;
454
455 if (freq > 0) {
456 frequencies[voices] = freq;
457 volumes[voices] = vol;
458 voices++;
459 }
460
461 gptStart(&GPTD8, &gpt8cfg1);
462 gptStartContinuous(&GPTD8, 2U);
463
464 }
465
466}
467
468void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat)
469{
470
471 if (!audio_initialized) {
472 audio_init();
473 }
474
475 if (audio_config.enable) {
476
477 // Cancel note if a note is playing
478 if (playing_note)
479 stop_all_notes();
480
481 playing_notes = true;
482
483 notes_pointer = np;
484 notes_count = n_count;
485 notes_repeat = n_repeat;
486
487 place = 0;
488 current_note = 0;
489
490 note_frequency = (*notes_pointer)[current_note][0];
491 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
492 note_position = 0;
493
494 gptStart(&GPTD8, &gpt8cfg1);
495 gptStartContinuous(&GPTD8, 2U);
496 restart_gpt6();
497 restart_gpt7();
498 }
499
500}
501
502bool is_playing_notes(void) {
503 return playing_notes;
504}
505
506bool is_audio_on(void) {
507 return (audio_config.enable != 0);
508}
509
510void audio_toggle(void) {
511 audio_config.enable ^= 1;
512 eeconfig_update_audio(audio_config.raw);
513 if (audio_config.enable)
514 audio_on_user();
515}
516
517void audio_on(void) {
518 audio_config.enable = 1;
519 eeconfig_update_audio(audio_config.raw);
520 audio_on_user();
521}
522
523void audio_off(void) {
524 audio_config.enable = 0;
525 eeconfig_update_audio(audio_config.raw);
526}
527
528#ifdef VIBRATO_ENABLE
529
530// Vibrato rate functions
531
532void set_vibrato_rate(float rate) {
533 vibrato_rate = rate;
534}
535
536void increase_vibrato_rate(float change) {
537 vibrato_rate *= change;
538}
539
540void decrease_vibrato_rate(float change) {
541 vibrato_rate /= change;
542}
543
544#ifdef VIBRATO_STRENGTH_ENABLE
545
546void set_vibrato_strength(float strength) {
547 vibrato_strength = strength;
548}
549
550void increase_vibrato_strength(float change) {
551 vibrato_strength *= change;
552}
553
554void decrease_vibrato_strength(float change) {
555 vibrato_strength /= change;
556}
557
558#endif /* VIBRATO_STRENGTH_ENABLE */
559
560#endif /* VIBRATO_ENABLE */
561
562// Polyphony functions
563
564void set_polyphony_rate(float rate) {
565 polyphony_rate = rate;
566}
567
568void enable_polyphony() {
569 polyphony_rate = 5;
570}
571
572void disable_polyphony() {
573 polyphony_rate = 0;
574}
575
576void increase_polyphony_rate(float change) {
577 polyphony_rate *= change;
578}
579
580void decrease_polyphony_rate(float change) {
581 polyphony_rate /= change;
582}
583
584// Timbre function
585
586void set_timbre(float timbre) {
587 note_timbre = timbre;
588}
589
590// Tempo functions
591
592void set_tempo(uint8_t tempo) {
593 note_tempo = tempo;
594}
595
596void decrease_tempo(uint8_t tempo_change) {
597 note_tempo += tempo_change;
598}
599
600void increase_tempo(uint8_t tempo_change) {
601 if (note_tempo - tempo_change < 10) {
602 note_tempo = 10;
603 } else {
604 note_tempo -= tempo_change;
605 }
606}