aboutsummaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/audio/audio.c539
-rw-r--r--quantum/audio/audio.h280
-rw-r--r--quantum/audio/audio_avr.c810
-rw-r--r--quantum/audio/audio_chibios.c702
-rw-r--r--quantum/audio/audio_pwm.c595
-rw-r--r--quantum/audio/driver_avr_pwm.h17
-rw-r--r--quantum/audio/driver_avr_pwm_hardware.c322
-rw-r--r--quantum/audio/driver_chibios_dac.h126
-rw-r--r--quantum/audio/driver_chibios_dac_additive.c335
-rw-r--r--quantum/audio/driver_chibios_dac_basic.c245
-rw-r--r--quantum/audio/driver_chibios_pwm.h40
-rw-r--r--quantum/audio/driver_chibios_pwm_hardware.c144
-rw-r--r--quantum/audio/driver_chibios_pwm_software.c164
-rw-r--r--quantum/audio/musical_notes.h82
-rw-r--r--quantum/audio/voices.c170
-rw-r--r--quantum/audio/voices.h21
-rw-r--r--quantum/audio/wave.h36
-rw-r--r--quantum/backlight/backlight_avr.c6
-rw-r--r--quantum/command.c12
-rw-r--r--quantum/debounce/sym_defer_pk.c6
-rw-r--r--quantum/debounce/sym_eager_pk.c6
-rw-r--r--quantum/debounce/sym_eager_pr.c6
-rw-r--r--quantum/dynamic_keymap.c2
-rw-r--r--quantum/encoder.c22
-rw-r--r--quantum/encoder.h2
-rw-r--r--quantum/fauxclicky.c59
-rw-r--r--quantum/fauxclicky.h97
-rw-r--r--quantum/keymap_extras/keymap_us_extended.h227
-rw-r--r--quantum/keymap_extras/keymap_us_international.h20
-rw-r--r--quantum/keymap_extras/keymap_us_international_linux.h224
-rw-r--r--quantum/keymap_extras/sendstring_us_international.h100
-rw-r--r--quantum/matrix.c14
-rw-r--r--quantum/matrix.h3
-rw-r--r--quantum/matrix_common.c7
-rw-r--r--quantum/mcu_selection.mk70
-rw-r--r--quantum/mousekey.c488
-rw-r--r--quantum/mousekey.h179
-rw-r--r--quantum/quantum.c62
-rw-r--r--quantum/quantum.h38
-rw-r--r--quantum/quantum_keycodes.h10
-rw-r--r--quantum/rgb_matrix.c6
-rw-r--r--quantum/rgblight.c100
-rw-r--r--quantum/rgblight.h2
-rw-r--r--quantum/split_common/matrix.c44
-rw-r--r--quantum/split_common/transport.c101
45 files changed, 3981 insertions, 2560 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
new file mode 100644
index 000000000..46277dd70
--- /dev/null
+++ b/quantum/audio/audio.c
@@ -0,0 +1,539 @@
1/* Copyright 2016-2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#include "audio.h"
18#include "eeconfig.h"
19#include "timer.h"
20#include "wait.h"
21
22/* audio system:
23 *
24 * audio.[ch] takes care of all overall state, tracking the actively playing
25 * notes/tones; the notes a SONG consists of;
26 * ...
27 * = everything audio-related that is platform agnostic
28 *
29 * driver_[avr|chibios]_[dac|pwm] take care of the lower hardware dependent parts,
30 * specific to each platform and the used subsystem/driver to drive
31 * the output pins/channels with the calculated frequencies for each
32 * active tone
33 * as part of this, the driver has to trigger regular state updates by
34 * calling 'audio_update_state' through some sort of timer - be it a
35 * dedicated one or piggybacking on for example the timer used to
36 * generate a pwm signal/clock.
37 *
38 *
39 * A Note on terminology:
40 * tone, pitch and frequency are used somewhat interchangeably, in a strict Wikipedia-sense:
41 * "(Musical) tone, a sound characterized by its duration, pitch (=frequency),
42 * intensity (=volume), and timbre"
43 * - intensity/volume is currently not handled at all, although the 'dac_additive' driver could do so
44 * - timbre is handled globally (TODO: only used with the pwm drivers at the moment)
45 *
46 * in musical_note.h a 'note' is the combination of a pitch and a duration
47 * these are used to create SONG arrays; during playback their frequencies
48 * are handled as single successive tones, while the durations are
49 * kept track of in 'audio_update_state'
50 *
51 * 'voice' as it is used here, equates to a sort of instrument with its own
52 * characteristics sound and effects
53 * the audio system as-is deals only with (possibly multiple) tones of one
54 * instrument/voice at a time (think: chords). since the number of tones that
55 * can be reproduced depends on the hardware/driver in use: pwm can only
56 * reproduce one tone per output/speaker; DACs can reproduce/mix multiple
57 * when doing additive synthesis.
58 *
59 * 'duration' can either be in the beats-per-minute related unit found in
60 * musical_notes.h, OR in ms; keyboards create SONGs with the former, while
61 * the internal state of the audio system does its calculations with the later - ms
62 */
63
64#ifndef AUDIO_TONE_STACKSIZE
65# define AUDIO_TONE_STACKSIZE 8
66#endif
67uint8_t active_tones = 0; // number of tones pushed onto the stack by audio_play_tone - might be more than the hardware is able to reproduce at any single time
68musical_tone_t tones[AUDIO_TONE_STACKSIZE]; // stack of currently active tones
69
70bool playing_melody = false; // playing a SONG?
71bool playing_note = false; // or (possibly multiple simultaneous) tones
72bool state_changed = false; // global flag, which is set if anything changes with the active_tones
73
74// melody/SONG related state variables
75float (*notes_pointer)[][2]; // SONG, an array of MUSICAL_NOTEs
76uint16_t notes_count; // length of the notes_pointer array
77bool notes_repeat; // PLAY_SONG or PLAY_LOOP?
78uint16_t melody_current_note_duration = 0; // duration of the currently playing note from the active melody, in ms
79uint8_t note_tempo = TEMPO_DEFAULT; // beats-per-minute
80uint16_t current_note = 0; // index into the array at notes_pointer
81bool note_resting = false; // if a short pause was introduced between two notes with the same frequency while playing a melody
82uint16_t last_timestamp = 0;
83
84#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
85# ifndef AUDIO_MAX_SIMULTANEOUS_TONES
86# define AUDIO_MAX_SIMULTANEOUS_TONES 3
87# endif
88uint16_t tone_multiplexing_rate = AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT;
89uint8_t tone_multiplexing_index_shift = 0; // offset used on active-tone array access
90#endif
91
92// provided and used by voices.c
93extern uint8_t note_timbre;
94extern bool glissando;
95extern bool vibrato;
96extern uint16_t voices_timer;
97
98#ifndef STARTUP_SONG
99# define STARTUP_SONG SONG(STARTUP_SOUND)
100#endif
101#ifndef AUDIO_ON_SONG
102# define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND)
103#endif
104#ifndef AUDIO_OFF_SONG
105# define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND)
106#endif
107float startup_song[][2] = STARTUP_SONG;
108float audio_on_song[][2] = AUDIO_ON_SONG;
109float audio_off_song[][2] = AUDIO_OFF_SONG;
110
111static bool audio_initialized = false;
112static bool audio_driver_stopped = true;
113audio_config_t audio_config;
114
115void audio_init() {
116 if (audio_initialized) {
117 return;
118 }
119
120 // Check EEPROM
121#ifdef EEPROM_ENABLE
122 if (!eeconfig_is_enabled()) {
123 eeconfig_init();
124 }
125 audio_config.raw = eeconfig_read_audio();
126#else // EEPROM settings
127 audio_config.enable = true;
128# ifdef AUDIO_CLICKY_ON
129 audio_config.clicky_enable = true;
130# endif
131#endif // EEPROM settings
132
133 for (uint8_t i = 0; i < AUDIO_TONE_STACKSIZE; i++) {
134 tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
135 }
136
137 if (!audio_initialized) {
138 audio_driver_initialize();
139 audio_initialized = true;
140 }
141 stop_all_notes();
142}
143
144void audio_startup(void) {
145 if (audio_config.enable) {
146 PLAY_SONG(startup_song);
147 }
148
149 last_timestamp = timer_read();
150}
151
152void audio_toggle(void) {
153 if (audio_config.enable) {
154 stop_all_notes();
155 }
156 audio_config.enable ^= 1;
157 eeconfig_update_audio(audio_config.raw);
158 if (audio_config.enable) {
159 audio_on_user();
160 }
161}
162
163void audio_on(void) {
164 audio_config.enable = 1;
165 eeconfig_update_audio(audio_config.raw);
166 audio_on_user();
167 PLAY_SONG(audio_on_song);
168}
169
170void audio_off(void) {
171 PLAY_SONG(audio_off_song);
172 wait_ms(100);
173 audio_stop_all();
174 audio_config.enable = 0;
175 eeconfig_update_audio(audio_config.raw);
176}
177
178bool audio_is_on(void) { return (audio_config.enable != 0); }
179
180void audio_stop_all() {
181 if (audio_driver_stopped) {
182 return;
183 }
184
185 active_tones = 0;
186
187 audio_driver_stop();
188
189 playing_melody = false;
190 playing_note = false;
191
192 melody_current_note_duration = 0;
193
194 for (uint8_t i = 0; i < AUDIO_TONE_STACKSIZE; i++) {
195 tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
196 }
197
198 audio_driver_stopped = true;
199}
200
201void audio_stop_tone(float pitch) {
202 if (pitch < 0.0f) {
203 pitch = -1 * pitch;
204 }
205
206 if (playing_note) {
207 if (!audio_initialized) {
208 audio_init();
209 }
210 bool found = false;
211 for (int i = AUDIO_TONE_STACKSIZE - 1; i >= 0; i--) {
212 found = (tones[i].pitch == pitch);
213 if (found) {
214 tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
215 for (int j = i; (j < AUDIO_TONE_STACKSIZE - 1); j++) {
216 tones[j] = tones[j + 1];
217 tones[j + 1] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
218 }
219 break;
220 }
221 }
222 if (!found) {
223 return;
224 }
225
226 state_changed = true;
227 active_tones--;
228 if (active_tones < 0) active_tones = 0;
229#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
230 if (tone_multiplexing_index_shift >= active_tones) {
231 tone_multiplexing_index_shift = 0;
232 }
233#endif
234 if (active_tones == 0) {
235 audio_driver_stop();
236 audio_driver_stopped = true;
237 playing_note = false;
238 }
239 }
240}
241
242void audio_play_note(float pitch, uint16_t duration) {
243 if (!audio_config.enable) {
244 return;
245 }
246
247 if (!audio_initialized) {
248 audio_init();
249 }
250
251 if (pitch < 0.0f) {
252 pitch = -1 * pitch;
253 }
254
255 // round-robin: shifting out old tones, keeping only unique ones
256 // if the new frequency is already amongst the active tones, shift it to the top of the stack
257 bool found = false;
258 for (int i = active_tones - 1; i >= 0; i--) {
259 found = (tones[i].pitch == pitch);
260 if (found) {
261 for (int j = i; (j < active_tones - 1); j++) {
262 tones[j] = tones[j + 1];
263 tones[j + 1] = (musical_tone_t){.time_started = timer_read(), .pitch = pitch, .duration = duration};
264 }
265 return; // since this frequency played already, the hardware was already started
266 }
267 }
268
269 // frequency/tone is actually new, so we put it on the top of the stack
270 active_tones++;
271 if (active_tones > AUDIO_TONE_STACKSIZE) {
272 active_tones = AUDIO_TONE_STACKSIZE;
273 // shift out the oldest tone to make room
274 for (int i = 0; i < active_tones - 1; i++) {
275 tones[i] = tones[i + 1];
276 }
277 }
278 state_changed = true;
279 playing_note = true;
280 tones[active_tones - 1] = (musical_tone_t){.time_started = timer_read(), .pitch = pitch, .duration = duration};
281
282 // TODO: needs to be handled per note/tone -> use its timestamp instead?
283 voices_timer = timer_read(); // reset to zero, for the effects added by voices.c
284
285 if (audio_driver_stopped) {
286 audio_driver_start();
287 audio_driver_stopped = false;
288 }
289}
290
291void audio_play_tone(float pitch) { audio_play_note(pitch, 0xffff); }
292
293void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat) {
294 if (!audio_config.enable) {
295 audio_stop_all();
296 return;
297 }
298
299 if (!audio_initialized) {
300 audio_init();
301 }
302
303 // Cancel note if a note is playing
304 if (playing_note) audio_stop_all();
305
306 playing_melody = true;
307 note_resting = false;
308
309 notes_pointer = np;
310 notes_count = n_count;
311 notes_repeat = n_repeat;
312
313 current_note = 0; // note in the melody-array/list at note_pointer
314
315 // start first note manually, which also starts the audio_driver
316 // all following/remaining notes are played by 'audio_update_state'
317 audio_play_note((*notes_pointer)[current_note][0], audio_duration_to_ms((*notes_pointer)[current_note][1]));
318 last_timestamp = timer_read();
319 melody_current_note_duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
320}
321
322float click[2][2];
323void audio_play_click(uint16_t delay, float pitch, uint16_t duration) {
324 uint16_t duration_tone = audio_ms_to_duration(duration);
325 uint16_t duration_delay = audio_ms_to_duration(delay);
326
327 if (delay <= 0.0f) {
328 click[0][0] = pitch;
329 click[0][1] = duration_tone;
330 click[1][0] = 0.0f;
331 click[1][1] = 0.0f;
332 audio_play_melody(&click, 1, false);
333 } else {
334 // first note is a rest/pause
335 click[0][0] = 0.0f;
336 click[0][1] = duration_delay;
337 // second note is the actual click
338 click[1][0] = pitch;
339 click[1][1] = duration_tone;
340 audio_play_melody(&click, 2, false);
341 }
342}
343
344bool audio_is_playing_note(void) { return playing_note; }
345
346bool audio_is_playing_melody(void) { return playing_melody; }
347
348uint8_t audio_get_number_of_active_tones(void) { return active_tones; }
349
350float audio_get_frequency(uint8_t tone_index) {
351 if (tone_index >= active_tones) {
352 return 0.0f;
353 }
354 return tones[active_tones - tone_index - 1].pitch;
355}
356
357float audio_get_processed_frequency(uint8_t tone_index) {
358 if (tone_index >= active_tones) {
359 return 0.0f;
360 }
361
362 int8_t index = active_tones - tone_index - 1;
363 // new tones are stacked on top (= appended at the end), so the most recent/current is MAX-1
364
365#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
366 index = index - tone_multiplexing_index_shift;
367 if (index < 0) // wrap around
368 index += active_tones;
369#endif
370
371 if (tones[index].pitch <= 0.0f) {
372 return 0.0f;
373 }
374
375 return voice_envelope(tones[index].pitch);
376}
377
378bool audio_update_state(void) {
379 if (!playing_note && !playing_melody) {
380 return false;
381 }
382
383 bool goto_next_note = false;
384 uint16_t current_time = timer_read();
385
386 if (playing_melody) {
387 goto_next_note = timer_elapsed(last_timestamp) >= melody_current_note_duration;
388 if (goto_next_note) {
389 uint16_t delta = timer_elapsed(last_timestamp) - melody_current_note_duration;
390 last_timestamp = current_time;
391 uint16_t previous_note = current_note;
392 current_note++;
393 voices_timer = timer_read(); // reset to zero, for the effects added by voices.c
394
395 if (current_note >= notes_count) {
396 if (notes_repeat) {
397 current_note = 0;
398 } else {
399 audio_stop_all();
400 return false;
401 }
402 }
403
404 if (!note_resting && (*notes_pointer)[previous_note][0] == (*notes_pointer)[current_note][0]) {
405 note_resting = true;
406
407 // special handling for successive notes of the same frequency:
408 // insert a short pause to separate them audibly
409 audio_play_note(0.0f, audio_duration_to_ms(2));
410 current_note = previous_note;
411 melody_current_note_duration = audio_duration_to_ms(2);
412
413 } else {
414 note_resting = false;
415
416 // TODO: handle glissando here (or remember previous and current tone)
417 /* there would need to be a freq(here we are) -> freq(next note)
418 * and do slide/glissando in between problem here is to know which
419 * frequency on the stack relates to what other? e.g. a melody starts
420 * tones in a sequence, and stops expiring one, so the most recently
421 * stopped is the starting point for a glissando to the most recently started?
422 * how to detect and preserve this relation?
423 * and what about user input, chords, ...?
424 */
425
426 // '- delta': Skip forward in the next note's length if we've over shot
427 // the last, so the overall length of the song is the same
428 uint16_t duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
429
430 // Skip forward past any completely missed notes
431 while (delta > duration && current_note < notes_count - 1) {
432 delta -= duration;
433 current_note++;
434 duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
435 }
436
437 if (delta < duration) {
438 duration -= delta;
439 } else {
440 // Only way to get here is if it is the last note and
441 // we have completely missed it. Play it for 1ms...
442 duration = 1;
443 }
444
445 audio_play_note((*notes_pointer)[current_note][0], duration);
446 melody_current_note_duration = duration;
447 }
448 }
449 }
450
451 if (playing_note) {
452#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
453 tone_multiplexing_index_shift = (int)(current_time / tone_multiplexing_rate) % MIN(AUDIO_MAX_SIMULTANEOUS_TONES, active_tones);
454 goto_next_note = true;
455#endif
456 if (vibrato || glissando) {
457 // force update on each cycle, since vibrato shifts the frequency slightly
458 goto_next_note = true;
459 }
460
461 // housekeeping: stop notes that have no playtime left
462 for (int i = 0; i < active_tones; i++) {
463 if ((tones[i].duration != 0xffff) // indefinitely playing notes, started by 'audio_play_tone'
464 && (tones[i].duration != 0) // 'uninitialized'
465 ) {
466 if (timer_elapsed(tones[i].time_started) >= tones[i].duration) {
467 audio_stop_tone(tones[i].pitch); // also sets 'state_changed=true'
468 }
469 }
470 }
471 }
472
473 // state-changes have a higher priority, always triggering the hardware to update
474 if (state_changed) {
475 state_changed = false;
476 return true;
477 }
478
479 return goto_next_note;
480}
481
482// Tone-multiplexing functions
483#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
484void audio_set_tone_multiplexing_rate(uint16_t rate) { tone_multiplexing_rate = rate; }
485void audio_enable_tone_multiplexing(void) { tone_multiplexing_rate = AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT; }
486void audio_disable_tone_multiplexing(void) { tone_multiplexing_rate = 0; }
487void audio_increase_tone_multiplexing_rate(uint16_t change) {
488 if ((0xffff - change) > tone_multiplexing_rate) {
489 tone_multiplexing_rate += change;
490 }
491}
492void audio_decrease_tone_multiplexing_rate(uint16_t change) {
493 if (change <= tone_multiplexing_rate) {
494 tone_multiplexing_rate -= change;
495 }
496}
497#endif
498
499// Tempo functions
500
501void audio_set_tempo(uint8_t tempo) {
502 if (tempo < 10) note_tempo = 10;
503 // else if (tempo > 250)
504 // note_tempo = 250;
505 else
506 note_tempo = tempo;
507}
508
509void audio_increase_tempo(uint8_t tempo_change) {
510 if (tempo_change > 255 - note_tempo)
511 note_tempo = 255;
512 else
513 note_tempo += tempo_change;
514}
515
516void audio_decrease_tempo(uint8_t tempo_change) {
517 if (tempo_change >= note_tempo - 10)
518 note_tempo = 10;
519 else
520 note_tempo -= tempo_change;
521}
522
523// TODO in the int-math version are some bugs; songs sometimes abruptly end - maybe an issue with the timer/system-tick wrapping around?
524uint16_t audio_duration_to_ms(uint16_t duration_bpm) {
525#if defined(__AVR__)
526 // doing int-math saves us some bytes in the overall firmware size, but the intermediate result is less accurate before being cast to/returned as uint
527 return ((uint32_t)duration_bpm * 60 * 1000) / (64 * note_tempo);
528 // NOTE: beware of uint16_t overflows when note_tempo is low and/or the duration is long
529#else
530 return ((float)duration_bpm * 60) / (64 * note_tempo) * 1000;
531#endif
532}
533uint16_t audio_ms_to_duration(uint16_t duration_ms) {
534#if defined(__AVR__)
535 return ((uint32_t)duration_ms * 64 * note_tempo) / 60 / 1000;
536#else
537 return ((float)duration_ms * 64 * note_tempo) / 60 / 1000;
538#endif
539}
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
index bc00cd19e..56b9158a1 100644
--- a/quantum/audio/audio.h
+++ b/quantum/audio/audio.h
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016-2020 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * 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 * it under the terms of the GNU General Public License as published by
@@ -13,28 +14,30 @@
13 * You should have received a copy of the GNU General Public License 14 * 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 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 16 */
16
17#pragma once 17#pragma once
18 18
19#include <stdint.h> 19#include <stdint.h>
20#include <stdbool.h> 20#include <stdbool.h>
21#if defined(__AVR__)
22# include <avr/io.h>
23#endif
24#include "wait.h"
25#include "musical_notes.h" 21#include "musical_notes.h"
26#include "song_list.h" 22#include "song_list.h"
27#include "voices.h" 23#include "voices.h"
28#include "quantum.h" 24#include "quantum.h"
29#include <math.h> 25#include <math.h>
30 26
31// Largely untested PWM audio mode (doesn't sound as good) 27#if defined(__AVR__)
32// #define PWM_AUDIO 28# include <avr/io.h>
33 29# if defined(AUDIO_DRIVER_PWM)
34// #define VIBRATO_ENABLE 30# include "driver_avr_pwm.h"
31# endif
32#endif
35 33
36// Enable vibrato strength/amplitude - slows down ISR too much 34#if defined(PROTOCOL_CHIBIOS)
37// #define VIBRATO_STRENGTH_ENABLE 35# if defined(AUDIO_DRIVER_PWM)
36# include "driver_chibios_pwm.h"
37# elif defined(AUDIO_DRIVER_DAC)
38# include "driver_chibios_dac.h"
39# endif
40#endif
38 41
39typedef union { 42typedef union {
40 uint8_t raw; 43 uint8_t raw;
@@ -45,61 +48,238 @@ typedef union {
45 }; 48 };
46} audio_config_t; 49} audio_config_t;
47 50
48bool is_audio_on(void); 51// AVR/LUFA has a MIN, arm/chibios does not
52#ifndef MIN
53# define MIN(a, b) (((a) < (b)) ? (a) : (b))
54#endif
55
56/*
57 * a 'musical note' is represented by pitch and duration; a 'musical tone' adds intensity and timbre
58 * https://en.wikipedia.org/wiki/Musical_tone
59 * "A musical tone is characterized by its duration, pitch, intensity (or loudness), and timbre (or quality)"
60 */
61typedef struct {
62 uint16_t time_started; // timestamp the tone/note was started, system time runs with 1ms resolution -> 16bit timer overflows every ~64 seconds, long enough under normal circumstances; but might be too soon for long-duration notes when the note_tempo is set to a very low value
63 float pitch; // aka frequency, in Hz
64 uint16_t duration; // in ms, converted from the musical_notes.h unit which has 64parts to a beat, factoring in the current tempo in beats-per-minute
65 // float intensity; // aka volume [0,1] TODO: not used at the moment; pwm drivers can't handle it
66 // uint8_t timbre; // range: [0,100] TODO: this currently kept track of globally, should we do this per tone instead?
67} musical_tone_t;
68
69// public interface
70
71/**
72 * @brief one-time initialization called by quantum/quantum.c
73 * @details usually done lazy, when some tones are to be played
74 *
75 * @post audio system (and hardware) initialized and ready to play tones
76 */
77void audio_init(void);
78void audio_startup(void);
79
80/**
81 * @brief en-/disable audio output, save this choice to the eeprom
82 */
49void audio_toggle(void); 83void audio_toggle(void);
84/**
85 * @brief enable audio output, save this choice to the eeprom
86 */
50void audio_on(void); 87void audio_on(void);
88/**
89 * @brief disable audio output, save this choice to the eeprom
90 */
51void audio_off(void); 91void audio_off(void);
92/**
93 * @brief query the if audio output is enabled
94 */
95bool audio_is_on(void);
96
97/**
98 * @brief start playback of a tone with the given frequency and duration
99 *
100 * @details starts the playback of a given note, which is automatically stopped
101 * at the the end of its duration = fire&forget
102 *
103 * @param[in] pitch frequency of the tone be played
104 * @param[in] duration in milliseconds, use 'audio_duration_to_ms' to convert
105 * from the musical_notes.h unit to ms
106 */
107void audio_play_note(float pitch, uint16_t duration);
108// TODO: audio_play_note(float pitch, uint16_t duration, float intensity, float timbre);
109// audio_play_note_with_instrument ifdef AUDIO_ENABLE_VOICES
110
111/**
112 * @brief start playback of a tone with the given frequency
113 *
114 * @details the 'frequency' is put on-top the internal stack of active tones,
115 * as a new tone with indefinite duration. this tone is played by
116 * the hardware until a call to 'audio_stop_tone'.
117 * should a tone with that frequency already be active, its entry
118 * is put on the top of said internal stack - so no duplicate
119 * entries are kept.
120 * 'hardware_start' is called upon the first note.
121 *
122 * @param[in] pitch frequency of the tone be played
123 */
124void audio_play_tone(float pitch);
125
126/**
127 * @brief stop a given tone/frequency
128 *
129 * @details removes a tone matching the given frequency from the internal
130 * playback stack
131 * the hardware is stopped in case this was the last/only frequency
132 * being played.
133 *
134 * @param[in] pitch tone/frequency to be stopped
135 */
136void audio_stop_tone(float pitch);
52 137
53// Vibrato rate functions 138/**
139 * @brief play a melody
140 *
141 * @details starts playback of a melody passed in from a SONG definition - an
142 * array of {pitch, duration} float-tuples
143 *
144 * @param[in] np note-pointer to the SONG array
145 * @param[in] n_count number of MUSICAL_NOTES of the SONG
146 * @param[in] n_repeat false for onetime, true for looped playback
147 */
148void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat);
54 149
55#ifdef VIBRATO_ENABLE 150/**
151 * @brief play a short tone of a specific frequency to emulate a 'click'
152 *
153 * @details constructs a two-note melody (one pause plus a note) and plays it through
154 * audio_play_melody. very short durations might not quite work due to
155 * hardware limitations (DAC: added pulses from zero-crossing feature;...)
156 *
157 * @param[in] delay in milliseconds, length for the pause before the pulses, can be zero
158 * @param[in] pitch
159 * @param[in] duration in milliseconds, length of the 'click'
160 */
161void audio_play_click(uint16_t delay, float pitch, uint16_t duration);
56 162
57void set_vibrato_rate(float rate); 163/**
58void increase_vibrato_rate(float change); 164 * @brief stops all playback
59void decrease_vibrato_rate(float change); 165 *
166 * @details stops playback of both a melody as well as single tones, resetting
167 * the internal state
168 */
169void audio_stop_all(void);
60 170
61# ifdef VIBRATO_STRENGTH_ENABLE 171/**
172 * @brief query if one/multiple tones are playing
173 */
174bool audio_is_playing_note(void);
62 175
63void set_vibrato_strength(float strength); 176/**
64void increase_vibrato_strength(float change); 177 * @brief query if a melody/SONG is playing
65void decrease_vibrato_strength(float change); 178 */
179bool audio_is_playing_melody(void);
66 180
67# endif 181// These macros are used to allow audio_play_melody to play an array of indeterminate
182// length. This works around the limitation of C's sizeof operation on pointers.
183// The global float array for the song must be used here.
184#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
185
186/**
187 * @brief convenience macro, to play a melody/SONG once
188 */
189#define PLAY_SONG(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), false)
190// TODO: a 'song' is a melody plus singing/vocals -> PLAY_MELODY
191/**
192 * @brief convenience macro, to play a melody/SONG in a loop, until stopped by 'audio_stop_all'
193 */
194#define PLAY_LOOP(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), true)
68 195
196// Tone-Multiplexing functions
197// this feature only makes sense for hardware setups which can't do proper
198// audio-wave synthesis = have no DAC and need to use PWM for tone generation
199#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
200# ifndef AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT
201# define AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 0
202// 0=off, good starting value is 4; the lower the value the higher the cpu-load
203# endif
204void audio_set_tone_multiplexing_rate(uint16_t rate);
205void audio_enable_tone_multiplexing(void);
206void audio_disable_tone_multiplexing(void);
207void audio_increase_tone_multiplexing_rate(uint16_t change);
208void audio_decrease_tone_multiplexing_rate(uint16_t change);
69#endif 209#endif
70 210
71// Polyphony functions 211// Tempo functions
72 212
73void set_polyphony_rate(float rate); 213void audio_set_tempo(uint8_t tempo);
74void enable_polyphony(void); 214void audio_increase_tempo(uint8_t tempo_change);
75void disable_polyphony(void); 215void audio_decrease_tempo(uint8_t tempo_change);
76void increase_polyphony_rate(float change);
77void decrease_polyphony_rate(float change);
78 216
79void set_timbre(float timbre); 217// conversion macros, from 64parts-to-a-beat to milliseconds and back
80void set_tempo(uint8_t tempo); 218uint16_t audio_duration_to_ms(uint16_t duration_bpm);
219uint16_t audio_ms_to_duration(uint16_t duration_ms);
81 220
82void increase_tempo(uint8_t tempo_change); 221void audio_startup(void);
83void decrease_tempo(uint8_t tempo_change);
84 222
85void audio_init(void); 223// hardware interface
86 224
87#ifdef PWM_AUDIO 225// implementation in the driver_avr/arm_* respective parts
88void play_sample(uint8_t* s, uint16_t l, bool r); 226void audio_driver_initialize(void);
89#endif 227void audio_driver_start(void);
90void play_note(float freq, int vol); 228void audio_driver_stop(void);
91void stop_note(float freq);
92void stop_all_notes(void);
93void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat);
94 229
95#define SCALE \ 230/**
96 (int8_t[]) { 0 + (12 * 0), 2 + (12 * 0), 4 + (12 * 0), 5 + (12 * 0), 7 + (12 * 0), 9 + (12 * 0), 11 + (12 * 0), 0 + (12 * 1), 2 + (12 * 1), 4 + (12 * 1), 5 + (12 * 1), 7 + (12 * 1), 9 + (12 * 1), 11 + (12 * 1), 0 + (12 * 2), 2 + (12 * 2), 4 + (12 * 2), 5 + (12 * 2), 7 + (12 * 2), 9 + (12 * 2), 11 + (12 * 2), 0 + (12 * 3), 2 + (12 * 3), 4 + (12 * 3), 5 + (12 * 3), 7 + (12 * 3), 9 + (12 * 3), 11 + (12 * 3), 0 + (12 * 4), 2 + (12 * 4), 4 + (12 * 4), 5 + (12 * 4), 7 + (12 * 4), 9 + (12 * 4), 11 + (12 * 4), } 231 * @brief get the number of currently active tones
232 * @return number, 0=none active
233 */
234uint8_t audio_get_number_of_active_tones(void);
97 235
98// These macros are used to allow play_notes to play an array of indeterminate 236/**
99// length. This works around the limitation of C's sizeof operation on pointers. 237 * @brief access to the raw/unprocessed frequency for a specific tone
100// The global float array for the song must be used here. 238 * @details each active tone has a frequency associated with it, which
101#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) 239 * the internal state keeps track of, and is usually influenced
102#define PLAY_SONG(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), false) 240 * by various effects
103#define PLAY_LOOP(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), true) 241 * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
242 * first being the most recent and each increment yielding the next
243 * older one
244 * @return a positive frequency, in Hz; or zero if the tone is a pause
245 */
246float audio_get_frequency(uint8_t tone_index);
247
248/**
249 * @brief calculate and return the frequency for the requested tone
250 * @details effects like glissando, vibrato, ... are post-processed onto the
251 * each active tones 'base'-frequency; this function returns the
252 * post-processed result.
253 * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
254 * first being the most recent and each increment yielding the next
255 * older one
256 * @return a positive frequency, in Hz; or zero if the tone is a pause
257 */
258float audio_get_processed_frequency(uint8_t tone_index);
259
260/**
261 * @brief update audio internal state: currently playing and active tones,...
262 * @details This function is intended to be called by the audio-hardware
263 * specific implementation on a somewhat regular basis while a SONG
264 * or notes (pitch+duration) are playing to 'advance' the internal
265 * state (current playing notes, position in the melody, ...)
266 *
267 * @return true if something changed in the currently active tones, which the
268 * hardware might need to react to
269 */
270bool audio_update_state(void);
271
272// legacy and back-warts compatibility stuff
273
274#define is_audio_on() audio_is_on()
275#define is_playing_notes() audio_is_playing_melody()
276#define is_playing_note() audio_is_playing_note()
277#define stop_all_notes() audio_stop_all()
278#define stop_note(f) audio_stop_tone(f)
279#define play_note(f, v) audio_play_tone(f)
104 280
105bool is_playing_notes(void); 281#define set_timbre(t) voice_set_timbre(t)
282#define set_tempo(t) audio_set_tempo(t)
283#define increase_tempo(t) audio_increase_tempo(t)
284#define decrease_tempo(t) audio_decrease_tempo(t)
285// vibrato functions are not used in any keyboards
diff --git a/quantum/audio/audio_avr.c b/quantum/audio/audio_avr.c
deleted file mode 100644
index 5a96bf643..000000000
--- a/quantum/audio/audio_avr.c
+++ /dev/null
@@ -1,810 +0,0 @@
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 <stdio.h>
18#include <string.h>
19//#include <math.h>
20#if defined(__AVR__)
21# include <avr/pgmspace.h>
22# include <avr/interrupt.h>
23# include <avr/io.h>
24#endif
25#include "print.h"
26#include "audio.h"
27#include "keymap.h"
28#include "wait.h"
29
30#include "eeconfig.h"
31
32#define CPU_PRESCALER 8
33
34// -----------------------------------------------------------------------------
35// Timer Abstractions
36// -----------------------------------------------------------------------------
37
38// Currently we support timers 1 and 3 used at the sime time, channels A-C,
39// pins PB5, PB6, PB7, PC4, PC5, and PC6
40#if defined(C6_AUDIO)
41# define CPIN_AUDIO
42# define CPIN_SET_DIRECTION DDRC |= _BV(PORTC6);
43# define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
44# define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
45# define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
46# define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
47# define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
48# define TIMER_3_PERIOD ICR3
49# define TIMER_3_DUTY_CYCLE OCR3A
50# define TIMER3_AUDIO_vect TIMER3_COMPA_vect
51#endif
52#if defined(C5_AUDIO)
53# define CPIN_AUDIO
54# define CPIN_SET_DIRECTION DDRC |= _BV(PORTC5);
55# define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3B1) | (0 << COM3B0) | (1 << WGM31) | (0 << WGM30);
56# define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3B)
57# define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3B)
58# define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3B1);
59# define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3B1) | _BV(COM3B0));
60# define TIMER_3_PERIOD ICR3
61# define TIMER_3_DUTY_CYCLE OCR3B
62# define TIMER3_AUDIO_vect TIMER3_COMPB_vect
63#endif
64#if defined(C4_AUDIO)
65# define CPIN_AUDIO
66# define CPIN_SET_DIRECTION DDRC |= _BV(PORTC4);
67# define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3C1) | (0 << COM3C0) | (1 << WGM31) | (0 << WGM30);
68# define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3C)
69# define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3C)
70# define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3C1);
71# define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3C1) | _BV(COM3C0));
72# define TIMER_3_PERIOD ICR3
73# define TIMER_3_DUTY_CYCLE OCR3C
74# define TIMER3_AUDIO_vect TIMER3_COMPC_vect
75#endif
76
77#if defined(B5_AUDIO)
78# define BPIN_AUDIO
79# define BPIN_SET_DIRECTION DDRB |= _BV(PORTB5);
80# define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << WGM11) | (0 << WGM10);
81# define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1A)
82# define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1A)
83# define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1A1);
84# define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0));
85# define TIMER_1_PERIOD ICR1
86# define TIMER_1_DUTY_CYCLE OCR1A
87# define TIMER1_AUDIO_vect TIMER1_COMPA_vect
88#endif
89#if defined(B6_AUDIO)
90# define BPIN_AUDIO
91# define BPIN_SET_DIRECTION DDRB |= _BV(PORTB6);
92# define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1B1) | (0 << COM1B0) | (1 << WGM11) | (0 << WGM10);
93# define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1B)
94# define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1B)
95# define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1B1);
96# define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1B1) | _BV(COM1B0));
97# define TIMER_1_PERIOD ICR1
98# define TIMER_1_DUTY_CYCLE OCR1B
99# define TIMER1_AUDIO_vect TIMER1_COMPB_vect
100#endif
101#if defined(B7_AUDIO)
102# define BPIN_AUDIO
103# define BPIN_SET_DIRECTION DDRB |= _BV(PORTB7);
104# define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1C1) | (0 << COM1C0) | (1 << WGM11) | (0 << WGM10);
105# define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1C)
106# define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1C)
107# define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1C1);
108# define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1C1) | _BV(COM1C0));
109# define TIMER_1_PERIOD ICR1
110# define TIMER_1_DUTY_CYCLE OCR1C
111# define TIMER1_AUDIO_vect TIMER1_COMPC_vect
112#endif
113
114#if !defined(BPIN_AUDIO) && !defined(CPIN_AUDIO)
115# error "Audio feature enabled, but no suitable pin selected - see docs/feature_audio.md under the AVR settings for available options."
116#endif
117
118// -----------------------------------------------------------------------------
119
120int voices = 0;
121int voice_place = 0;
122float frequency = 0;
123float frequency_alt = 0;
124int volume = 0;
125long position = 0;
126
127float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
128int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
129bool sliding = false;
130
131float place = 0;
132
133uint8_t* sample;
134uint16_t sample_length = 0;
135
136bool playing_notes = false;
137bool playing_note = false;
138float note_frequency = 0;
139float note_length = 0;
140uint8_t note_tempo = TEMPO_DEFAULT;
141float note_timbre = TIMBRE_DEFAULT;
142uint16_t note_position = 0;
143float (*notes_pointer)[][2];
144uint16_t notes_count;
145bool notes_repeat;
146bool note_resting = false;
147
148uint16_t current_note = 0;
149uint8_t rest_counter = 0;
150
151#ifdef VIBRATO_ENABLE
152float vibrato_counter = 0;
153float vibrato_strength = .5;
154float vibrato_rate = 0.125;
155#endif
156
157float polyphony_rate = 0;
158
159static bool audio_initialized = false;
160
161audio_config_t audio_config;
162
163uint16_t envelope_index = 0;
164bool glissando = true;
165
166#ifndef STARTUP_SONG
167# define STARTUP_SONG SONG(STARTUP_SOUND)
168#endif
169#ifndef AUDIO_ON_SONG
170# define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND)
171#endif
172#ifndef AUDIO_OFF_SONG
173# define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND)
174#endif
175float startup_song[][2] = STARTUP_SONG;
176float audio_on_song[][2] = AUDIO_ON_SONG;
177float audio_off_song[][2] = AUDIO_OFF_SONG;
178
179void audio_init() {
180 // Check EEPROM
181 if (!eeconfig_is_enabled()) {
182 eeconfig_init();
183 }
184 audio_config.raw = eeconfig_read_audio();
185
186 if (!audio_initialized) {
187// Set audio ports as output
188#ifdef CPIN_AUDIO
189 CPIN_SET_DIRECTION
190 DISABLE_AUDIO_COUNTER_3_ISR;
191#endif
192#ifdef BPIN_AUDIO
193 BPIN_SET_DIRECTION
194 DISABLE_AUDIO_COUNTER_1_ISR;
195#endif
196
197// TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
198// Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
199// OC3A -- PC6
200// OC3B -- PC5
201// OC3C -- PC4
202// OC1A -- PB5
203// OC1B -- PB6
204// OC1C -- PB7
205
206// Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
207// OCR3A - PC6
208// OCR3B - PC5
209// OCR3C - PC4
210// OCR1A - PB5
211// OCR1B - PB6
212// OCR1C - PB7
213
214// Clock Select (CS3n) = 0b010 = Clock / 8
215#ifdef CPIN_AUDIO
216 INIT_AUDIO_COUNTER_3
217 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
218 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER));
219 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre);
220#endif
221#ifdef BPIN_AUDIO
222 INIT_AUDIO_COUNTER_1
223 TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10);
224 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER));
225 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre);
226#endif
227
228 audio_initialized = true;
229 }
230
231 if (audio_config.enable) {
232 PLAY_SONG(startup_song);
233 }
234}
235
236void stop_all_notes() {
237 dprintf("audio stop all notes");
238
239 if (!audio_initialized) {
240 audio_init();
241 }
242 voices = 0;
243
244#ifdef CPIN_AUDIO
245 DISABLE_AUDIO_COUNTER_3_ISR;
246 DISABLE_AUDIO_COUNTER_3_OUTPUT;
247#endif
248
249#ifdef BPIN_AUDIO
250 DISABLE_AUDIO_COUNTER_1_ISR;
251 DISABLE_AUDIO_COUNTER_1_OUTPUT;
252#endif
253
254 playing_notes = false;
255 playing_note = false;
256 frequency = 0;
257 frequency_alt = 0;
258 volume = 0;
259
260 for (uint8_t i = 0; i < 8; i++) {
261 frequencies[i] = 0;
262 volumes[i] = 0;
263 }
264}
265
266void stop_note(float freq) {
267 dprintf("audio stop note freq=%d", (int)freq);
268
269 if (playing_note) {
270 if (!audio_initialized) {
271 audio_init();
272 }
273 for (int i = 7; i >= 0; i--) {
274 if (frequencies[i] == freq) {
275 frequencies[i] = 0;
276 volumes[i] = 0;
277 for (int j = i; (j < 7); j++) {
278 frequencies[j] = frequencies[j + 1];
279 frequencies[j + 1] = 0;
280 volumes[j] = volumes[j + 1];
281 volumes[j + 1] = 0;
282 }
283 break;
284 }
285 }
286 voices--;
287 if (voices < 0) voices = 0;
288 if (voice_place >= voices) {
289 voice_place = 0;
290 }
291 if (voices == 0) {
292#ifdef CPIN_AUDIO
293 DISABLE_AUDIO_COUNTER_3_ISR;
294 DISABLE_AUDIO_COUNTER_3_OUTPUT;
295#endif
296#ifdef BPIN_AUDIO
297 DISABLE_AUDIO_COUNTER_1_ISR;
298 DISABLE_AUDIO_COUNTER_1_OUTPUT;
299#endif
300 frequency = 0;
301 frequency_alt = 0;
302 volume = 0;
303 playing_note = false;
304 }
305 }
306}
307
308#ifdef VIBRATO_ENABLE
309
310float mod(float a, int b) {
311 float r = fmod(a, b);
312 return r < 0 ? r + b : r;
313}
314
315float vibrato(float average_freq) {
316# ifdef VIBRATO_STRENGTH_ENABLE
317 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
318# else
319 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
320# endif
321 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
322 return vibrated_freq;
323}
324
325#endif
326
327#ifdef CPIN_AUDIO
328ISR(TIMER3_AUDIO_vect) {
329 float freq;
330
331 if (playing_note) {
332 if (voices > 0) {
333# ifdef BPIN_AUDIO
334 float freq_alt = 0;
335 if (voices > 1) {
336 if (polyphony_rate == 0) {
337 if (glissando) {
338 if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) {
339 frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2);
340 } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) {
341 frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2);
342 } else {
343 frequency_alt = frequencies[voices - 2];
344 }
345 } else {
346 frequency_alt = frequencies[voices - 2];
347 }
348
349# ifdef VIBRATO_ENABLE
350 if (vibrato_strength > 0) {
351 freq_alt = vibrato(frequency_alt);
352 } else {
353 freq_alt = frequency_alt;
354 }
355# else
356 freq_alt = frequency_alt;
357# endif
358 }
359
360 if (envelope_index < 65535) {
361 envelope_index++;
362 }
363
364 freq_alt = voice_envelope(freq_alt);
365
366 if (freq_alt < 30.517578125) {
367 freq_alt = 30.52;
368 }
369
370 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq_alt * CPU_PRESCALER));
371 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq_alt * CPU_PRESCALER)) * note_timbre);
372 }
373# endif
374
375 if (polyphony_rate > 0) {
376 if (voices > 1) {
377 voice_place %= voices;
378 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
379 voice_place = (voice_place + 1) % voices;
380 place = 0.0;
381 }
382 }
383
384# ifdef VIBRATO_ENABLE
385 if (vibrato_strength > 0) {
386 freq = vibrato(frequencies[voice_place]);
387 } else {
388 freq = frequencies[voice_place];
389 }
390# else
391 freq = frequencies[voice_place];
392# endif
393 } else {
394 if (glissando) {
395 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
396 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
397 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
398 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
399 } else {
400 frequency = frequencies[voices - 1];
401 }
402 } else {
403 frequency = frequencies[voices - 1];
404 }
405
406# ifdef VIBRATO_ENABLE
407 if (vibrato_strength > 0) {
408 freq = vibrato(frequency);
409 } else {
410 freq = frequency;
411 }
412# else
413 freq = frequency;
414# endif
415 }
416
417 if (envelope_index < 65535) {
418 envelope_index++;
419 }
420
421 freq = voice_envelope(freq);
422
423 if (freq < 30.517578125) {
424 freq = 30.52;
425 }
426
427 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
428 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
429 }
430 }
431
432 if (playing_notes) {
433 if (note_frequency > 0) {
434# ifdef VIBRATO_ENABLE
435 if (vibrato_strength > 0) {
436 freq = vibrato(note_frequency);
437 } else {
438 freq = note_frequency;
439 }
440# else
441 freq = note_frequency;
442# endif
443
444 if (envelope_index < 65535) {
445 envelope_index++;
446 }
447 freq = voice_envelope(freq);
448
449 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
450 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
451 } else {
452 TIMER_3_PERIOD = 0;
453 TIMER_3_DUTY_CYCLE = 0;
454 }
455
456 note_position++;
457 bool end_of_note = false;
458 if (TIMER_3_PERIOD > 0) {
459 if (!note_resting)
460 end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF - 1));
461 else
462 end_of_note = (note_position >= (note_length));
463 } else {
464 end_of_note = (note_position >= (note_length));
465 }
466
467 if (end_of_note) {
468 current_note++;
469 if (current_note >= notes_count) {
470 if (notes_repeat) {
471 current_note = 0;
472 } else {
473 DISABLE_AUDIO_COUNTER_3_ISR;
474 DISABLE_AUDIO_COUNTER_3_OUTPUT;
475 playing_notes = false;
476 return;
477 }
478 }
479 if (!note_resting) {
480 note_resting = true;
481 current_note--;
482 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
483 note_frequency = 0;
484 note_length = 1;
485 } else {
486 note_frequency = (*notes_pointer)[current_note][0];
487 note_length = 1;
488 }
489 } else {
490 note_resting = false;
491 envelope_index = 0;
492 note_frequency = (*notes_pointer)[current_note][0];
493 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
494 }
495
496 note_position = 0;
497 }
498 }
499
500 if (!audio_config.enable) {
501 playing_notes = false;
502 playing_note = false;
503 }
504}
505#endif
506
507#ifdef BPIN_AUDIO
508ISR(TIMER1_AUDIO_vect) {
509# if defined(BPIN_AUDIO) && !defined(CPIN_AUDIO)
510 float freq = 0;
511
512 if (playing_note) {
513 if (voices > 0) {
514 if (polyphony_rate > 0) {
515 if (voices > 1) {
516 voice_place %= voices;
517 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
518 voice_place = (voice_place + 1) % voices;
519 place = 0.0;
520 }
521 }
522
523# ifdef VIBRATO_ENABLE
524 if (vibrato_strength > 0) {
525 freq = vibrato(frequencies[voice_place]);
526 } else {
527 freq = frequencies[voice_place];
528 }
529# else
530 freq = frequencies[voice_place];
531# endif
532 } else {
533 if (glissando) {
534 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
535 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
536 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
537 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
538 } else {
539 frequency = frequencies[voices - 1];
540 }
541 } else {
542 frequency = frequencies[voices - 1];
543 }
544
545# ifdef VIBRATO_ENABLE
546 if (vibrato_strength > 0) {
547 freq = vibrato(frequency);
548 } else {
549 freq = frequency;
550 }
551# else
552 freq = frequency;
553# endif
554 }
555
556 if (envelope_index < 65535) {
557 envelope_index++;
558 }
559
560 freq = voice_envelope(freq);
561
562 if (freq < 30.517578125) {
563 freq = 30.52;
564 }
565
566 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
567 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
568 }
569 }
570
571 if (playing_notes) {
572 if (note_frequency > 0) {
573# ifdef VIBRATO_ENABLE
574 if (vibrato_strength > 0) {
575 freq = vibrato(note_frequency);
576 } else {
577 freq = note_frequency;
578 }
579# else
580 freq = note_frequency;
581# endif
582
583 if (envelope_index < 65535) {
584 envelope_index++;
585 }
586 freq = voice_envelope(freq);
587
588 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
589 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
590 } else {
591 TIMER_1_PERIOD = 0;
592 TIMER_1_DUTY_CYCLE = 0;
593 }
594
595 note_position++;
596 bool end_of_note = false;
597 if (TIMER_1_PERIOD > 0) {
598 if (!note_resting)
599 end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF - 1));
600 else
601 end_of_note = (note_position >= (note_length));
602 } else {
603 end_of_note = (note_position >= (note_length));
604 }
605
606 if (end_of_note) {
607 current_note++;
608 if (current_note >= notes_count) {
609 if (notes_repeat) {
610 current_note = 0;
611 } else {
612 DISABLE_AUDIO_COUNTER_1_ISR;
613 DISABLE_AUDIO_COUNTER_1_OUTPUT;
614 playing_notes = false;
615 return;
616 }
617 }
618 if (!note_resting) {
619 note_resting = true;
620 current_note--;
621 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
622 note_frequency = 0;
623 note_length = 1;
624 } else {
625 note_frequency = (*notes_pointer)[current_note][0];
626 note_length = 1;
627 }
628 } else {
629 note_resting = false;
630 envelope_index = 0;
631 note_frequency = (*notes_pointer)[current_note][0];
632 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
633 }
634
635 note_position = 0;
636 }
637 }
638
639 if (!audio_config.enable) {
640 playing_notes = false;
641 playing_note = false;
642 }
643# endif
644}
645#endif
646
647void play_note(float freq, int vol) {
648 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
649
650 if (!audio_initialized) {
651 audio_init();
652 }
653
654 if (audio_config.enable && voices < 8) {
655#ifdef CPIN_AUDIO
656 DISABLE_AUDIO_COUNTER_3_ISR;
657#endif
658#ifdef BPIN_AUDIO
659 DISABLE_AUDIO_COUNTER_1_ISR;
660#endif
661
662 // Cancel notes if notes are playing
663 if (playing_notes) stop_all_notes();
664
665 playing_note = true;
666
667 envelope_index = 0;
668
669 if (freq > 0) {
670 frequencies[voices] = freq;
671 volumes[voices] = vol;
672 voices++;
673 }
674
675#ifdef CPIN_AUDIO
676 ENABLE_AUDIO_COUNTER_3_ISR;
677 ENABLE_AUDIO_COUNTER_3_OUTPUT;
678#endif
679#ifdef BPIN_AUDIO
680# ifdef CPIN_AUDIO
681 if (voices > 1) {
682 ENABLE_AUDIO_COUNTER_1_ISR;
683 ENABLE_AUDIO_COUNTER_1_OUTPUT;
684 }
685# else
686 ENABLE_AUDIO_COUNTER_1_ISR;
687 ENABLE_AUDIO_COUNTER_1_OUTPUT;
688# endif
689#endif
690 }
691}
692
693void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) {
694 if (!audio_initialized) {
695 audio_init();
696 }
697
698 if (audio_config.enable) {
699#ifdef CPIN_AUDIO
700 DISABLE_AUDIO_COUNTER_3_ISR;
701#endif
702#ifdef BPIN_AUDIO
703 DISABLE_AUDIO_COUNTER_1_ISR;
704#endif
705
706 // Cancel note if a note is playing
707 if (playing_note) stop_all_notes();
708
709 playing_notes = true;
710
711 notes_pointer = np;
712 notes_count = n_count;
713 notes_repeat = n_repeat;
714
715 place = 0;
716 current_note = 0;
717
718 note_frequency = (*notes_pointer)[current_note][0];
719 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
720 note_position = 0;
721
722#ifdef CPIN_AUDIO
723 ENABLE_AUDIO_COUNTER_3_ISR;
724 ENABLE_AUDIO_COUNTER_3_OUTPUT;
725#endif
726#ifdef BPIN_AUDIO
727# ifndef CPIN_AUDIO
728 ENABLE_AUDIO_COUNTER_1_ISR;
729 ENABLE_AUDIO_COUNTER_1_OUTPUT;
730# endif
731#endif
732 }
733}
734
735bool is_playing_notes(void) { return playing_notes; }
736
737bool is_audio_on(void) { return (audio_config.enable != 0); }
738
739void audio_toggle(void) {
740 audio_config.enable ^= 1;
741 eeconfig_update_audio(audio_config.raw);
742 if (audio_config.enable) audio_on_user();
743}
744
745void audio_on(void) {
746 audio_config.enable = 1;
747 eeconfig_update_audio(audio_config.raw);
748 audio_on_user();
749 PLAY_SONG(audio_on_song);
750}
751
752void audio_off(void) {
753 PLAY_SONG(audio_off_song);
754 wait_ms(100);
755 stop_all_notes();
756 audio_config.enable = 0;
757 eeconfig_update_audio(audio_config.raw);
758}
759
760#ifdef VIBRATO_ENABLE
761
762// Vibrato rate functions
763
764void set_vibrato_rate(float rate) { vibrato_rate = rate; }
765
766void increase_vibrato_rate(float change) { vibrato_rate *= change; }
767
768void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
769
770# ifdef VIBRATO_STRENGTH_ENABLE
771
772void set_vibrato_strength(float strength) { vibrato_strength = strength; }
773
774void increase_vibrato_strength(float change) { vibrato_strength *= change; }
775
776void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
777
778# endif /* VIBRATO_STRENGTH_ENABLE */
779
780#endif /* VIBRATO_ENABLE */
781
782// Polyphony functions
783
784void set_polyphony_rate(float rate) { polyphony_rate = rate; }
785
786void enable_polyphony() { polyphony_rate = 5; }
787
788void disable_polyphony() { polyphony_rate = 0; }
789
790void increase_polyphony_rate(float change) { polyphony_rate *= change; }
791
792void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
793
794// Timbre function
795
796void set_timbre(float timbre) { note_timbre = timbre; }
797
798// Tempo functions
799
800void set_tempo(uint8_t tempo) { note_tempo = tempo; }
801
802void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
803
804void increase_tempo(uint8_t tempo_change) {
805 if (note_tempo - tempo_change < 10) {
806 note_tempo = 10;
807 } else {
808 note_tempo -= tempo_change;
809 }
810}
diff --git a/quantum/audio/audio_chibios.c b/quantum/audio/audio_chibios.c
deleted file mode 100644
index 1f147f2c9..000000000
--- a/quantum/audio/audio_chibios.c
+++ /dev/null
@@ -1,702 +0,0 @@
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 <string.h>
22#include "print.h"
23#include "keymap.h"
24
25#include "eeconfig.h"
26
27// -----------------------------------------------------------------------------
28
29int voices = 0;
30int voice_place = 0;
31float frequency = 0;
32float frequency_alt = 0;
33int volume = 0;
34long position = 0;
35
36float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
37int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
38bool sliding = false;
39
40float place = 0;
41
42uint8_t *sample;
43uint16_t sample_length = 0;
44
45bool playing_notes = false;
46bool playing_note = false;
47float note_frequency = 0;
48float note_length = 0;
49uint8_t note_tempo = TEMPO_DEFAULT;
50float note_timbre = TIMBRE_DEFAULT;
51uint16_t note_position = 0;
52float (*notes_pointer)[][2];
53uint16_t notes_count;
54bool notes_repeat;
55bool note_resting = false;
56
57uint16_t current_note = 0;
58uint8_t rest_counter = 0;
59
60#ifdef VIBRATO_ENABLE
61float vibrato_counter = 0;
62float vibrato_strength = .5;
63float vibrato_rate = 0.125;
64#endif
65
66float polyphony_rate = 0;
67
68static bool audio_initialized = false;
69
70audio_config_t audio_config;
71
72uint16_t envelope_index = 0;
73bool glissando = true;
74
75#ifndef STARTUP_SONG
76# define STARTUP_SONG SONG(STARTUP_SOUND)
77#endif
78float startup_song[][2] = STARTUP_SONG;
79
80static void gpt_cb8(GPTDriver *gptp);
81
82#define DAC_BUFFER_SIZE 100
83#ifndef DAC_SAMPLE_MAX
84# define DAC_SAMPLE_MAX 65535U
85#endif
86
87#define START_CHANNEL_1() \
88 gptStart(&GPTD6, &gpt6cfg1); \
89 gptStartContinuous(&GPTD6, 2U)
90#define START_CHANNEL_2() \
91 gptStart(&GPTD7, &gpt7cfg1); \
92 gptStartContinuous(&GPTD7, 2U)
93#define STOP_CHANNEL_1() gptStopTimer(&GPTD6)
94#define STOP_CHANNEL_2() gptStopTimer(&GPTD7)
95#define RESTART_CHANNEL_1() \
96 STOP_CHANNEL_1(); \
97 START_CHANNEL_1()
98#define RESTART_CHANNEL_2() \
99 STOP_CHANNEL_2(); \
100 START_CHANNEL_2()
101#define UPDATE_CHANNEL_1_FREQ(freq) \
102 gpt6cfg1.frequency = freq * DAC_BUFFER_SIZE; \
103 RESTART_CHANNEL_1()
104#define UPDATE_CHANNEL_2_FREQ(freq) \
105 gpt7cfg1.frequency = freq * DAC_BUFFER_SIZE; \
106 RESTART_CHANNEL_2()
107#define GET_CHANNEL_1_FREQ (uint16_t)(gpt6cfg1.frequency * DAC_BUFFER_SIZE)
108#define GET_CHANNEL_2_FREQ (uint16_t)(gpt7cfg1.frequency * DAC_BUFFER_SIZE)
109
110/*
111 * GPT6 configuration.
112 */
113// static const GPTConfig gpt6cfg1 = {
114// .frequency = 1000000U,
115// .callback = NULL,
116// .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
117// .dier = 0U
118// };
119
120GPTConfig gpt6cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE,
121 .callback = NULL,
122 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
123 .dier = 0U};
124
125GPTConfig gpt7cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE,
126 .callback = NULL,
127 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
128 .dier = 0U};
129
130GPTConfig gpt8cfg1 = {.frequency = 10,
131 .callback = gpt_cb8,
132 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
133 .dier = 0U};
134
135/*
136 * DAC test buffer (sine wave).
137 */
138// static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = {
139// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437,
140// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846,
141// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221,
142// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544,
143// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801,
144// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982,
145// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078,
146// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086,
147// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004,
148// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837,
149// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591,
150// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278,
151// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912,
152// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507,
153// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082,
154// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657,
155// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248,
156// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873,
157// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550,
158// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293,
159// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112,
160// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16,
161// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8,
162// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90,
163// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257,
164// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503,
165// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816,
166// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182,
167// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587,
168// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012
169// };
170
171// static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = {
172// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8,
173// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90,
174// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257,
175// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503,
176// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816,
177// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182,
178// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587,
179// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012,
180// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437,
181// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846,
182// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221,
183// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544,
184// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801,
185// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982,
186// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078,
187// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086,
188// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004,
189// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837,
190// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591,
191// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278,
192// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912,
193// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507,
194// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082,
195// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657,
196// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248,
197// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873,
198// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550,
199// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293,
200// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112,
201// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16
202// };
203
204// squarewave
205static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = {
206 // First half is max, second half is 0
207 [0 ... DAC_BUFFER_SIZE / 2 - 1] = DAC_SAMPLE_MAX,
208 [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = 0,
209};
210
211// squarewave
212static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = {
213 // opposite of dac_buffer above
214 [0 ... DAC_BUFFER_SIZE / 2 - 1] = 0,
215 [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = DAC_SAMPLE_MAX,
216};
217
218/*
219 * DAC streaming callback.
220 */
221size_t nz = 0;
222static void end_cb1(DACDriver *dacp) {
223 (void)dacp;
224
225 nz++;
226 if ((nz % 1000) == 0) {
227 // palTogglePad(GPIOD, GPIOD_LED3);
228 }
229}
230
231/*
232 * DAC error callback.
233 */
234static void error_cb1(DACDriver *dacp, dacerror_t err) {
235 (void)dacp;
236 (void)err;
237
238 chSysHalt("DAC failure");
239}
240
241static const DACConfig dac1cfg1 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT};
242
243static const DACConversionGroup dacgrpcfg1 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)};
244
245static const DACConfig dac1cfg2 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT};
246
247static const DACConversionGroup dacgrpcfg2 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)};
248
249void audio_init() {
250 if (audio_initialized) {
251 return;
252 }
253
254// Check EEPROM
255#ifdef EEPROM_ENABLE
256 if (!eeconfig_is_enabled()) {
257 eeconfig_init();
258 }
259 audio_config.raw = eeconfig_read_audio();
260#else // ARM EEPROM
261 audio_config.enable = true;
262# ifdef AUDIO_CLICKY_ON
263 audio_config.clicky_enable = true;
264# endif
265#endif // ARM EEPROM
266
267 /*
268 * Starting DAC1 driver, setting up the output pin as analog as suggested
269 * by the Reference Manual.
270 */
271 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
272 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
273 dacStart(&DACD1, &dac1cfg1);
274 dacStart(&DACD2, &dac1cfg2);
275
276 /*
277 * Starting GPT6/7 driver, it is used for triggering the DAC.
278 */
279 START_CHANNEL_1();
280 START_CHANNEL_2();
281
282 /*
283 * Starting a continuous conversion.
284 */
285 dacStartConversion(&DACD1, &dacgrpcfg1, (dacsample_t *)dac_buffer, DAC_BUFFER_SIZE);
286 dacStartConversion(&DACD2, &dacgrpcfg2, (dacsample_t *)dac_buffer_2, DAC_BUFFER_SIZE);
287
288 audio_initialized = true;
289
290 if (audio_config.enable) {
291 PLAY_SONG(startup_song);
292 } else {
293 stop_all_notes();
294 }
295}
296
297void stop_all_notes() {
298 dprintf("audio stop all notes");
299
300 if (!audio_initialized) {
301 audio_init();
302 }
303 voices = 0;
304
305 gptStopTimer(&GPTD6);
306 gptStopTimer(&GPTD7);
307 gptStopTimer(&GPTD8);
308
309 playing_notes = false;
310 playing_note = false;
311 frequency = 0;
312 frequency_alt = 0;
313 volume = 0;
314
315 for (uint8_t i = 0; i < 8; i++) {
316 frequencies[i] = 0;
317 volumes[i] = 0;
318 }
319}
320
321void stop_note(float freq) {
322 dprintf("audio stop note freq=%d", (int)freq);
323
324 if (playing_note) {
325 if (!audio_initialized) {
326 audio_init();
327 }
328 for (int i = 7; i >= 0; i--) {
329 if (frequencies[i] == freq) {
330 frequencies[i] = 0;
331 volumes[i] = 0;
332 for (int j = i; (j < 7); j++) {
333 frequencies[j] = frequencies[j + 1];
334 frequencies[j + 1] = 0;
335 volumes[j] = volumes[j + 1];
336 volumes[j + 1] = 0;
337 }
338 break;
339 }
340 }
341 voices--;
342 if (voices < 0) {
343 voices = 0;
344 }
345 if (voice_place >= voices) {
346 voice_place = 0;
347 }
348 if (voices == 0) {
349 STOP_CHANNEL_1();
350 STOP_CHANNEL_2();
351 gptStopTimer(&GPTD8);
352 frequency = 0;
353 frequency_alt = 0;
354 volume = 0;
355 playing_note = false;
356 }
357 }
358}
359
360#ifdef VIBRATO_ENABLE
361
362float mod(float a, int b) {
363 float r = fmod(a, b);
364 return r < 0 ? r + b : r;
365}
366
367float vibrato(float average_freq) {
368# ifdef VIBRATO_STRENGTH_ENABLE
369 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
370# else
371 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
372# endif
373 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
374 return vibrated_freq;
375}
376
377#endif
378
379static void gpt_cb8(GPTDriver *gptp) {
380 float freq;
381
382 if (playing_note) {
383 if (voices > 0) {
384 float freq_alt = 0;
385 if (voices > 1) {
386 if (polyphony_rate == 0) {
387 if (glissando) {
388 if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) {
389 frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2);
390 } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) {
391 frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2);
392 } else {
393 frequency_alt = frequencies[voices - 2];
394 }
395 } else {
396 frequency_alt = frequencies[voices - 2];
397 }
398
399#ifdef VIBRATO_ENABLE
400 if (vibrato_strength > 0) {
401 freq_alt = vibrato(frequency_alt);
402 } else {
403 freq_alt = frequency_alt;
404 }
405#else
406 freq_alt = frequency_alt;
407#endif
408 }
409
410 if (envelope_index < 65535) {
411 envelope_index++;
412 }
413
414 freq_alt = voice_envelope(freq_alt);
415
416 if (freq_alt < 30.517578125) {
417 freq_alt = 30.52;
418 }
419
420 if (GET_CHANNEL_2_FREQ != (uint16_t)freq_alt) {
421 UPDATE_CHANNEL_2_FREQ(freq_alt);
422 } else {
423 RESTART_CHANNEL_2();
424 }
425 // note_timbre;
426 }
427
428 if (polyphony_rate > 0) {
429 if (voices > 1) {
430 voice_place %= voices;
431 if (place++ > (frequencies[voice_place] / polyphony_rate)) {
432 voice_place = (voice_place + 1) % voices;
433 place = 0.0;
434 }
435 }
436
437#ifdef VIBRATO_ENABLE
438 if (vibrato_strength > 0) {
439 freq = vibrato(frequencies[voice_place]);
440 } else {
441 freq = frequencies[voice_place];
442 }
443#else
444 freq = frequencies[voice_place];
445#endif
446 } else {
447 if (glissando) {
448 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
449 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
450 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
451 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
452 } else {
453 frequency = frequencies[voices - 1];
454 }
455 } else {
456 frequency = frequencies[voices - 1];
457 }
458
459#ifdef VIBRATO_ENABLE
460 if (vibrato_strength > 0) {
461 freq = vibrato(frequency);
462 } else {
463 freq = frequency;
464 }
465#else
466 freq = frequency;
467#endif
468 }
469
470 if (envelope_index < 65535) {
471 envelope_index++;
472 }
473
474 freq = voice_envelope(freq);
475
476 if (freq < 30.517578125) {
477 freq = 30.52;
478 }
479
480 if (GET_CHANNEL_1_FREQ != (uint16_t)freq) {
481 UPDATE_CHANNEL_1_FREQ(freq);
482 } else {
483 RESTART_CHANNEL_1();
484 }
485 // note_timbre;
486 }
487 }
488
489 if (playing_notes) {
490 if (note_frequency > 0) {
491#ifdef VIBRATO_ENABLE
492 if (vibrato_strength > 0) {
493 freq = vibrato(note_frequency);
494 } else {
495 freq = note_frequency;
496 }
497#else
498 freq = note_frequency;
499#endif
500
501 if (envelope_index < 65535) {
502 envelope_index++;
503 }
504 freq = voice_envelope(freq);
505
506 if (GET_CHANNEL_1_FREQ != (uint16_t)freq) {
507 UPDATE_CHANNEL_1_FREQ(freq);
508 UPDATE_CHANNEL_2_FREQ(freq);
509 }
510 // note_timbre;
511 } else {
512 // gptStopTimer(&GPTD6);
513 // gptStopTimer(&GPTD7);
514 }
515
516 note_position++;
517 bool end_of_note = false;
518 if (GET_CHANNEL_1_FREQ > 0) {
519 if (!note_resting)
520 end_of_note = (note_position >= (note_length * 8 - 1));
521 else
522 end_of_note = (note_position >= (note_length * 8));
523 } else {
524 end_of_note = (note_position >= (note_length * 8));
525 }
526
527 if (end_of_note) {
528 current_note++;
529 if (current_note >= notes_count) {
530 if (notes_repeat) {
531 current_note = 0;
532 } else {
533 STOP_CHANNEL_1();
534 STOP_CHANNEL_2();
535 // gptStopTimer(&GPTD8);
536 playing_notes = false;
537 return;
538 }
539 }
540 if (!note_resting) {
541 note_resting = true;
542 current_note--;
543 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
544 note_frequency = 0;
545 note_length = 1;
546 } else {
547 note_frequency = (*notes_pointer)[current_note][0];
548 note_length = 1;
549 }
550 } else {
551 note_resting = false;
552 envelope_index = 0;
553 note_frequency = (*notes_pointer)[current_note][0];
554 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
555 }
556
557 note_position = 0;
558 }
559 }
560
561 if (!audio_config.enable) {
562 playing_notes = false;
563 playing_note = false;
564 }
565}
566
567void play_note(float freq, int vol) {
568 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
569
570 if (!audio_initialized) {
571 audio_init();
572 }
573
574 if (audio_config.enable && voices < 8) {
575 // Cancel notes if notes are playing
576 if (playing_notes) {
577 stop_all_notes();
578 }
579
580 playing_note = true;
581
582 envelope_index = 0;
583
584 if (freq > 0) {
585 frequencies[voices] = freq;
586 volumes[voices] = vol;
587 voices++;
588 }
589
590 gptStart(&GPTD8, &gpt8cfg1);
591 gptStartContinuous(&GPTD8, 2U);
592 RESTART_CHANNEL_1();
593 RESTART_CHANNEL_2();
594 }
595}
596
597void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) {
598 if (!audio_initialized) {
599 audio_init();
600 }
601
602 if (audio_config.enable) {
603 // Cancel note if a note is playing
604 if (playing_note) {
605 stop_all_notes();
606 }
607
608 playing_notes = true;
609
610 notes_pointer = np;
611 notes_count = n_count;
612 notes_repeat = n_repeat;
613
614 place = 0;
615 current_note = 0;
616
617 note_frequency = (*notes_pointer)[current_note][0];
618 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
619 note_position = 0;
620
621 gptStart(&GPTD8, &gpt8cfg1);
622 gptStartContinuous(&GPTD8, 2U);
623 RESTART_CHANNEL_1();
624 RESTART_CHANNEL_2();
625 }
626}
627
628bool is_playing_notes(void) { return playing_notes; }
629
630bool is_audio_on(void) { return (audio_config.enable != 0); }
631
632void audio_toggle(void) {
633 audio_config.enable ^= 1;
634 eeconfig_update_audio(audio_config.raw);
635 if (audio_config.enable) {
636 audio_on_user();
637 }
638}
639
640void audio_on(void) {
641 audio_config.enable = 1;
642 eeconfig_update_audio(audio_config.raw);
643 audio_on_user();
644}
645
646void audio_off(void) {
647 stop_all_notes();
648 audio_config.enable = 0;
649 eeconfig_update_audio(audio_config.raw);
650}
651
652#ifdef VIBRATO_ENABLE
653
654// Vibrato rate functions
655
656void set_vibrato_rate(float rate) { vibrato_rate = rate; }
657
658void increase_vibrato_rate(float change) { vibrato_rate *= change; }
659
660void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
661
662# ifdef VIBRATO_STRENGTH_ENABLE
663
664void set_vibrato_strength(float strength) { vibrato_strength = strength; }
665
666void increase_vibrato_strength(float change) { vibrato_strength *= change; }
667
668void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
669
670# endif /* VIBRATO_STRENGTH_ENABLE */
671
672#endif /* VIBRATO_ENABLE */
673
674// Polyphony functions
675
676void set_polyphony_rate(float rate) { polyphony_rate = rate; }
677
678void enable_polyphony() { polyphony_rate = 5; }
679
680void disable_polyphony() { polyphony_rate = 0; }
681
682void increase_polyphony_rate(float change) { polyphony_rate *= change; }
683
684void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
685
686// Timbre function
687
688void set_timbre(float timbre) { note_timbre = timbre; }
689
690// Tempo functions
691
692void set_tempo(uint8_t tempo) { note_tempo = tempo; }
693
694void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
695
696void increase_tempo(uint8_t tempo_change) {
697 if (note_tempo - tempo_change < 10) {
698 note_tempo = 10;
699 } else {
700 note_tempo -= tempo_change;
701 }
702}
diff --git a/quantum/audio/audio_pwm.c b/quantum/audio/audio_pwm.c
deleted file mode 100644
index 545aef6dd..000000000
--- a/quantum/audio/audio_pwm.c
+++ /dev/null
@@ -1,595 +0,0 @@
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#include <stdio.h>
17#include <string.h>
18//#include <math.h>
19#include <avr/pgmspace.h>
20#include <avr/interrupt.h>
21#include <avr/io.h>
22#include "print.h"
23#include "audio.h"
24#include "keymap.h"
25
26#include "eeconfig.h"
27
28#define PI 3.14159265
29
30#define CPU_PRESCALER 8
31
32// Timer Abstractions
33
34// TIMSK3 - Timer/Counter #3 Interrupt Mask Register
35// Turn on/off 3A interputs, stopping/enabling the ISR calls
36#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
37#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
38
39// TCCR3A: Timer/Counter #3 Control Register
40// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
41#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
42#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
43
44#define NOTE_PERIOD ICR3
45#define NOTE_DUTY_CYCLE OCR3A
46
47#ifdef PWM_AUDIO
48# include "wave.h"
49# define SAMPLE_DIVIDER 39
50# define SAMPLE_RATE (2000000.0 / SAMPLE_DIVIDER / 2048)
51// Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
52
53float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
54uint16_t place_int = 0;
55bool repeat = true;
56#endif
57
58void delay_us(int count) {
59 while (count--) {
60 _delay_us(1);
61 }
62}
63
64int voices = 0;
65int voice_place = 0;
66float frequency = 0;
67int volume = 0;
68long position = 0;
69
70float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
71int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
72bool sliding = false;
73
74float place = 0;
75
76uint8_t* sample;
77uint16_t sample_length = 0;
78// float freq = 0;
79
80bool playing_notes = false;
81bool playing_note = false;
82float note_frequency = 0;
83float note_length = 0;
84uint8_t note_tempo = TEMPO_DEFAULT;
85float note_timbre = TIMBRE_DEFAULT;
86uint16_t note_position = 0;
87float (*notes_pointer)[][2];
88uint16_t notes_count;
89bool notes_repeat;
90float notes_rest;
91bool note_resting = false;
92
93uint16_t current_note = 0;
94uint8_t rest_counter = 0;
95
96#ifdef VIBRATO_ENABLE
97float vibrato_counter = 0;
98float vibrato_strength = .5;
99float vibrato_rate = 0.125;
100#endif
101
102float polyphony_rate = 0;
103
104static bool audio_initialized = false;
105
106audio_config_t audio_config;
107
108uint16_t envelope_index = 0;
109
110void audio_init() {
111 // Check EEPROM
112 if (!eeconfig_is_enabled()) {
113 eeconfig_init();
114 }
115 audio_config.raw = eeconfig_read_audio();
116
117#ifdef PWM_AUDIO
118
119 PLLFRQ = _BV(PDIV2);
120 PLLCSR = _BV(PLLE);
121 while (!(PLLCSR & _BV(PLOCK)))
122 ;
123 PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
124
125 /* Init a fast PWM on Timer4 */
126 TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
127 TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
128 OCR4A = 0;
129
130 /* Enable the OC4A output */
131 DDRC |= _BV(PORTC6);
132
133 DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs
134
135 TCCR3A = 0x0; // Options not needed
136 TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
137 OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
138
139#else
140
141 // Set port PC6 (OC3A and /OC4A) as output
142 DDRC |= _BV(PORTC6);
143
144 DISABLE_AUDIO_COUNTER_3_ISR;
145
146 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
147 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
148 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
149 // Clock Select (CS3n) = 0b010 = Clock / 8
150 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
151 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
152
153#endif
154
155 audio_initialized = true;
156}
157
158void stop_all_notes() {
159 if (!audio_initialized) {
160 audio_init();
161 }
162 voices = 0;
163#ifdef PWM_AUDIO
164 DISABLE_AUDIO_COUNTER_3_ISR;
165#else
166 DISABLE_AUDIO_COUNTER_3_ISR;
167 DISABLE_AUDIO_COUNTER_3_OUTPUT;
168#endif
169
170 playing_notes = false;
171 playing_note = false;
172 frequency = 0;
173 volume = 0;
174
175 for (uint8_t i = 0; i < 8; i++) {
176 frequencies[i] = 0;
177 volumes[i] = 0;
178 }
179}
180
181void stop_note(float freq) {
182 if (playing_note) {
183 if (!audio_initialized) {
184 audio_init();
185 }
186#ifdef PWM_AUDIO
187 freq = freq / SAMPLE_RATE;
188#endif
189 for (int i = 7; i >= 0; i--) {
190 if (frequencies[i] == freq) {
191 frequencies[i] = 0;
192 volumes[i] = 0;
193 for (int j = i; (j < 7); j++) {
194 frequencies[j] = frequencies[j + 1];
195 frequencies[j + 1] = 0;
196 volumes[j] = volumes[j + 1];
197 volumes[j + 1] = 0;
198 }
199 break;
200 }
201 }
202 voices--;
203 if (voices < 0) voices = 0;
204 if (voice_place >= voices) {
205 voice_place = 0;
206 }
207 if (voices == 0) {
208#ifdef PWM_AUDIO
209 DISABLE_AUDIO_COUNTER_3_ISR;
210#else
211 DISABLE_AUDIO_COUNTER_3_ISR;
212 DISABLE_AUDIO_COUNTER_3_OUTPUT;
213#endif
214 frequency = 0;
215 volume = 0;
216 playing_note = false;
217 }
218 }
219}
220
221#ifdef VIBRATO_ENABLE
222
223float mod(float a, int b) {
224 float r = fmod(a, b);
225 return r < 0 ? r + b : r;
226}
227
228float vibrato(float average_freq) {
229# ifdef VIBRATO_STRENGTH_ENABLE
230 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
231# else
232 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
233# endif
234 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
235 return vibrated_freq;
236}
237
238#endif
239
240ISR(TIMER3_COMPA_vect) {
241 if (playing_note) {
242#ifdef PWM_AUDIO
243 if (voices == 1) {
244 // SINE
245 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
246
247 // SQUARE
248 // if (((int)place) >= 1024){
249 // OCR4A = 0xFF >> 2;
250 // } else {
251 // OCR4A = 0x00;
252 // }
253
254 // SAWTOOTH
255 // OCR4A = (int)place / 4;
256
257 // TRIANGLE
258 // if (((int)place) >= 1024) {
259 // OCR4A = (int)place / 2;
260 // } else {
261 // OCR4A = 2048 - (int)place / 2;
262 // }
263
264 place += frequency;
265
266 if (place >= SINE_LENGTH) place -= SINE_LENGTH;
267
268 } else {
269 int sum = 0;
270 for (int i = 0; i < voices; i++) {
271 // SINE
272 sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
273
274 // SQUARE
275 // if (((int)places[i]) >= 1024){
276 // sum += 0xFF >> 2;
277 // } else {
278 // sum += 0x00;
279 // }
280
281 places[i] += frequencies[i];
282
283 if (places[i] >= SINE_LENGTH) places[i] -= SINE_LENGTH;
284 }
285 OCR4A = sum;
286 }
287#else
288 if (voices > 0) {
289 float freq;
290 if (polyphony_rate > 0) {
291 if (voices > 1) {
292 voice_place %= voices;
293 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
294 voice_place = (voice_place + 1) % voices;
295 place = 0.0;
296 }
297 }
298# ifdef VIBRATO_ENABLE
299 if (vibrato_strength > 0) {
300 freq = vibrato(frequencies[voice_place]);
301 } else {
302# else
303 {
304# endif
305 freq = frequencies[voice_place];
306 }
307 } else {
308 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
309 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
310 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
311 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
312 } else {
313 frequency = frequencies[voices - 1];
314 }
315
316# ifdef VIBRATO_ENABLE
317 if (vibrato_strength > 0) {
318 freq = vibrato(frequency);
319 } else {
320# else
321 {
322# endif
323 freq = frequency;
324 }
325 }
326
327 if (envelope_index < 65535) {
328 envelope_index++;
329 }
330 freq = voice_envelope(freq);
331
332 if (freq < 30.517578125) freq = 30.52;
333 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
334 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
335 }
336#endif
337 }
338
339 // SAMPLE
340 // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
341
342 // place_int++;
343
344 // if (place_int >= sample_length)
345 // if (repeat)
346 // place_int -= sample_length;
347 // else
348 // DISABLE_AUDIO_COUNTER_3_ISR;
349
350 if (playing_notes) {
351#ifdef PWM_AUDIO
352 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
353
354 place += note_frequency;
355 if (place >= SINE_LENGTH) place -= SINE_LENGTH;
356#else
357 if (note_frequency > 0) {
358 float freq;
359
360# ifdef VIBRATO_ENABLE
361 if (vibrato_strength > 0) {
362 freq = vibrato(note_frequency);
363 } else {
364# else
365 {
366# endif
367 freq = note_frequency;
368 }
369
370 if (envelope_index < 65535) {
371 envelope_index++;
372 }
373 freq = voice_envelope(freq);
374
375 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
376 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
377 } else {
378 NOTE_PERIOD = 0;
379 NOTE_DUTY_CYCLE = 0;
380 }
381#endif
382
383 note_position++;
384 bool end_of_note = false;
385 if (NOTE_PERIOD > 0)
386 end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF));
387 else
388 end_of_note = (note_position >= (note_length * 0x7FF));
389 if (end_of_note) {
390 current_note++;
391 if (current_note >= notes_count) {
392 if (notes_repeat) {
393 current_note = 0;
394 } else {
395#ifdef PWM_AUDIO
396 DISABLE_AUDIO_COUNTER_3_ISR;
397#else
398 DISABLE_AUDIO_COUNTER_3_ISR;
399 DISABLE_AUDIO_COUNTER_3_OUTPUT;
400#endif
401 playing_notes = false;
402 return;
403 }
404 }
405 if (!note_resting && (notes_rest > 0)) {
406 note_resting = true;
407 note_frequency = 0;
408 note_length = notes_rest;
409 current_note--;
410 } else {
411 note_resting = false;
412#ifdef PWM_AUDIO
413 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
414 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
415#else
416 envelope_index = 0;
417 note_frequency = (*notes_pointer)[current_note][0];
418 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
419#endif
420 }
421 note_position = 0;
422 }
423 }
424
425 if (!audio_config.enable) {
426 playing_notes = false;
427 playing_note = false;
428 }
429}
430
431void play_note(float freq, int vol) {
432 if (!audio_initialized) {
433 audio_init();
434 }
435
436 if (audio_config.enable && voices < 8) {
437 DISABLE_AUDIO_COUNTER_3_ISR;
438
439 // Cancel notes if notes are playing
440 if (playing_notes) stop_all_notes();
441
442 playing_note = true;
443
444 envelope_index = 0;
445
446#ifdef PWM_AUDIO
447 freq = freq / SAMPLE_RATE;
448#endif
449 if (freq > 0) {
450 frequencies[voices] = freq;
451 volumes[voices] = vol;
452 voices++;
453 }
454
455#ifdef PWM_AUDIO
456 ENABLE_AUDIO_COUNTER_3_ISR;
457#else
458 ENABLE_AUDIO_COUNTER_3_ISR;
459 ENABLE_AUDIO_COUNTER_3_OUTPUT;
460#endif
461 }
462}
463
464void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) {
465 if (!audio_initialized) {
466 audio_init();
467 }
468
469 if (audio_config.enable) {
470 DISABLE_AUDIO_COUNTER_3_ISR;
471
472 // Cancel note if a note is playing
473 if (playing_note) stop_all_notes();
474
475 playing_notes = true;
476
477 notes_pointer = np;
478 notes_count = n_count;
479 notes_repeat = n_repeat;
480 notes_rest = n_rest;
481
482 place = 0;
483 current_note = 0;
484
485#ifdef PWM_AUDIO
486 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
487 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
488#else
489 note_frequency = (*notes_pointer)[current_note][0];
490 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
491#endif
492 note_position = 0;
493
494#ifdef PWM_AUDIO
495 ENABLE_AUDIO_COUNTER_3_ISR;
496#else
497 ENABLE_AUDIO_COUNTER_3_ISR;
498 ENABLE_AUDIO_COUNTER_3_OUTPUT;
499#endif
500 }
501}
502
503#ifdef PWM_AUDIO
504void play_sample(uint8_t* s, uint16_t l, bool r) {
505 if (!audio_initialized) {
506 audio_init();
507 }
508
509 if (audio_config.enable) {
510 DISABLE_AUDIO_COUNTER_3_ISR;
511 stop_all_notes();
512 place_int = 0;
513 sample = s;
514 sample_length = l;
515 repeat = r;
516
517 ENABLE_AUDIO_COUNTER_3_ISR;
518 }
519}
520#endif
521
522void audio_toggle(void) {
523 audio_config.enable ^= 1;
524 eeconfig_update_audio(audio_config.raw);
525}
526
527void audio_on(void) {
528 audio_config.enable = 1;
529 eeconfig_update_audio(audio_config.raw);
530}
531
532void audio_off(void) {
533 audio_config.enable = 0;
534 eeconfig_update_audio(audio_config.raw);
535}
536
537#ifdef VIBRATO_ENABLE
538
539// Vibrato rate functions
540
541void set_vibrato_rate(float rate) { vibrato_rate = rate; }
542
543void increase_vibrato_rate(float change) { vibrato_rate *= change; }
544
545void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
546
547# ifdef VIBRATO_STRENGTH_ENABLE
548
549void set_vibrato_strength(float strength) { vibrato_strength = strength; }
550
551void increase_vibrato_strength(float change) { vibrato_strength *= change; }
552
553void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
554
555# endif /* VIBRATO_STRENGTH_ENABLE */
556
557#endif /* VIBRATO_ENABLE */
558
559// Polyphony functions
560
561void set_polyphony_rate(float rate) { polyphony_rate = rate; }
562
563void enable_polyphony() { polyphony_rate = 5; }
564
565void disable_polyphony() { polyphony_rate = 0; }
566
567void increase_polyphony_rate(float change) { polyphony_rate *= change; }
568
569void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
570
571// Timbre function
572
573void set_timbre(float timbre) { note_timbre = timbre; }
574
575// Tempo functions
576
577void set_tempo(uint8_t tempo) { note_tempo = tempo; }
578
579void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
580
581void increase_tempo(uint8_t tempo_change) {
582 if (note_tempo - tempo_change < 10) {
583 note_tempo = 10;
584 } else {
585 note_tempo -= tempo_change;
586 }
587}
588
589//------------------------------------------------------------------------------
590// Override these functions in your keymap file to play different tunes on
591// startup and bootloader jump
592__attribute__((weak)) void play_startup_tone() {}
593
594__attribute__((weak)) void play_goodbye_tone() {}
595//------------------------------------------------------------------------------
diff --git a/quantum/audio/driver_avr_pwm.h b/quantum/audio/driver_avr_pwm.h
new file mode 100644
index 000000000..d6eb3571d
--- /dev/null
+++ b/quantum/audio/driver_avr_pwm.h
@@ -0,0 +1,17 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
diff --git a/quantum/audio/driver_avr_pwm_hardware.c b/quantum/audio/driver_avr_pwm_hardware.c
new file mode 100644
index 000000000..492b9bfb0
--- /dev/null
+++ b/quantum/audio/driver_avr_pwm_hardware.c
@@ -0,0 +1,322 @@
1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#if defined(__AVR__)
19# include <avr/pgmspace.h>
20# include <avr/interrupt.h>
21# include <avr/io.h>
22#endif
23
24#include "audio.h"
25
26extern bool playing_note;
27extern bool playing_melody;
28extern uint8_t note_timbre;
29
30#define CPU_PRESCALER 8
31
32/*
33 Audio Driver: PWM
34
35 drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4.
36
37 the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3
38 and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1
39
40 alternatively, the PWM pins on PORTB can be used as only/primary speaker
41*/
42
43#if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7)
44# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options."
45#endif
46
47#if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6)
48# define AUDIO1_PIN_SET
49# define AUDIO1_TIMSKx TIMSK3
50# define AUDIO1_TCCRxA TCCR3A
51# define AUDIO1_TCCRxB TCCR3B
52# define AUDIO1_ICRx ICR3
53# define AUDIO1_WGMx0 WGM30
54# define AUDIO1_WGMx1 WGM31
55# define AUDIO1_WGMx2 WGM32
56# define AUDIO1_WGMx3 WGM33
57# define AUDIO1_CSx0 CS30
58# define AUDIO1_CSx1 CS31
59# define AUDIO1_CSx2 CS32
60
61# if (AUDIO_PIN == C6)
62# define AUDIO1_COMxy0 COM3A0
63# define AUDIO1_COMxy1 COM3A1
64# define AUDIO1_OCIExy OCIE3A
65# define AUDIO1_OCRxy OCR3A
66# define AUDIO1_PIN C6
67# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect
68# elif (AUDIO_PIN == C5)
69# define AUDIO1_COMxy0 COM3B0
70# define AUDIO1_COMxy1 COM3B1
71# define AUDIO1_OCIExy OCIE3B
72# define AUDIO1_OCRxy OCR3B
73# define AUDIO1_PIN C5
74# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect
75# elif (AUDIO_PIN == C4)
76# define AUDIO1_COMxy0 COM3C0
77# define AUDIO1_COMxy1 COM3C1
78# define AUDIO1_OCIExy OCIE3C
79# define AUDIO1_OCRxy OCR3C
80# define AUDIO1_PIN C4
81# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect
82# endif
83#endif
84
85#if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT)
86# error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense."
87#endif
88
89#if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6)))
90# error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported."
91#endif
92
93#if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
94# error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported."
95#endif
96
97#if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7)
98# define AUDIO2_PIN_SET
99# define AUDIO2_TIMSKx TIMSK1
100# define AUDIO2_TCCRxA TCCR1A
101# define AUDIO2_TCCRxB TCCR1B
102# define AUDIO2_ICRx ICR1
103# define AUDIO2_WGMx0 WGM10
104# define AUDIO2_WGMx1 WGM11
105# define AUDIO2_WGMx2 WGM12
106# define AUDIO2_WGMx3 WGM13
107# define AUDIO2_CSx0 CS10
108# define AUDIO2_CSx1 CS11
109# define AUDIO2_CSx2 CS12
110
111# if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5)
112# define AUDIO2_COMxy0 COM1A0
113# define AUDIO2_COMxy1 COM1A1
114# define AUDIO2_OCIExy OCIE1A
115# define AUDIO2_OCRxy OCR1A
116# define AUDIO2_PIN B5
117# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
118# elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6)
119# define AUDIO2_COMxy0 COM1B0
120# define AUDIO2_COMxy1 COM1B1
121# define AUDIO2_OCIExy OCIE1B
122# define AUDIO2_OCRxy OCR1B
123# define AUDIO2_PIN B6
124# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect
125# elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7)
126# define AUDIO2_COMxy0 COM1C0
127# define AUDIO2_COMxy1 COM1C1
128# define AUDIO2_OCIExy OCIE1C
129# define AUDIO2_OCRxy OCR1C
130# define AUDIO2_PIN B7
131# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect
132# endif
133#endif
134
135// C6 seems to be the assumed default by many existing keyboard - but sill warn the user
136#if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET)
137# pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)"
138// TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define
139#endif
140// -----------------------------------------------------------------------------
141
142#ifdef AUDIO1_PIN_SET
143static float channel_1_frequency = 0.0f;
144void channel_1_set_frequency(float freq) {
145 if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0
146 {
147 // disable the output, but keep the pwm-ISR going (with the previous
148 // frequency) so the audio-state keeps getting updated
149 // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet
150 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
151 return;
152 } else {
153 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode
154 }
155
156 channel_1_frequency = freq;
157
158 // set pwm period
159 AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
160 // and duty cycle
161 AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
162}
163
164void channel_1_start(void) {
165 // enable timer-counter ISR
166 AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy);
167 // enable timer-counter output
168 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1);
169}
170
171void channel_1_stop(void) {
172 // disable timer-counter ISR
173 AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy);
174 // disable timer-counter output
175 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
176}
177#endif
178
179#ifdef AUDIO2_PIN_SET
180static float channel_2_frequency = 0.0f;
181void channel_2_set_frequency(float freq) {
182 if (freq == 0.0f) {
183 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
184 return;
185 } else {
186 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
187 }
188
189 channel_2_frequency = freq;
190
191 AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
192 AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
193}
194
195float channel_2_get_frequency(void) { return channel_2_frequency; }
196
197void channel_2_start(void) {
198 AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);
199 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
200}
201
202void channel_2_stop(void) {
203 AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy);
204 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
205}
206#endif
207
208void audio_driver_initialize() {
209#ifdef AUDIO1_PIN_SET
210 channel_1_stop();
211 setPinOutput(AUDIO1_PIN);
212#endif
213
214#ifdef AUDIO2_PIN_SET
215 channel_2_stop();
216 setPinOutput(AUDIO2_PIN);
217#endif
218
219 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
220 // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
221 // OC3A -- PC6
222 // OC3B -- PC5
223 // OC3C -- PC4
224 // OC1A -- PB5
225 // OC1B -- PB6
226 // OC1C -- PB7
227
228 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
229 // OCR3A - PC6
230 // OCR3B - PC5
231 // OCR3C - PC4
232 // OCR1A - PB5
233 // OCR1B - PB6
234 // OCR1C - PB7
235
236 // Clock Select (CS3n) = 0b010 = Clock / 8
237#ifdef AUDIO1_PIN_SET
238 // initialize timer-counter
239 AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0);
240 AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0);
241#endif
242
243#ifdef AUDIO2_PIN_SET
244 AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0);
245 AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0);
246#endif
247}
248
249void audio_driver_stop() {
250#ifdef AUDIO1_PIN_SET
251 channel_1_stop();
252#endif
253
254#ifdef AUDIO2_PIN_SET
255 channel_2_stop();
256#endif
257}
258
259void audio_driver_start(void) {
260#ifdef AUDIO1_PIN_SET
261 channel_1_start();
262 if (playing_note) {
263 channel_1_set_frequency(audio_get_processed_frequency(0));
264 }
265#endif
266
267#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
268 channel_2_start();
269 if (playing_note) {
270 channel_2_set_frequency(audio_get_processed_frequency(0));
271 }
272#endif
273}
274
275static volatile uint32_t isr_counter = 0;
276#ifdef AUDIO1_PIN_SET
277ISR(AUDIO1_TIMERx_COMPy_vect) {
278 isr_counter++;
279 if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return;
280
281 isr_counter = 0;
282 bool state_changed = audio_update_state();
283
284 if (!playing_note && !playing_melody) {
285 channel_1_stop();
286# ifdef AUDIO2_PIN_SET
287 channel_2_stop();
288# endif
289 return;
290 }
291
292 if (state_changed) {
293 channel_1_set_frequency(audio_get_processed_frequency(0));
294# ifdef AUDIO2_PIN_SET
295 if (audio_get_number_of_active_tones() > 1) {
296 channel_2_set_frequency(audio_get_processed_frequency(1));
297 } else {
298 channel_2_stop();
299 }
300# endif
301 }
302}
303#endif
304
305#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
306ISR(AUDIO2_TIMERx_COMPy_vect) {
307 isr_counter++;
308 if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return;
309
310 isr_counter = 0;
311 bool state_changed = audio_update_state();
312
313 if (!playing_note && !playing_melody) {
314 channel_2_stop();
315 return;
316 }
317
318 if (state_changed) {
319 channel_2_set_frequency(audio_get_processed_frequency(0));
320 }
321}
322#endif
diff --git a/quantum/audio/driver_chibios_dac.h b/quantum/audio/driver_chibios_dac.h
new file mode 100644
index 000000000..07cd622ea
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac.h
@@ -0,0 +1,126 @@
1/* Copyright 2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#ifndef A4
20# define A4 PAL_LINE(GPIOA, 4)
21#endif
22#ifndef A5
23# define A5 PAL_LINE(GPIOA, 5)
24#endif
25
26/**
27 * Size of the dac_buffer arrays. All must be the same size.
28 */
29#define AUDIO_DAC_BUFFER_SIZE 256U
30
31/**
32 * Highest value allowed sample value.
33
34 * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U;
35 * lower values adjust the peak-voltage aka volume down.
36 * adjusting this value has only an effect on a sample-buffer whose values are
37 * are NOT pregenerated - see square-wave
38 */
39#ifndef AUDIO_DAC_SAMPLE_MAX
40# define AUDIO_DAC_SAMPLE_MAX 4095U
41#endif
42
43#if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH)
44# define AUDIO_DAC_QUALITY_SANE_MINIMUM
45#endif
46
47/**
48 * These presets allow you to quickly switch between quality settings for
49 * the DAC. The sample rate and maximum number of simultaneous tones roughly
50 * has an inverse relationship - slightly higher sample rates may be possible.
51 *
52 * NOTE: a high sample-rate results in a higher cpu-load, which might lead to
53 * (audible) discontinuities and/or starve other processes of cpu-time
54 * (like RGB-led back-lighting, ...)
55 */
56#ifdef AUDIO_DAC_QUALITY_VERY_LOW
57# define AUDIO_DAC_SAMPLE_RATE 11025U
58# define AUDIO_MAX_SIMULTANEOUS_TONES 8
59#endif
60
61#ifdef AUDIO_DAC_QUALITY_LOW
62# define AUDIO_DAC_SAMPLE_RATE 22050U
63# define AUDIO_MAX_SIMULTANEOUS_TONES 4
64#endif
65
66#ifdef AUDIO_DAC_QUALITY_HIGH
67# define AUDIO_DAC_SAMPLE_RATE 44100U
68# define AUDIO_MAX_SIMULTANEOUS_TONES 2
69#endif
70
71#ifdef AUDIO_DAC_QUALITY_VERY_HIGH
72# define AUDIO_DAC_SAMPLE_RATE 88200U
73# define AUDIO_MAX_SIMULTANEOUS_TONES 1
74#endif
75
76#ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM
77/* a sane-minimum config: with a trade-off between cpu-load and tone-range
78 *
79 * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now
80 * aim for an even even multiple of the buffer-size, we end up with:
81 * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE)
82 * 7902/256 = 30.867 * 2 * 256 ~= 16384
83 * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P)
84 */
85# define AUDIO_DAC_SAMPLE_RATE 16384U
86# define AUDIO_MAX_SIMULTANEOUS_TONES 8
87#endif
88
89/**
90 * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any
91 * lower will sacrifice perceptible audio quality. Any higher will limit the
92 * number of simultaneous tones. In most situations, a tenth (1/10) of the
93 * sample rate is where notes become unbearable.
94 */
95#ifndef AUDIO_DAC_SAMPLE_RATE
96# define AUDIO_DAC_SAMPLE_RATE 44100U
97#endif
98
99/**
100 * The number of tones that can be played simultaneously. If too high a value
101 * is used here, the keyboard will freeze and glitch-out when that many tones
102 * are being played.
103 */
104#ifndef AUDIO_MAX_SIMULTANEOUS_TONES
105# define AUDIO_MAX_SIMULTANEOUS_TONES 2
106#endif
107
108/**
109 * The default value of the DAC when not playing anything. Certain hardware
110 * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here.
111 * Since multiple added sine waves tend to oscillate around the midpoint,
112 * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a
113 * reasonable default value.
114 */
115#ifndef AUDIO_DAC_OFF_VALUE
116# define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2
117#endif
118
119#if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX
120# error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX"
121#endif
122
123/**
124 *user overridable sample generation/processing
125 */
126uint16_t dac_value_generate(void);
diff --git a/quantum/audio/driver_chibios_dac_additive.c b/quantum/audio/driver_chibios_dac_additive.c
new file mode 100644
index 000000000..db304adb8
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac_additive.c
@@ -0,0 +1,335 @@
1/* Copyright 2016-2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "audio.h"
19#include <ch.h>
20#include <hal.h>
21
22/*
23 Audio Driver: DAC
24
25 which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA
26
27 it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate'
28
29 this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis
30*/
31
32#if !defined(AUDIO_PIN)
33# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options."
34#endif
35#if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE)
36# pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though."
37#endif
38
39#if !defined(AUDIO_PIN_ALT)
40// no ALT pin defined is valid, but the c-ifs below need some value set
41# define AUDIO_PIN_ALT PAL_NOLINE
42#endif
43
44#if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
45# define AUDIO_DAC_SAMPLE_WAVEFORM_SINE
46#endif
47
48#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE
49/* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0
50 */
51static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = {
52 // 256 values, max 4095
53 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe,
54 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1};
55#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE
56#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
57static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = {
58 // 256 values, max 4095
59 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf,
60 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
61#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
62#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
63static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = {
64 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and
65 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half
66};
67#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
68/*
69// four steps: 0, 1/3, 2/3 and 1
70static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = {
71 [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0,
72 [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3,
73 [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3,
74 [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX,
75}
76*/
77#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
78static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
79 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
80#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
81
82static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE};
83
84/* keep track of the sample position for for each frequency */
85static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0};
86
87static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0};
88static uint8_t active_tones_snapshot_length = 0;
89
90typedef enum {
91 OUTPUT_SHOULD_START,
92 OUTPUT_RUN_NORMALLY,
93 // path 1: wait for zero, then change/update active tones
94 OUTPUT_TONES_CHANGED,
95 OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE,
96 // path 2: hardware should stop, wait for zero then turn output off = stop the timer
97 OUTPUT_SHOULD_STOP,
98 OUTPUT_REACHED_ZERO_BEFORE_OFF,
99 OUTPUT_OFF,
100 OUTPUT_OFF_1,
101 OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level
102 number_of_output_states
103} output_states_t;
104output_states_t state = OUTPUT_OFF_2;
105
106/**
107 * Generation of the waveform being passed to the callback. Declared weak so users
108 * can override it with their own wave-forms/noises.
109 */
110__attribute__((weak)) uint16_t dac_value_generate(void) {
111 // DAC is running/asking for values but snapshot length is zero -> must be playing a pause
112 if (active_tones_snapshot_length == 0) {
113 return AUDIO_DAC_OFF_VALUE;
114 }
115
116 /* doing additive wave synthesis over all currently playing tones = adding up
117 * sine-wave-samples for each frequency, scaled by the number of active tones
118 */
119 uint16_t value = 0;
120 float frequency = 0.0f;
121
122 for (uint8_t i = 0; i < active_tones_snapshot_length; i++) {
123 /* Note: a user implementation does not have to rely on the active_tones_snapshot, but
124 * could directly query the active frequencies through audio_get_processed_frequency */
125 frequency = active_tones_snapshot[i];
126
127 dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3;
128 /*Note: the 2/3 are necessary to get the correct frequencies on the
129 * DAC output (as measured with an oscilloscope), since the gpt
130 * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback
131 * is called twice per conversion.*/
132
133 dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE);
134
135 // Wavetable generation/lookup
136 uint16_t dac_i = (uint16_t)dac_if[i];
137
138#if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE)
139 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length;
140#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE)
141 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length;
142#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
143 value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length;
144#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE)
145 value += dac_buffer_square[dac_i] / active_tones_snapshot_length;
146#endif
147 /*
148 // SINE
149 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3;
150 // TRIANGLE
151 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3;
152 // SQUARE
153 value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3;
154 //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P
155 */
156
157 // STAIRS (mostly usefully as test-pattern)
158 // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length;
159 }
160
161 return value;
162}
163
164/**
165 * DAC streaming callback. Does all of the main computing for playing songs.
166 *
167 * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'.
168 */
169static void dac_end(DACDriver *dacp) {
170 dacsample_t *sample_p = (dacp)->samples;
171
172 // work on the other half of the buffer
173 if (dacIsBufferComplete(dacp)) {
174 sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index'
175 }
176
177 for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) {
178 if (OUTPUT_OFF <= state) {
179 sample_p[s] = AUDIO_DAC_OFF_VALUE;
180 continue;
181 } else {
182 sample_p[s] = dac_value_generate();
183 }
184
185 /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX)
186 * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX
187 * * *
188 * * *
189 * ---------------------------------------------------------
190 * * * } AUDIO_DAC_SAMPLE_MAX/100
191 * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE
192 * * * } AUDIO_DAC_SAMPLE_MAX/100
193 * ---------------------------------------------------------
194 * *
195 * * *
196 * * *
197 * =====*=*================================================= 0x0
198 */
199 if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below
200 (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above
201 ) {
202 if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) {
203 state = OUTPUT_RUN_NORMALLY;
204 } else if (OUTPUT_TONES_CHANGED == state) {
205 state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE;
206 } else if (OUTPUT_SHOULD_STOP == state) {
207 state = OUTPUT_REACHED_ZERO_BEFORE_OFF;
208 }
209 }
210
211 // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover
212 if (OUTPUT_SHOULD_START == state) {
213 sample_p[s] = AUDIO_DAC_OFF_VALUE;
214 }
215
216 if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) {
217 uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones());
218 active_tones_snapshot_length = 0;
219 // update the snapshot - once, and only on occasion that something changed;
220 // -> saves cpu cycles (?)
221 for (uint8_t i = 0; i < active_tones; i++) {
222 float freq = audio_get_processed_frequency(i);
223 if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step
224 active_tones_snapshot[active_tones_snapshot_length++] = freq;
225 }
226 }
227
228 if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) {
229 state = OUTPUT_OFF;
230 }
231 if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) {
232 state = OUTPUT_RUN_NORMALLY;
233 }
234 }
235 }
236
237 // update audio internal state (note position, current_note, ...)
238 if (audio_update_state()) {
239 if (OUTPUT_SHOULD_STOP != state) {
240 state = OUTPUT_TONES_CHANGED;
241 }
242 }
243
244 if (OUTPUT_OFF <= state) {
245 if (OUTPUT_OFF_2 == state) {
246 // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE
247 gptStopTimer(&GPTD6);
248 } else {
249 state++;
250 }
251 }
252}
253
254static void dac_error(DACDriver *dacp, dacerror_t err) {
255 (void)dacp;
256 (void)err;
257
258 chSysHalt("DAC failure. halp");
259}
260
261static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3,
262 .callback = NULL,
263 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
264 .dier = 0U};
265
266static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
267
268/**
269 * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
270 * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
271 * to be a third of what we expect.
272 *
273 * Here are all the values for DAC_TRG (TSEL in the ref manual)
274 * TIM15_TRGO 0b011
275 * TIM2_TRGO 0b100
276 * TIM3_TRGO 0b001
277 * TIM6_TRGO 0b000
278 * TIM7_TRGO 0b010
279 * EXTI9 0b110
280 * SWTRIG 0b111
281 */
282static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};
283
284void audio_driver_initialize() {
285 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
286 palSetLineMode(A4, PAL_MODE_INPUT_ANALOG);
287 dacStart(&DACD1, &dac_conf);
288 }
289 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
290 palSetLineMode(A5, PAL_MODE_INPUT_ANALOG);
291 dacStart(&DACD2, &dac_conf);
292 }
293
294 /* enable the output buffer, to directly drive external loads with no additional circuitry
295 *
296 * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
297 * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
298 * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
299 *
300 * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
301 * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
302 */
303 DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
304 DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
305
306 if (AUDIO_PIN == A4) {
307 dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
308 } else if (AUDIO_PIN == A5) {
309 dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
310 }
311
312 // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE
313#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
314 if (AUDIO_PIN_ALT == A4) {
315 dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
316 } else if (AUDIO_PIN_ALT == A5) {
317 dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
318 }
319#endif
320
321 gptStart(&GPTD6, &gpt6cfg1);
322}
323
324void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; }
325
326void audio_driver_start(void) {
327 gptStartContinuous(&GPTD6, 2U);
328
329 for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) {
330 dac_if[i] = 0.0f;
331 active_tones_snapshot[i] = 0.0f;
332 }
333 active_tones_snapshot_length = 0;
334 state = OUTPUT_SHOULD_START;
335}
diff --git a/quantum/audio/driver_chibios_dac_basic.c b/quantum/audio/driver_chibios_dac_basic.c
new file mode 100644
index 000000000..b8cec5ff1
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac_basic.c
@@ -0,0 +1,245 @@
1/* Copyright 2016-2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "audio.h"
19#include "ch.h"
20#include "hal.h"
21
22/*
23 Audio Driver: DAC
24
25 which utilizes both channels of the DAC unit many STM32 are equipped with to output a modulated square-wave, from precomputed samples stored in a buffer, which is passed to the hardware through DMA
26
27 this driver can either be used to drive to separate speakers, wired to A4+Gnd and A5+Gnd, which allows two tones to be played simultaneously
28 OR
29 one speaker wired to A4+A5 with the AUDIO_PIN_ALT_AS_NEGATIVE define set - see docs/feature_audio
30
31*/
32
33#if !defined(AUDIO_PIN)
34# pragma message "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC basic)' for available options."
35// TODO: make this an 'error' instead; go through a breaking change, and add AUDIO_PIN A5 to all keyboards currently using AUDIO on STM32 based boards? - for now: set the define here
36# define AUDIO_PIN A5
37#endif
38// check configuration for ONE speaker, connected to both DAC pins
39#if defined(AUDIO_PIN_ALT_AS_NEGATIVE) && !defined(AUDIO_PIN_ALT)
40# error "Audio feature: AUDIO_PIN_ALT_AS_NEGATIVE set, but no pin configured as AUDIO_PIN_ALT"
41#endif
42
43#ifndef AUDIO_PIN_ALT
44// no ALT pin defined is valid, but the c-ifs below need some value set
45# define AUDIO_PIN_ALT -1
46#endif
47
48#if !defined(AUDIO_STATE_TIMER)
49# define AUDIO_STATE_TIMER GPTD8
50#endif
51
52// square-wave
53static const dacsample_t dac_buffer_1[AUDIO_DAC_BUFFER_SIZE] = {
54 // First half is max, second half is 0
55 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = AUDIO_DAC_SAMPLE_MAX,
56 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = 0,
57};
58
59// square-wave
60static const dacsample_t dac_buffer_2[AUDIO_DAC_BUFFER_SIZE] = {
61 // opposite of dac_buffer above
62 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0,
63 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX,
64};
65
66GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
67 .callback = NULL,
68 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
69 .dier = 0U};
70GPTConfig gpt7cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
71 .callback = NULL,
72 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
73 .dier = 0U};
74
75static void gpt_audio_state_cb(GPTDriver *gptp);
76GPTConfig gptStateUpdateCfg = {.frequency = 10,
77 .callback = gpt_audio_state_cb,
78 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
79 .dier = 0U};
80
81static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
82static const DACConfig dac_conf_ch2 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
83
84/**
85 * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
86 * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
87 * to be a third of what we expect.
88 *
89 * Here are all the values for DAC_TRG (TSEL in the ref manual)
90 * TIM15_TRGO 0b011
91 * TIM2_TRGO 0b100
92 * TIM3_TRGO 0b001
93 * TIM6_TRGO 0b000
94 * TIM7_TRGO 0b010
95 * EXTI9 0b110
96 * SWTRIG 0b111
97 */
98static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)};
99static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)};
100
101void channel_1_start(void) {
102 gptStart(&GPTD6, &gpt6cfg1);
103 gptStartContinuous(&GPTD6, 2U);
104 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
105}
106
107void channel_1_stop(void) {
108 gptStopTimer(&GPTD6);
109 palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);
110 palSetPad(GPIOA, 4);
111}
112
113static float channel_1_frequency = 0.0f;
114void channel_1_set_frequency(float freq) {
115 channel_1_frequency = freq;
116
117 channel_1_stop();
118 if (freq <= 0.0) // a pause/rest has freq=0
119 return;
120
121 gpt6cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
122 channel_1_start();
123}
124float channel_1_get_frequency(void) { return channel_1_frequency; }
125
126void channel_2_start(void) {
127 gptStart(&GPTD7, &gpt7cfg1);
128 gptStartContinuous(&GPTD7, 2U);
129 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
130}
131
132void channel_2_stop(void) {
133 gptStopTimer(&GPTD7);
134 palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL);
135 palSetPad(GPIOA, 5);
136}
137
138static float channel_2_frequency = 0.0f;
139void channel_2_set_frequency(float freq) {
140 channel_2_frequency = freq;
141
142 channel_2_stop();
143 if (freq <= 0.0) // a pause/rest has freq=0
144 return;
145
146 gpt7cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
147 channel_2_start();
148}
149float channel_2_get_frequency(void) { return channel_2_frequency; }
150
151static void gpt_audio_state_cb(GPTDriver *gptp) {
152 if (audio_update_state()) {
153#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
154 // one piezo/speaker connected to both audio pins, the generated square-waves are inverted
155 channel_1_set_frequency(audio_get_processed_frequency(0));
156 channel_2_set_frequency(audio_get_processed_frequency(0));
157
158#else // two separate audio outputs/speakers
159 // primary speaker on A4, optional secondary on A5
160 if (AUDIO_PIN == A4) {
161 channel_1_set_frequency(audio_get_processed_frequency(0));
162 if (AUDIO_PIN_ALT == A5) {
163 if (audio_get_number_of_active_tones() > 1) {
164 channel_2_set_frequency(audio_get_processed_frequency(1));
165 } else {
166 channel_2_stop();
167 }
168 }
169 }
170
171 // primary speaker on A5, optional secondary on A4
172 if (AUDIO_PIN == A5) {
173 channel_2_set_frequency(audio_get_processed_frequency(0));
174 if (AUDIO_PIN_ALT == A4) {
175 if (audio_get_number_of_active_tones() > 1) {
176 channel_1_set_frequency(audio_get_processed_frequency(1));
177 } else {
178 channel_1_stop();
179 }
180 }
181 }
182#endif
183 }
184}
185
186void audio_driver_initialize() {
187 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
188 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
189 dacStart(&DACD1, &dac_conf_ch1);
190
191 // initial setup of the dac-triggering timer is still required, even
192 // though it gets reconfigured and restarted later on
193 gptStart(&GPTD6, &gpt6cfg1);
194 }
195
196 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
197 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
198 dacStart(&DACD2, &dac_conf_ch2);
199
200 gptStart(&GPTD7, &gpt7cfg1);
201 }
202
203 /* enable the output buffer, to directly drive external loads with no additional circuitry
204 *
205 * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
206 * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
207 * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
208 *
209 * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
210 * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
211 */
212 DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
213 DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
214
215 // start state-updater
216 gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg);
217}
218
219void audio_driver_stop(void) {
220 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
221 gptStopTimer(&GPTD6);
222
223 // stop the ongoing conversion and put the output in a known state
224 dacStopConversion(&DACD1);
225 dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
226 }
227
228 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
229 gptStopTimer(&GPTD7);
230
231 dacStopConversion(&DACD2);
232 dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
233 }
234 gptStopTimer(&AUDIO_STATE_TIMER);
235}
236
237void audio_driver_start(void) {
238 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
239 dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE);
240 }
241 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
242 dacStartConversion(&DACD2, &dac_conv_grp_ch2, (dacsample_t *)dac_buffer_2, AUDIO_DAC_BUFFER_SIZE);
243 }
244 gptStartContinuous(&AUDIO_STATE_TIMER, 2U);
245}
diff --git a/quantum/audio/driver_chibios_pwm.h b/quantum/audio/driver_chibios_pwm.h
new file mode 100644
index 000000000..86cab916e
--- /dev/null
+++ b/quantum/audio/driver_chibios_pwm.h
@@ -0,0 +1,40 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#if !defined(AUDIO_PWM_DRIVER)
20// NOTE: Timer2 seems to be used otherwise in QMK, otherwise we could default to A5 (= TIM2_CH1, with PWMD2 and alternate-function(1))
21# define AUDIO_PWM_DRIVER PWMD1
22#endif
23
24#if !defined(AUDIO_PWM_CHANNEL)
25// NOTE: sticking to the STM data-sheet numbering: TIMxCH1 to TIMxCH4
26// default: STM32F303CC PA8+TIM1_CH1 -> 1
27# define AUDIO_PWM_CHANNEL 1
28#endif
29
30#if !defined(AUDIO_PWM_PAL_MODE)
31// pin-alternate function: see the data-sheet for which pin needs what AF to connect to TIMx_CHy
32// default: STM32F303CC PA8+TIM1_CH1 -> 6
33# define AUDIO_PWM_PAL_MODE 6
34#endif
35
36#if !defined(AUDIO_STATE_TIMER)
37// timer used to trigger updates in the audio-system, configured/enabled in chibios mcuconf.
38// Tim6 is the default for "larger" STMs, smaller ones might not have this one (enabled) and need to switch to a different one (e.g.: STM32F103 has only Tim1-Tim4)
39# define AUDIO_STATE_TIMER GPTD6
40#endif
diff --git a/quantum/audio/driver_chibios_pwm_hardware.c b/quantum/audio/driver_chibios_pwm_hardware.c
new file mode 100644
index 000000000..3c7d89b29
--- /dev/null
+++ b/quantum/audio/driver_chibios_pwm_hardware.c
@@ -0,0 +1,144 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19Audio Driver: PWM
20
21the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
22
23this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware.
24The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function.
25
26 */
27
28#include "audio.h"
29#include "ch.h"
30#include "hal.h"
31
32#if !defined(AUDIO_PIN)
33# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
34#endif
35
36extern bool playing_note;
37extern bool playing_melody;
38extern uint8_t note_timbre;
39
40static PWMConfig pwmCFG = {
41 .frequency = 100000, /* PWM clock frequency */
42 // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
43 .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
44 .callback = NULL, /* no callback, the hardware directly toggles the pin */
45 .channels =
46 {
47#if AUDIO_PWM_CHANNEL == 4
48 {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIMx_CH1 */
49 {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
50 {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
51 {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */
52#elif AUDIO_PWM_CHANNEL == 3
53 {PWM_OUTPUT_DISABLED, NULL},
54 {PWM_OUTPUT_DISABLED, NULL},
55 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */
56 {PWM_OUTPUT_DISABLED, NULL}
57#elif AUDIO_PWM_CHANNEL == 2
58 {PWM_OUTPUT_DISABLED, NULL},
59 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */
60 {PWM_OUTPUT_DISABLED, NULL},
61 {PWM_OUTPUT_DISABLED, NULL}
62#else /*fallback to CH1 */
63 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */
64 {PWM_OUTPUT_DISABLED, NULL},
65 {PWM_OUTPUT_DISABLED, NULL},
66 {PWM_OUTPUT_DISABLED, NULL}
67#endif
68 },
69};
70
71static float channel_1_frequency = 0.0f;
72void channel_1_set_frequency(float freq) {
73 channel_1_frequency = freq;
74
75 if (freq <= 0.0) // a pause/rest has freq=0
76 return;
77
78 pwmcnt_t period = (pwmCFG.frequency / freq);
79 pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
80 pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
81 // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
82 PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
83}
84
85float channel_1_get_frequency(void) { return channel_1_frequency; }
86
87void channel_1_start(void) {
88 pwmStop(&AUDIO_PWM_DRIVER);
89 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
90}
91
92void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); }
93
94static void gpt_callback(GPTDriver *gptp);
95GPTConfig gptCFG = {
96 /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
97 the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
98 the tempo (which might vary!) is in bpm (beats per minute)
99 therefore: if the timer ticks away at .frequency = (60*64)Hz,
100 and the .interval counts from 64 downwards - audio_update_state is
101 called just often enough to not miss any notes
102 */
103 .frequency = 60 * 64,
104 .callback = gpt_callback,
105};
106
107void audio_driver_initialize(void) {
108 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
109
110 // connect the AUDIO_PIN to the PWM hardware
111#if defined(USE_GPIOV1) // STM32F103C8
112 palSetLineMode(AUDIO_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
113#else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
114 palSetLineMode(AUDIO_PIN, PAL_STM32_MODE_ALTERNATE | PAL_STM32_ALTERNATE(AUDIO_PWM_PAL_MODE));
115#endif
116
117 gptStart(&AUDIO_STATE_TIMER, &gptCFG);
118}
119
120void audio_driver_start(void) {
121 channel_1_stop();
122 channel_1_start();
123
124 if (playing_note || playing_melody) {
125 gptStartContinuous(&AUDIO_STATE_TIMER, 64);
126 }
127}
128
129void audio_driver_stop(void) {
130 channel_1_stop();
131 gptStopTimer(&AUDIO_STATE_TIMER);
132}
133
134/* a regular timer task, that checks the note to be currently played
135 * and updates the pwm to output that frequency
136 */
137static void gpt_callback(GPTDriver *gptp) {
138 float freq; // TODO: freq_alt
139
140 if (audio_update_state()) {
141 freq = audio_get_processed_frequency(0); // freq_alt would be index=1
142 channel_1_set_frequency(freq);
143 }
144}
diff --git a/quantum/audio/driver_chibios_pwm_software.c b/quantum/audio/driver_chibios_pwm_software.c
new file mode 100644
index 000000000..15c3e98b6
--- /dev/null
+++ b/quantum/audio/driver_chibios_pwm_software.c
@@ -0,0 +1,164 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19Audio Driver: PWM
20
21the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
22
23this driver uses the chibios-PWM system to produce a square-wave on any given output pin in software
24- a pwm callback is used to set/clear the configured pin.
25
26 */
27#include "audio.h"
28#include "ch.h"
29#include "hal.h"
30
31#if !defined(AUDIO_PIN)
32# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
33#endif
34extern bool playing_note;
35extern bool playing_melody;
36extern uint8_t note_timbre;
37
38static void pwm_audio_period_callback(PWMDriver *pwmp);
39static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp);
40
41static PWMConfig pwmCFG = {
42 .frequency = 100000, /* PWM clock frequency */
43 // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
44 .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
45 .callback = pwm_audio_period_callback,
46 .channels =
47 {
48 // software-PWM just needs another callback on any channel
49 {PWM_OUTPUT_ACTIVE_HIGH, pwm_audio_channel_interrupt_callback}, /* channel 0 -> TIMx_CH1 */
50 {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
51 {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
52 {PWM_OUTPUT_DISABLED, NULL} /* channel 3 -> TIMx_CH4 */
53 },
54};
55
56static float channel_1_frequency = 0.0f;
57void channel_1_set_frequency(float freq) {
58 channel_1_frequency = freq;
59
60 if (freq <= 0.0) // a pause/rest has freq=0
61 return;
62
63 pwmcnt_t period = (pwmCFG.frequency / freq);
64 pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
65
66 pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
67 // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
68 PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
69}
70
71float channel_1_get_frequency(void) { return channel_1_frequency; }
72
73void channel_1_start(void) {
74 pwmStop(&AUDIO_PWM_DRIVER);
75 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
76
77 pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER);
78 pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
79}
80
81void channel_1_stop(void) {
82 pwmStop(&AUDIO_PWM_DRIVER);
83
84 palClearLine(AUDIO_PIN); // leave the line low, after last note was played
85
86#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
87 palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played
88#endif
89}
90
91// generate a PWM signal on any pin, not necessarily the one connected to the timer
92static void pwm_audio_period_callback(PWMDriver *pwmp) {
93 (void)pwmp;
94 palClearLine(AUDIO_PIN);
95
96#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
97 palSetLine(AUDIO_PIN_ALT);
98#endif
99}
100static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp) {
101 (void)pwmp;
102 if (channel_1_frequency > 0) {
103 palSetLine(AUDIO_PIN); // generate a PWM signal on any pin, not necessarily the one connected to the timer
104#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
105 palClearLine(AUDIO_PIN_ALT);
106#endif
107 }
108}
109
110static void gpt_callback(GPTDriver *gptp);
111GPTConfig gptCFG = {
112 /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
113 the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
114 the tempo (which might vary!) is in bpm (beats per minute)
115 therefore: if the timer ticks away at .frequency = (60*64)Hz,
116 and the .interval counts from 64 downwards - audio_update_state is
117 called just often enough to not miss anything
118 */
119 .frequency = 60 * 64,
120 .callback = gpt_callback,
121};
122
123void audio_driver_initialize(void) {
124 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
125
126 palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL);
127 palClearLine(AUDIO_PIN);
128
129#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
130 palSetLineMode(AUDIO_PIN_ALT, PAL_MODE_OUTPUT_PUSHPULL);
131 palClearLine(AUDIO_PIN_ALT);
132#endif
133
134 pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks
135 pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
136
137 gptStart(&AUDIO_STATE_TIMER, &gptCFG);
138}
139
140void audio_driver_start(void) {
141 channel_1_stop();
142 channel_1_start();
143
144 if (playing_note || playing_melody) {
145 gptStartContinuous(&AUDIO_STATE_TIMER, 64);
146 }
147}
148
149void audio_driver_stop(void) {
150 channel_1_stop();
151 gptStopTimer(&AUDIO_STATE_TIMER);
152}
153
154/* a regular timer task, that checks the note to be currently played
155 * and updates the pwm to output that frequency
156 */
157static void gpt_callback(GPTDriver *gptp) {
158 float freq; // TODO: freq_alt
159
160 if (audio_update_state()) {
161 freq = audio_get_processed_frequency(0); // freq_alt would be index=1
162 channel_1_set_frequency(freq);
163 }
164}
diff --git a/quantum/audio/musical_notes.h b/quantum/audio/musical_notes.h
index 8ac6aafd3..ddd7d374f 100644
--- a/quantum/audio/musical_notes.h
+++ b/quantum/audio/musical_notes.h
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * 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 * it under the terms of the GNU General Public License as published by
@@ -13,11 +14,12 @@
13 * You should have received a copy of the GNU General Public License 14 * 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 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 16 */
16
17#pragma once 17#pragma once
18 18
19// Tempo Placeholder 19#ifndef TEMPO_DEFAULT
20#define TEMPO_DEFAULT 100 20# define TEMPO_DEFAULT 120
21// in beats-per-minute
22#endif
21 23
22#define SONG(notes...) \ 24#define SONG(notes...) \
23 { notes } 25 { notes }
@@ -25,12 +27,14 @@
25// Note Types 27// Note Types
26#define MUSICAL_NOTE(note, duration) \ 28#define MUSICAL_NOTE(note, duration) \
27 { (NOTE##note), duration } 29 { (NOTE##note), duration }
30
28#define BREVE_NOTE(note) MUSICAL_NOTE(note, 128) 31#define BREVE_NOTE(note) MUSICAL_NOTE(note, 128)
29#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64) 32#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64)
30#define HALF_NOTE(note) MUSICAL_NOTE(note, 32) 33#define HALF_NOTE(note) MUSICAL_NOTE(note, 32)
31#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16) 34#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16)
32#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8) 35#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8)
33#define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4) 36#define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4)
37#define THIRTYSECOND_NOTE(note) MUSICAL_NOTE(note, 2)
34 38
35#define BREVE_DOT_NOTE(note) MUSICAL_NOTE(note, 128 + 64) 39#define BREVE_DOT_NOTE(note) MUSICAL_NOTE(note, 128 + 64)
36#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64 + 32) 40#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64 + 32)
@@ -38,6 +42,9 @@
38#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16 + 8) 42#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16 + 8)
39#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8 + 4) 43#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8 + 4)
40#define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4 + 2) 44#define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4 + 2)
45#define THIRTYSECOND_DOT_NOTE(note) MUSICAL_NOTE(note, 2 + 1)
46// duration of 64 units == one beat == one whole note
47// with a tempo of 60bpm this comes to a length of one second
41 48
42// Note Type Shortcuts 49// Note Type Shortcuts
43#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration) 50#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration)
@@ -47,55 +54,52 @@
47#define Q__NOTE(n) QUARTER_NOTE(n) 54#define Q__NOTE(n) QUARTER_NOTE(n)
48#define E__NOTE(n) EIGHTH_NOTE(n) 55#define E__NOTE(n) EIGHTH_NOTE(n)
49#define S__NOTE(n) SIXTEENTH_NOTE(n) 56#define S__NOTE(n) SIXTEENTH_NOTE(n)
57#define T__NOTE(n) THIRTYSECOND_NOTE(n)
50#define BD_NOTE(n) BREVE_DOT_NOTE(n) 58#define BD_NOTE(n) BREVE_DOT_NOTE(n)
51#define WD_NOTE(n) WHOLE_DOT_NOTE(n) 59#define WD_NOTE(n) WHOLE_DOT_NOTE(n)
52#define HD_NOTE(n) HALF_DOT_NOTE(n) 60#define HD_NOTE(n) HALF_DOT_NOTE(n)
53#define QD_NOTE(n) QUARTER_DOT_NOTE(n) 61#define QD_NOTE(n) QUARTER_DOT_NOTE(n)
54#define ED_NOTE(n) EIGHTH_DOT_NOTE(n) 62#define ED_NOTE(n) EIGHTH_DOT_NOTE(n)
55#define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n) 63#define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n)
64#define TD_NOTE(n) THIRTYSECOND_DOT_NOTE(n)
56 65
57// Note Timbre 66// Note Timbre
58// Changes how the notes sound 67// Changes how the notes sound
59#define TIMBRE_12 0.125f 68#define TIMBRE_12 12
60#define TIMBRE_25 0.250f 69#define TIMBRE_25 25
61#define TIMBRE_50 0.500f 70#define TIMBRE_50 50
62#define TIMBRE_75 0.750f 71#define TIMBRE_75 75
63#define TIMBRE_DEFAULT TIMBRE_50 72#ifndef TIMBRE_DEFAULT
73# define TIMBRE_DEFAULT TIMBRE_50
74#endif
64 75
65// Notes - # = Octave 76// Notes - # = Octave
66 77
67#ifdef __arm__ 78#define NOTE_REST 0.00f
68# define NOTE_REST 1.00f
69#else
70# define NOTE_REST 0.00f
71#endif
72
73/* These notes are currently bugged
74#define NOTE_C0 16.35f
75#define NOTE_CS0 17.32f
76#define NOTE_D0 18.35f
77#define NOTE_DS0 19.45f
78#define NOTE_E0 20.60f
79#define NOTE_F0 21.83f
80#define NOTE_FS0 23.12f
81#define NOTE_G0 24.50f
82#define NOTE_GS0 25.96f
83#define NOTE_A0 27.50f
84#define NOTE_AS0 29.14f
85#define NOTE_B0 30.87f
86#define NOTE_C1 32.70f
87#define NOTE_CS1 34.65f
88#define NOTE_D1 36.71f
89#define NOTE_DS1 38.89f
90#define NOTE_E1 41.20f
91#define NOTE_F1 43.65f
92#define NOTE_FS1 46.25f
93#define NOTE_G1 49.00f
94#define NOTE_GS1 51.91f
95#define NOTE_A1 55.00f
96#define NOTE_AS1 58.27f
97*/
98 79
80#define NOTE_C0 16.35f
81#define NOTE_CS0 17.32f
82#define NOTE_D0 18.35f
83#define NOTE_DS0 19.45f
84#define NOTE_E0 20.60f
85#define NOTE_F0 21.83f
86#define NOTE_FS0 23.12f
87#define NOTE_G0 24.50f
88#define NOTE_GS0 25.96f
89#define NOTE_A0 27.50f
90#define NOTE_AS0 29.14f
91#define NOTE_B0 30.87f
92#define NOTE_C1 32.70f
93#define NOTE_CS1 34.65f
94#define NOTE_D1 36.71f
95#define NOTE_DS1 38.89f
96#define NOTE_E1 41.20f
97#define NOTE_F1 43.65f
98#define NOTE_FS1 46.25f
99#define NOTE_G1 49.00f
100#define NOTE_GS1 51.91f
101#define NOTE_A1 55.00f
102#define NOTE_AS1 58.27f
99#define NOTE_B1 61.74f 103#define NOTE_B1 61.74f
100#define NOTE_C2 65.41f 104#define NOTE_C2 65.41f
101#define NOTE_CS2 69.30f 105#define NOTE_CS2 69.30f
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c
index 1592618be..8988d827e 100644
--- a/quantum/audio/voices.c
+++ b/quantum/audio/voices.c
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * 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 * it under the terms of the GNU General Public License as published by
@@ -17,13 +18,19 @@
17#include "audio.h" 18#include "audio.h"
18#include <stdlib.h> 19#include <stdlib.h>
19 20
20// these are imported from audio.c 21uint8_t note_timbre = TIMBRE_DEFAULT;
21extern uint16_t envelope_index; 22bool glissando = false;
22extern float note_timbre; 23bool vibrato = false;
23extern float polyphony_rate; 24float vibrato_strength = 0.5;
24extern bool glissando; 25float vibrato_rate = 0.125;
25 26
27uint16_t voices_timer = 0;
28
29#ifdef AUDIO_VOICE_DEFAULT
30voice_type voice = AUDIO_VOICE_DEFAULT;
31#else
26voice_type voice = default_voice; 32voice_type voice = default_voice;
33#endif
27 34
28void set_voice(voice_type v) { voice = v; } 35void set_voice(voice_type v) { voice = v; }
29 36
@@ -31,22 +38,54 @@ void voice_iterate() { voice = (voice + 1) % number_of_voices; }
31 38
32void voice_deiterate() { voice = (voice - 1 + number_of_voices) % number_of_voices; } 39void voice_deiterate() { voice = (voice - 1 + number_of_voices) % number_of_voices; }
33 40
41#ifdef AUDIO_VOICES
42float mod(float a, int b) {
43 float r = fmod(a, b);
44 return r < 0 ? r + b : r;
45}
46
47// Effect: 'vibrate' a given target frequency slightly above/below its initial value
48float voice_add_vibrato(float average_freq) {
49 float vibrato_counter = mod(timer_read() / (100 * vibrato_rate), VIBRATO_LUT_LENGTH);
50
51 return average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
52}
53
54// Effect: 'slides' the 'frequency' from the starting-point, to the target frequency
55float voice_add_glissando(float from_freq, float to_freq) {
56 if (to_freq != 0 && from_freq < to_freq && from_freq < to_freq * pow(2, -440 / to_freq / 12 / 2)) {
57 return from_freq * pow(2, 440 / from_freq / 12 / 2);
58 } else if (to_freq != 0 && from_freq > to_freq && from_freq > to_freq * pow(2, 440 / to_freq / 12 / 2)) {
59 return from_freq * pow(2, -440 / from_freq / 12 / 2);
60 } else {
61 return to_freq;
62 }
63}
64#endif
65
34float voice_envelope(float frequency) { 66float voice_envelope(float frequency) {
35 // envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz 67 // envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz
36 __attribute__((unused)) uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency)); 68// __attribute__((unused)) uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency));
69#ifdef AUDIO_VOICES
70 uint16_t envelope_index = timer_elapsed(voices_timer); // TODO: multiply in some factor?
71 uint16_t compensated_index = envelope_index / 100; // TODO: correct factor would be?
72#endif
37 73
38 switch (voice) { 74 switch (voice) {
39 case default_voice: 75 case default_voice:
40 glissando = false; 76 glissando = false;
41 note_timbre = TIMBRE_50; 77 // note_timbre = TIMBRE_50; //Note: leave the user the possibility to adjust the timbre with 'audio_set_timbre'
42 polyphony_rate = 0;
43 break; 78 break;
44 79
45#ifdef AUDIO_VOICES 80#ifdef AUDIO_VOICES
46 81
82 case vibrating:
83 glissando = false;
84 vibrato = true;
85 break;
86
47 case something: 87 case something:
48 glissando = false; 88 glissando = false;
49 polyphony_rate = 0;
50 switch (compensated_index) { 89 switch (compensated_index) {
51 case 0 ... 9: 90 case 0 ... 9:
52 note_timbre = TIMBRE_12; 91 note_timbre = TIMBRE_12;
@@ -57,24 +96,23 @@ float voice_envelope(float frequency) {
57 break; 96 break;
58 97
59 case 20 ... 200: 98 case 20 ... 200:
60 note_timbre = .125 + .125; 99 note_timbre = 12 + 12;
61 break; 100 break;
62 101
63 default: 102 default:
64 note_timbre = .125; 103 note_timbre = 12;
65 break; 104 break;
66 } 105 }
67 break; 106 break;
68 107
69 case drums: 108 case drums:
70 glissando = false; 109 glissando = false;
71 polyphony_rate = 0;
72 // switch (compensated_index) { 110 // switch (compensated_index) {
73 // case 0 ... 10: 111 // case 0 ... 10:
74 // note_timbre = 0.5; 112 // note_timbre = 50;
75 // break; 113 // break;
76 // case 11 ... 20: 114 // case 11 ... 20:
77 // note_timbre = 0.5 * (21 - compensated_index) / 10; 115 // note_timbre = 50 * (21 - compensated_index) / 10;
78 // break; 116 // break;
79 // default: 117 // default:
80 // note_timbre = 0; 118 // note_timbre = 0;
@@ -88,10 +126,10 @@ float voice_envelope(float frequency) {
88 frequency = (rand() % (int)(40)) + 60; 126 frequency = (rand() % (int)(40)) + 60;
89 switch (envelope_index) { 127 switch (envelope_index) {
90 case 0 ... 10: 128 case 0 ... 10:
91 note_timbre = 0.5; 129 note_timbre = 50;
92 break; 130 break;
93 case 11 ... 20: 131 case 11 ... 20:
94 note_timbre = 0.5 * (21 - envelope_index) / 10; 132 note_timbre = 50 * (21 - envelope_index) / 10;
95 break; 133 break;
96 default: 134 default:
97 note_timbre = 0; 135 note_timbre = 0;
@@ -103,10 +141,10 @@ float voice_envelope(float frequency) {
103 frequency = (rand() % (int)(1000)) + 1000; 141 frequency = (rand() % (int)(1000)) + 1000;
104 switch (envelope_index) { 142 switch (envelope_index) {
105 case 0 ... 5: 143 case 0 ... 5:
106 note_timbre = 0.5; 144 note_timbre = 50;
107 break; 145 break;
108 case 6 ... 20: 146 case 6 ... 20:
109 note_timbre = 0.5 * (21 - envelope_index) / 15; 147 note_timbre = 50 * (21 - envelope_index) / 15;
110 break; 148 break;
111 default: 149 default:
112 note_timbre = 0; 150 note_timbre = 0;
@@ -118,10 +156,10 @@ float voice_envelope(float frequency) {
118 frequency = (rand() % (int)(2000)) + 3000; 156 frequency = (rand() % (int)(2000)) + 3000;
119 switch (envelope_index) { 157 switch (envelope_index) {
120 case 0 ... 15: 158 case 0 ... 15:
121 note_timbre = 0.5; 159 note_timbre = 50;
122 break; 160 break;
123 case 16 ... 20: 161 case 16 ... 20:
124 note_timbre = 0.5 * (21 - envelope_index) / 5; 162 note_timbre = 50 * (21 - envelope_index) / 5;
125 break; 163 break;
126 default: 164 default:
127 note_timbre = 0; 165 note_timbre = 0;
@@ -133,10 +171,10 @@ float voice_envelope(float frequency) {
133 frequency = (rand() % (int)(2000)) + 3000; 171 frequency = (rand() % (int)(2000)) + 3000;
134 switch (envelope_index) { 172 switch (envelope_index) {
135 case 0 ... 35: 173 case 0 ... 35:
136 note_timbre = 0.5; 174 note_timbre = 50;
137 break; 175 break;
138 case 36 ... 50: 176 case 36 ... 50:
139 note_timbre = 0.5 * (51 - envelope_index) / 15; 177 note_timbre = 50 * (51 - envelope_index) / 15;
140 break; 178 break;
141 default: 179 default:
142 note_timbre = 0; 180 note_timbre = 0;
@@ -145,8 +183,7 @@ float voice_envelope(float frequency) {
145 } 183 }
146 break; 184 break;
147 case butts_fader: 185 case butts_fader:
148 glissando = true; 186 glissando = true;
149 polyphony_rate = 0;
150 switch (compensated_index) { 187 switch (compensated_index) {
151 case 0 ... 9: 188 case 0 ... 9:
152 frequency = frequency / 4; 189 frequency = frequency / 4;
@@ -159,7 +196,7 @@ float voice_envelope(float frequency) {
159 break; 196 break;
160 197
161 case 20 ... 200: 198 case 20 ... 200:
162 note_timbre = .125 - pow(((float)compensated_index - 20) / (200 - 20), 2) * .125; 199 note_timbre = 12 - (uint8_t)(pow(((float)compensated_index - 20) / (200 - 20), 2) * 12.5);
163 break; 200 break;
164 201
165 default: 202 default:
@@ -169,7 +206,6 @@ float voice_envelope(float frequency) {
169 break; 206 break;
170 207
171 // case octave_crunch: 208 // case octave_crunch:
172 // polyphony_rate = 0;
173 // switch (compensated_index) { 209 // switch (compensated_index) {
174 // case 0 ... 9: 210 // case 0 ... 9:
175 // case 20 ... 24: 211 // case 20 ... 24:
@@ -187,14 +223,13 @@ float voice_envelope(float frequency) {
187 223
188 // default: 224 // default:
189 // note_timbre = TIMBRE_12; 225 // note_timbre = TIMBRE_12;
190 // break; 226 // break;
191 // } 227 // }
192 // break; 228 // break;
193 229
194 case duty_osc: 230 case duty_osc:
195 // This slows the loop down a substantial amount, so higher notes may freeze 231 // This slows the loop down a substantial amount, so higher notes may freeze
196 glissando = true; 232 glissando = true;
197 polyphony_rate = 0;
198 switch (compensated_index) { 233 switch (compensated_index) {
199 default: 234 default:
200# define OCS_SPEED 10 235# define OCS_SPEED 10
@@ -202,38 +237,36 @@ float voice_envelope(float frequency) {
202 // sine wave is slow 237 // sine wave is slow
203 // note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5; 238 // note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5;
204 // triangle wave is a bit faster 239 // triangle wave is a bit faster
205 note_timbre = (float)abs((compensated_index * OCS_SPEED % 3000) - 1500) * (OCS_AMP / 1500) + (1 - OCS_AMP) / 2; 240 note_timbre = (uint8_t)abs((compensated_index * OCS_SPEED % 3000) - 1500) * (OCS_AMP / 1500) + (1 - OCS_AMP) / 2;
206 break; 241 break;
207 } 242 }
208 break; 243 break;
209 244
210 case duty_octave_down: 245 case duty_octave_down:
211 glissando = true; 246 glissando = true;
212 polyphony_rate = 0; 247 note_timbre = (uint8_t)(100 * (envelope_index % 2) * .125 + .375 * 2);
213 note_timbre = (envelope_index % 2) * .125 + .375 * 2; 248 if ((envelope_index % 4) == 0) note_timbre = 50;
214 if ((envelope_index % 4) == 0) note_timbre = 0.5;
215 if ((envelope_index % 8) == 0) note_timbre = 0; 249 if ((envelope_index % 8) == 0) note_timbre = 0;
216 break; 250 break;
217 case delayed_vibrato: 251 case delayed_vibrato:
218 glissando = true; 252 glissando = true;
219 polyphony_rate = 0; 253 note_timbre = TIMBRE_50;
220 note_timbre = TIMBRE_50;
221# define VOICE_VIBRATO_DELAY 150 254# define VOICE_VIBRATO_DELAY 150
222# define VOICE_VIBRATO_SPEED 50 255# define VOICE_VIBRATO_SPEED 50
223 switch (compensated_index) { 256 switch (compensated_index) {
224 case 0 ... VOICE_VIBRATO_DELAY: 257 case 0 ... VOICE_VIBRATO_DELAY:
225 break; 258 break;
226 default: 259 default:
260 // TODO: merge/replace with voice_add_vibrato above
227 frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1)) / 1000 * VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; 261 frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1)) / 1000 * VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)];
228 break; 262 break;
229 } 263 }
230 break; 264 break;
231 // case delayed_vibrato_octave: 265 // case delayed_vibrato_octave:
232 // polyphony_rate = 0;
233 // if ((envelope_index % 2) == 1) { 266 // if ((envelope_index % 2) == 1) {
234 // note_timbre = 0.55; 267 // note_timbre = 55;
235 // } else { 268 // } else {
236 // note_timbre = 0.45; 269 // note_timbre = 45;
237 // } 270 // }
238 // #define VOICE_VIBRATO_DELAY 150 271 // #define VOICE_VIBRATO_DELAY 150
239 // #define VOICE_VIBRATO_SPEED 50 272 // #define VOICE_VIBRATO_SPEED 50
@@ -246,35 +279,64 @@ float voice_envelope(float frequency) {
246 // } 279 // }
247 // break; 280 // break;
248 // case duty_fifth_down: 281 // case duty_fifth_down:
249 // note_timbre = 0.5; 282 // note_timbre = TIMBRE_50;
250 // if ((envelope_index % 3) == 0) 283 // if ((envelope_index % 3) == 0)
251 // note_timbre = 0.75; 284 // note_timbre = TIMBRE_75;
252 // break; 285 // break;
253 // case duty_fourth_down: 286 // case duty_fourth_down:
254 // note_timbre = 0.0; 287 // note_timbre = 0;
255 // if ((envelope_index % 12) == 0) 288 // if ((envelope_index % 12) == 0)
256 // note_timbre = 0.75; 289 // note_timbre = TIMBRE_75;
257 // if (((envelope_index % 12) % 4) != 1) 290 // if (((envelope_index % 12) % 4) != 1)
258 // note_timbre = 0.75; 291 // note_timbre = TIMBRE_75;
259 // break; 292 // break;
260 // case duty_third_down: 293 // case duty_third_down:
261 // note_timbre = 0.5; 294 // note_timbre = TIMBRE_50;
262 // if ((envelope_index % 5) == 0) 295 // if ((envelope_index % 5) == 0)
263 // note_timbre = 0.75; 296 // note_timbre = TIMBRE_75;
264 // break; 297 // break;
265 // case duty_fifth_third_down: 298 // case duty_fifth_third_down:
266 // note_timbre = 0.5; 299 // note_timbre = TIMBRE_50;
267 // if ((envelope_index % 5) == 0) 300 // if ((envelope_index % 5) == 0)
268 // note_timbre = 0.75; 301 // note_timbre = TIMBRE_75;
269 // if ((envelope_index % 3) == 0) 302 // if ((envelope_index % 3) == 0)
270 // note_timbre = 0.25; 303 // note_timbre = TIMBRE_25;
271 // break; 304 // break;
272 305
273#endif 306#endif // AUDIO_VOICES
274 307
275 default: 308 default:
276 break; 309 break;
277 } 310 }
278 311
312#ifdef AUDIO_VOICES
313 if (vibrato && (vibrato_strength > 0)) {
314 frequency = voice_add_vibrato(frequency);
315 }
316
317 if (glissando) {
318 // TODO: where to keep track of the start-frequency?
319 // frequency = voice_add_glissando(??, frequency);
320 }
321#endif // AUDIO_VOICES
322
279 return frequency; 323 return frequency;
280} 324}
325
326// Vibrato functions
327
328void voice_set_vibrato_rate(float rate) { vibrato_rate = rate; }
329void voice_increase_vibrato_rate(float change) { vibrato_rate *= change; }
330void voice_decrease_vibrato_rate(float change) { vibrato_rate /= change; }
331void voice_set_vibrato_strength(float strength) { vibrato_strength = strength; }
332void voice_increase_vibrato_strength(float change) { vibrato_strength *= change; }
333void voice_decrease_vibrato_strength(float change) { vibrato_strength /= change; }
334
335// Timbre functions
336
337void voice_set_timbre(uint8_t timbre) {
338 if ((timbre > 0) && (timbre < 100)) {
339 note_timbre = timbre;
340 }
341}
342uint8_t voice_get_timbre(void) { return note_timbre; }
diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h
index abafa2b40..578350d33 100644
--- a/quantum/audio/voices.h
+++ b/quantum/audio/voices.h
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * 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 * it under the terms of the GNU General Public License as published by
@@ -13,7 +14,6 @@
13 * You should have received a copy of the GNU General Public License 14 * 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 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 16 */
16
17#pragma once 17#pragma once
18 18
19#include <stdint.h> 19#include <stdint.h>
@@ -29,6 +29,7 @@ float voice_envelope(float frequency);
29typedef enum { 29typedef enum {
30 default_voice, 30 default_voice,
31#ifdef AUDIO_VOICES 31#ifdef AUDIO_VOICES
32 vibrating,
32 something, 33 something,
33 drums, 34 drums,
34 butts_fader, 35 butts_fader,
@@ -48,3 +49,21 @@ typedef enum {
48void set_voice(voice_type v); 49void set_voice(voice_type v);
49void voice_iterate(void); 50void voice_iterate(void);
50void voice_deiterate(void); 51void voice_deiterate(void);
52
53// Vibrato functions
54void voice_set_vibrato_rate(float rate);
55void voice_increase_vibrato_rate(float change);
56void voice_decrease_vibrato_rate(float change);
57void voice_set_vibrato_strength(float strength);
58void voice_increase_vibrato_strength(float change);
59void voice_decrease_vibrato_strength(float change);
60
61// Timbre functions
62/**
63 * @brief set the global timbre for tones to be played
64 * @note: only applies to pwm implementations - where it adjusts the duty-cycle
65 * @note: using any instrument from voices.[ch] other than 'default' may override the set value
66 * @param[in]: timbre: valid range is (0,100)
67 */
68void voice_set_timbre(uint8_t timbre);
69uint8_t voice_get_timbre(void);
diff --git a/quantum/audio/wave.h b/quantum/audio/wave.h
deleted file mode 100644
index 48210a944..000000000
--- a/quantum/audio/wave.h
+++ /dev/null
@@ -1,36 +0,0 @@
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 <avr/io.h>
18#include <avr/interrupt.h>
19#include <avr/pgmspace.h>
20
21#define SINE_LENGTH 2048
22
23const uint8_t sinewave[] PROGMEM = // 2048 values
24 {0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x93, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xbb,
25 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd5, 0xd5, 0xd5, 0xd5, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8,
26 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
27 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
28 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4,
29 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9d,
30 0x9d, 0x9d, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x94, 0x94, 0x93, 0x93, 0x93, 0x92, 0x92, 0x91, 0x91, 0x91, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x86, 0x86, 0x85, 0x85, 0x85, 0x84, 0x84, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, 0x7a, 0x7a, 0x7a, 0x79, 0x79, 0x78, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x75, 0x75, 0x75, 0x74, 0x74, 0x73, 0x73, 0x73, 0x72, 0x72, 0x71, 0x71, 0x71, 0x70, 0x70, 0x70, 0x6f, 0x6f, 0x6e, 0x6e, 0x6e, 0x6d, 0x6d, 0x6c, 0x6c, 0x6c, 0x6b, 0x6b, 0x6a, 0x6a, 0x6a, 0x69, 0x69, 0x69, 0x68, 0x68, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x62, 0x61, 0x61, 0x61, 0x60,
31 0x60, 0x5f, 0x5f, 0x5f, 0x5e, 0x5e, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5b, 0x5b, 0x5a, 0x5a, 0x5a, 0x59, 0x59, 0x59, 0x58, 0x58, 0x58, 0x57, 0x57, 0x56, 0x56, 0x56, 0x55, 0x55, 0x55, 0x54, 0x54, 0x53, 0x53, 0x53, 0x52, 0x52, 0x52, 0x51, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 0x4f, 0x4e, 0x4e, 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x4a, 0x4a, 0x49, 0x49, 0x49, 0x48, 0x48, 0x48, 0x47, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2a, 0x2a,
32 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26, 0x26, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, 0x10, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xe, 0xe, 0xe, 0xe, 0xe, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8,
33 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
34 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xe, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17,
35 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46,
36 0x46, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f};
diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c
index 4d66da80b..e47192de3 100644
--- a/quantum/backlight/backlight_avr.c
+++ b/quantum/backlight/backlight_avr.c
@@ -68,7 +68,7 @@
68# define COMxx1 COM3A1 68# define COMxx1 COM3A1
69# define OCRxx OCR3A 69# define OCRxx OCR3A
70# endif 70# endif
71#elif (defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) 71#elif (defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
72# define HARDWARE_PWM 72# define HARDWARE_PWM
73# define ICRx ICR1 73# define ICRx ICR1
74# define TCCRxA TCCR1A 74# define TCCRxA TCCR1A
@@ -126,7 +126,7 @@
126# define COMxx1 COM1B1 126# define COMxx1 COM1B1
127# define OCRxx OCR1B 127# define OCRxx OCR1B
128# endif 128# endif
129#elif !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO) 129#elif (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
130// Timer 1 is not in use by Audio feature, Backlight can use it 130// Timer 1 is not in use by Audio feature, Backlight can use it
131# pragma message "Using hardware timer 1 with software PWM" 131# pragma message "Using hardware timer 1 with software PWM"
132# define HARDWARE_PWM 132# define HARDWARE_PWM
@@ -145,7 +145,7 @@
145 145
146# define OCIExA OCIE1A 146# define OCIExA OCIE1A
147# define OCRxx OCR1A 147# define OCRxx OCR1A
148#elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO) 148#elif (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6)
149# pragma message "Using hardware timer 3 with software PWM" 149# pragma message "Using hardware timer 3 with software PWM"
150// Timer 3 is not in use by Audio feature, Backlight can use it 150// Timer 3 is not in use by Audio feature, Backlight can use it
151# define HARDWARE_PWM 151# define HARDWARE_PWM
diff --git a/quantum/command.c b/quantum/command.c
index 59aa4e4d3..34c4b36b1 100644
--- a/quantum/command.c
+++ b/quantum/command.c
@@ -550,22 +550,22 @@ static void mousekey_param_print(void) {
550# if !defined(NO_PRINT) && !defined(USER_PRINT) 550# if !defined(NO_PRINT) && !defined(USER_PRINT)
551 print("\n\t- Values -\n"); 551 print("\n\t- Values -\n");
552 print("1: delay(*10ms): "); 552 print("1: delay(*10ms): ");
553 pdec(mk_delay); 553 print_dec(mk_delay);
554 print("\n"); 554 print("\n");
555 print("2: interval(ms): "); 555 print("2: interval(ms): ");
556 pdec(mk_interval); 556 print_dec(mk_interval);
557 print("\n"); 557 print("\n");
558 print("3: max_speed: "); 558 print("3: max_speed: ");
559 pdec(mk_max_speed); 559 print_dec(mk_max_speed);
560 print("\n"); 560 print("\n");
561 print("4: time_to_max: "); 561 print("4: time_to_max: ");
562 pdec(mk_time_to_max); 562 print_dec(mk_time_to_max);
563 print("\n"); 563 print("\n");
564 print("5: wheel_max_speed: "); 564 print("5: wheel_max_speed: ");
565 pdec(mk_wheel_max_speed); 565 print_dec(mk_wheel_max_speed);
566 print("\n"); 566 print("\n");
567 print("6: wheel_time_to_max: "); 567 print("6: wheel_time_to_max: ");
568 pdec(mk_wheel_time_to_max); 568 print_dec(mk_wheel_time_to_max);
569 print("\n"); 569 print("\n");
570# endif /* !NO_PRINT */ 570# endif /* !NO_PRINT */
571} 571}
diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c
index 6c0e3bb07..60513f98e 100644
--- a/quantum/debounce/sym_defer_pk.c
+++ b/quantum/debounce/sym_defer_pk.c
@@ -23,6 +23,12 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
23#include "quantum.h" 23#include "quantum.h"
24#include <stdlib.h> 24#include <stdlib.h>
25 25
26#ifdef PROTOCOL_CHIBIOS
27# if CH_CFG_USE_MEMCORE == FALSE
28# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
29# endif
30#endif
31
26#ifndef DEBOUNCE 32#ifndef DEBOUNCE
27# define DEBOUNCE 5 33# define DEBOUNCE 5
28#endif 34#endif
diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c
index 93a40ad44..e66cf92d7 100644
--- a/quantum/debounce/sym_eager_pk.c
+++ b/quantum/debounce/sym_eager_pk.c
@@ -23,6 +23,12 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
23#include "quantum.h" 23#include "quantum.h"
24#include <stdlib.h> 24#include <stdlib.h>
25 25
26#ifdef PROTOCOL_CHIBIOS
27# if CH_CFG_USE_MEMCORE == FALSE
28# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
29# endif
30#endif
31
26#ifndef DEBOUNCE 32#ifndef DEBOUNCE
27# define DEBOUNCE 5 33# define DEBOUNCE 5
28#endif 34#endif
diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c
index d12931fdd..20ccb46f1 100644
--- a/quantum/debounce/sym_eager_pr.c
+++ b/quantum/debounce/sym_eager_pr.c
@@ -23,6 +23,12 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
23#include "quantum.h" 23#include "quantum.h"
24#include <stdlib.h> 24#include <stdlib.h>
25 25
26#ifdef PROTOCOL_CHIBIOS
27# if CH_CFG_USE_MEMCORE == FALSE
28# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
29# endif
30#endif
31
26#ifndef DEBOUNCE 32#ifndef DEBOUNCE
27# define DEBOUNCE 5 33# define DEBOUNCE 5
28#endif 34#endif
diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c
index 0608b469c..a860b9497 100644
--- a/quantum/dynamic_keymap.c
+++ b/quantum/dynamic_keymap.c
@@ -37,6 +37,8 @@
37#ifndef DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 37#ifndef DYNAMIC_KEYMAP_EEPROM_MAX_ADDR
38# if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) 38# if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
39# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 2047 39# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 2047
40# elif defined(__AVR_AT90USB162__)
41# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 511
40# else 42# else
41# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 1023 43# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 1023
42# endif 44# endif
diff --git a/quantum/encoder.c b/quantum/encoder.c
index 7ca31afed..2ed64c1e3 100644
--- a/quantum/encoder.c
+++ b/quantum/encoder.c
@@ -94,8 +94,9 @@ void encoder_init(void) {
94#endif 94#endif
95} 95}
96 96
97static void encoder_update(int8_t index, uint8_t state) { 97static bool encoder_update(int8_t index, uint8_t state) {
98 uint8_t i = index; 98 bool changed = false;
99 uint8_t i = index;
99 100
100#ifdef ENCODER_RESOLUTIONS 101#ifdef ENCODER_RESOLUTIONS
101 int8_t resolution = encoder_resolutions[i]; 102 int8_t resolution = encoder_resolutions[i];
@@ -109,40 +110,53 @@ static void encoder_update(int8_t index, uint8_t state) {
109 encoder_pulses[i] += encoder_LUT[state & 0xF]; 110 encoder_pulses[i] += encoder_LUT[state & 0xF];
110 if (encoder_pulses[i] >= resolution) { 111 if (encoder_pulses[i] >= resolution) {
111 encoder_value[index]++; 112 encoder_value[index]++;
113 changed = true;
112 encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); 114 encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
113 } 115 }
114 if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise 116 if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise
115 encoder_value[index]--; 117 encoder_value[index]--;
118 changed = true;
116 encoder_update_kb(index, ENCODER_CLOCKWISE); 119 encoder_update_kb(index, ENCODER_CLOCKWISE);
117 } 120 }
118 encoder_pulses[i] %= resolution; 121 encoder_pulses[i] %= resolution;
122 return changed;
119} 123}
120 124
121void encoder_read(void) { 125bool encoder_read(void) {
126 bool changed = false;
122 for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) { 127 for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) {
123 encoder_state[i] <<= 2; 128 encoder_state[i] <<= 2;
124 encoder_state[i] |= (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1); 129 encoder_state[i] |= (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1);
125 encoder_update(i, encoder_state[i]); 130 changed |= encoder_update(i, encoder_state[i]);
126 } 131 }
132 return changed;
127} 133}
128 134
129#ifdef SPLIT_KEYBOARD 135#ifdef SPLIT_KEYBOARD
136void last_encoder_activity_trigger(void);
137
130void encoder_state_raw(uint8_t* slave_state) { memcpy(slave_state, &encoder_value[thisHand], sizeof(uint8_t) * NUMBER_OF_ENCODERS); } 138void encoder_state_raw(uint8_t* slave_state) { memcpy(slave_state, &encoder_value[thisHand], sizeof(uint8_t) * NUMBER_OF_ENCODERS); }
131 139
132void encoder_update_raw(uint8_t* slave_state) { 140void encoder_update_raw(uint8_t* slave_state) {
141 bool changed = false;
133 for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) { 142 for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) {
134 uint8_t index = i + thatHand; 143 uint8_t index = i + thatHand;
135 int8_t delta = slave_state[i] - encoder_value[index]; 144 int8_t delta = slave_state[i] - encoder_value[index];
136 while (delta > 0) { 145 while (delta > 0) {
137 delta--; 146 delta--;
138 encoder_value[index]++; 147 encoder_value[index]++;
148 changed = true;
139 encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); 149 encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
140 } 150 }
141 while (delta < 0) { 151 while (delta < 0) {
142 delta++; 152 delta++;
143 encoder_value[index]--; 153 encoder_value[index]--;
154 changed = true;
144 encoder_update_kb(index, ENCODER_CLOCKWISE); 155 encoder_update_kb(index, ENCODER_CLOCKWISE);
145 } 156 }
146 } 157 }
158
159 // Update the last encoder input time -- handled external to encoder_read() when we're running a split
160 if (changed) last_encoder_activity_trigger();
147} 161}
148#endif 162#endif
diff --git a/quantum/encoder.h b/quantum/encoder.h
index ec09a8cc4..db6f220da 100644
--- a/quantum/encoder.h
+++ b/quantum/encoder.h
@@ -20,7 +20,7 @@
20#include "quantum.h" 20#include "quantum.h"
21 21
22void encoder_init(void); 22void encoder_init(void);
23void encoder_read(void); 23bool encoder_read(void);
24 24
25void encoder_update_kb(int8_t index, bool clockwise); 25void encoder_update_kb(int8_t index, bool clockwise);
26void encoder_update_user(int8_t index, bool clockwise); 26void encoder_update_user(int8_t index, bool clockwise);
diff --git a/quantum/fauxclicky.c b/quantum/fauxclicky.c
deleted file mode 100644
index 53499c9c1..000000000
--- a/quantum/fauxclicky.c
+++ /dev/null
@@ -1,59 +0,0 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12You should have received a copy of the GNU General Public License
13along with this program. If not, see <http://www.gnu.org/licenses/>.
14*/
15
16#include <avr/interrupt.h>
17#include <avr/io.h>
18#include "timer.h"
19#include "fauxclicky.h"
20#include <stdbool.h>
21#include "musical_notes.h"
22
23bool fauxclicky_enabled = true;
24uint16_t note_start = 0;
25bool note_playing = false;
26uint16_t note_period = 0;
27
28void fauxclicky_init() {
29 // Set port PC6 (OC3A and /OC4A) as output
30 DDRC |= _BV(PORTC6);
31
32 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
33 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
34 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
35}
36
37void fauxclicky_stop() {
38 FAUXCLICKY_DISABLE_OUTPUT;
39 note_playing = false;
40}
41
42void fauxclicky_play(float note[]) {
43 if (!fauxclicky_enabled) return;
44 if (note_playing) fauxclicky_stop();
45 FAUXCLICKY_TIMER_PERIOD = (uint16_t)(((float)F_CPU) / (note[0] * (float)FAUXCLICKY_CPU_PRESCALER));
46 FAUXCLICKY_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (note[0] * (float)FAUXCLICKY_CPU_PRESCALER)) / (float)2);
47 note_playing = true;
48 note_period = (note[1] / (float)16) * ((float)60 / (float)FAUXCLICKY_TEMPO) * 1000;
49 note_start = timer_read();
50 FAUXCLICKY_ENABLE_OUTPUT;
51}
52
53void fauxclicky_check() {
54 if (!note_playing) return;
55
56 if (timer_elapsed(note_start) > note_period) {
57 fauxclicky_stop();
58 }
59}
diff --git a/quantum/fauxclicky.h b/quantum/fauxclicky.h
deleted file mode 100644
index ed54d0edc..000000000
--- a/quantum/fauxclicky.h
+++ /dev/null
@@ -1,97 +0,0 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12You should have received a copy of the GNU General Public License
13along with this program. If not, see <http://www.gnu.org/licenses/>.
14*/
15
16#ifdef AUDIO_ENABLE
17# error "AUDIO_ENABLE and FAUXCLICKY_ENABLE cannot be both enabled"
18#endif
19
20#include "musical_notes.h"
21#include <stdbool.h>
22
23__attribute__((weak)) float fauxclicky_pressed_note[2] = MUSICAL_NOTE(_D4, 0.25);
24__attribute__((weak)) float fauxclicky_released_note[2] = MUSICAL_NOTE(_C4, 0.125);
25__attribute__((weak)) float fauxclicky_beep_note[2] = MUSICAL_NOTE(_C4, 0.25);
26
27extern bool fauxclicky_enabled;
28
29//
30// tempo in BPM
31//
32
33#ifndef FAUXCLICKY_TEMPO
34# define FAUXCLICKY_TEMPO TEMPO_DEFAULT
35#endif
36
37// beep on press
38#define FAUXCLICKY_ACTION_PRESS fauxclicky_play(fauxclicky_pressed_note)
39
40// beep on release
41#define FAUXCLICKY_ACTION_RELEASE fauxclicky_play(fauxclicky_released_note)
42
43// general purpose beep
44#define FAUXCLICKY_BEEP fauxclicky_play(fauxclicky_beep_note)
45
46// enable
47#define FAUXCLICKY_ON fauxclicky_enabled = true
48
49// disable
50#define FAUXCLICKY_OFF \
51 do { \
52 fauxclicky_enabled = false; \
53 fauxclicky_stop(); \
54 } while (0)
55
56// toggle
57#define FAUXCLICKY_TOGGLE \
58 do { \
59 if (fauxclicky_enabled) { \
60 FAUXCLICKY_OFF; \
61 } else { \
62 FAUXCLICKY_ON; \
63 } \
64 } while (0)
65
66//
67// pin configuration
68//
69
70#ifndef FAUXCLICKY_CPU_PRESCALER
71# define FAUXCLICKY_CPU_PRESCALER 8
72#endif
73
74#ifndef FAUXCLICKY_ENABLE_OUTPUT
75# define FAUXCLICKY_ENABLE_OUTPUT TCCR3A |= _BV(COM3A1)
76#endif
77
78#ifndef FAUXCLICKY_DISABLE_OUTPUT
79# define FAUXCLICKY_DISABLE_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0))
80#endif
81
82#ifndef FAUXCLICKY_TIMER_PERIOD
83# define FAUXCLICKY_TIMER_PERIOD ICR3
84#endif
85
86#ifndef FAUXCLICKY_DUTY_CYCLE
87# define FAUXCLICKY_DUTY_CYCLE OCR3A
88#endif
89
90//
91// definitions
92//
93
94void fauxclicky_init(void);
95void fauxclicky_stop(void);
96void fauxclicky_play(float note[2]);
97void fauxclicky_check(void);
diff --git a/quantum/keymap_extras/keymap_us_extended.h b/quantum/keymap_extras/keymap_us_extended.h
new file mode 100644
index 000000000..b2b3a734c
--- /dev/null
+++ b/quantum/keymap_extras/keymap_us_extended.h
@@ -0,0 +1,227 @@
1/* Copyright 2020
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#pragma once
18
19#include "keymap.h"
20
21// clang-format off
22
23/*
24 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
25 * │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │       │
26 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
27 * │     │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │  \  │
28 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
29 * │      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │        │
30 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
31 * │        │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │          │
32 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
33 * │    │    │    │                        │    │    │    │    │
34 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
35 */
36// Row 1
37#define US_GRV KC_GRV // `
38#define US_1 KC_1 // 1
39#define US_2 KC_2 // 2
40#define US_3 KC_3 // 3
41#define US_4 KC_4 // 4
42#define US_5 KC_5 // 5
43#define US_6 KC_6 // 6
44#define US_7 KC_7 // 7
45#define US_8 KC_8 // 8
46#define US_9 KC_9 // 9
47#define US_0 KC_0 // 0
48#define US_MINS KC_MINS // -
49#define US_EQL KC_EQL // =
50// Row 2
51#define US_Q KC_Q // Q
52#define US_W KC_W // W
53#define US_E KC_E // E
54#define US_R KC_R // R
55#define US_T KC_T // T
56#define US_Y KC_Y // Y
57#define US_U KC_U // U
58#define US_I KC_I // I
59#define US_O KC_O // O
60#define US_P KC_P // P
61#define US_LBRC KC_LBRC // [
62#define US_RBRC KC_RBRC // ]
63#define US_BSLS KC_BSLS // (backslash)
64// Row 3
65#define US_A KC_A // A
66#define US_S KC_S // S
67#define US_D KC_D // D
68#define US_F KC_F // F
69#define US_G KC_G // G
70#define US_H KC_H // H
71#define US_J KC_J // J
72#define US_K KC_K // K
73#define US_L KC_L // L
74#define US_SCLN KC_SCLN // ;
75#define US_QUOT KC_QUOT // '
76// Row 4
77#define US_Z KC_Z // Z
78#define US_X KC_X // X
79#define US_C KC_C // C
80#define US_V KC_V // V
81#define US_B KC_B // B
82#define US_N KC_N // N
83#define US_M KC_M // M
84#define US_COMM KC_COMM // ,
85#define US_DOT KC_DOT // .
86#define US_SLSH KC_SLSH // /
87
88/* Shifted symbols
89 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
90 * │ ~ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ ( │ ) │ _ │ + │       │
91 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
92 * │     │   │   │   │   │   │   │   │   │   │   │ { │ } │  |  │
93 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
94 * │      │   │   │   │   │   │   │   │   │   │ : │ " │        │
95 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
96 * │        │   │   │   │   │   │   │   │ < │ > │ ? │          │
97 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
98 * │    │    │    │                        │    │    │    │    │
99 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
100 */
101// Row 1
102#define US_TILD S(US_GRV) // ~
103#define US_EXLM S(US_1) // !
104#define US_AT S(US_2) // @
105#define US_HASH S(US_3) // #
106#define US_DLR S(US_4) // $
107#define US_PERC S(US_5) // %
108#define US_CIRC S(US_6) // ^
109#define US_AMPR S(US_7) // &
110#define US_ASTR S(US_8) // *
111#define US_LPRN S(US_9) // (
112#define US_RPRN S(US_0) // )
113#define US_UNDS S(US_MINS) // _
114#define US_PLUS S(US_EQL) // +
115// Row 2
116#define US_LCBR S(US_LBRC) // {
117#define US_RCBR S(US_RBRC) // }
118#define US_PIPE S(US_BSLS) // |
119// Row 3
120#define US_COLN S(US_SCLN) // :
121#define US_DQUO S(US_QUOT) // "
122// Row 4
123#define US_LABK S(US_COMM) // <
124#define US_RABK S(US_DOT) // >
125#define US_QUES S(US_SLSH) // ?
126
127/* AltGr symbols
128 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
129 * │ ` │ ¹ │ ² │ ³ │ ¤ │ € │ ^ │ ̛  │ ¾ │ ‘ │ ’ │ ¥ │ × │       │
130 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
131 * │     │ Ä │ Å │ É │ ® │ Þ │ Ü │ Ú │ Í │ Ó │ Ö │ « │ » │  ¬  │
132 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
133 * │      │ Á │ ß │ Ð │   │   │   │ Ï │ Œ │ Ø │ ¶ │ ' │        │
134 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
135 * │        │ Æ │   │ © │   │   │ Ñ │ µ │ Ç │ ˙ │ ¿ │          │
136 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
137 * │    │    │    │                        │    │    │    │    │
138 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
139 */
140// Row 1
141#define US_DGRV ALGR(US_GRV) // ` (dead)
142#define US_SUP1 ALGR(US_1) // ¹
143#define US_SUP2 ALGR(US_2) // ²
144#define US_SUP3 ALGR(US_3) // ³
145#define US_CURR ALGR(US_4) // ¤
146#define US_EURO ALGR(US_5) // €
147#define US_DCIR ALGR(US_6) // ^ (dead)
148#define US_HORN ALGR(US_7) // ̛̛ (dead)
149#define US_OGON ALGR(US_8) // ˛ (dead)
150#define US_LSQU ALGR(US_9) // ‘
151#define US_RSQU ALGR(US_0) // ’
152#define US_YEN ALGR(US_MINS) // ¥
153#define US_MUL ALGR(US_EQL) // ×
154// Row 2
155#define US_ADIA ALGR(US_Q) // Ä
156#define US_ARNG ALGR(US_W) // Å
157#define US_EACU ALGR(US_E) // É
158#define US_EDIA ALGR(US_R) // Ë
159#define US_THRN ALGR(US_T) // Þ
160#define US_UDIA ALGR(US_Y) // Ü
161#define US_UACU ALGR(US_U) // Ú
162#define US_IACU ALGR(US_I) // Í
163#define US_OACU ALGR(US_O) // Ó
164#define US_ODIA ALGR(US_P) // Ö
165#define US_LDAQ ALGR(US_LBRC) // «
166#define US_RDAQ ALGR(US_RBRC) // »
167#define US_NOT ALGR(US_BSLS) // ¬
168// Row 3
169#define US_AACU ALGR(US_A) // Á
170#define US_SS ALGR(US_S) // ß
171#define US_ETH ALGR(US_D) // Ð
172#define US_IDIA ALGR(US_J) // Ï
173#define US_OE ALGR(US_K) // Œ
174#define US_OSTR ALGR(US_L) // Ø
175#define US_PILC ALGR(US_SCLN) // ¶
176#define US_ACUT ALGR(US_QUOT) // ´ (dead)
177// Row 4
178#define US_AE ALGR(US_Z) // Æ
179#define US_OE_2 ALGR(US_X) // Œ
180#define US_COPY ALGR(US_C) // ©
181#define US_REGD ALGR(US_V) // ®
182#define US_NTIL ALGR(US_N) // Ñ
183#define US_MICR ALGR(US_M) // µ
184#define US_CCED ALGR(US_COMM) // Ç
185#define US_DOTA ALGR(US_DOT) // ˙ (dead)
186#define US_IQUE ALGR(US_SLSH) // ¿
187
188/* Shift+AltGr symbols
189 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
190 * │ ~ │ ¡ │ ˝ │ ¯ │ £ │ ¸ │ ¼ │ ½ │ ¾ │ ˘ │ ° │  ̣ │ ÷ │       │
191 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
192 * │     │   │   │   │   │   │   │   │   │   │   │ “ │ ” │  ¦  │
193 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
194 * │      │   │ § │   │   │   │   │   │   │   │ ° │ " │        │
195 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
196 * │        │   │   │ ¢ │   │   │   │   │   │ ˇ │  ̉ │          │
197 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
198 * │    │    │    │                        │    │    │    │    │
199 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
200 */
201// Row 1
202#define US_DTIL S(ALGR(US_GRV)) // ~ (dead)
203#define US_IEXL S(ALGR(US_1)) // ¡
204#define US_DACU S(ALGR(US_2)) // ˝ (dead)
205#define US_MACR S(ALGR(US_3)) // ¯ (dead)
206#define US_PND S(ALGR(US_4)) // £
207#define US_CEDL S(ALGR(US_5)) // ¸ (dead)
208#define US_QRTR S(ALGR(US_6)) // ¼
209#define US_HALF S(ALGR(US_7)) // ½
210#define US_TQTR S(ALGR(US_8)) // ¾
211#define US_BREV S(ALGR(US_9)) // ˘ (dead)
212#define US_RNGA S(ALGR(US_0)) // ° (dead)
213#define US_DOTB S(ALGR(US_MINS)) // ̣ (dead)
214#define US_DIV S(ALGR(US_EQL)) // ÷
215// Row 2
216#define US_LDQU S(ALGR(US_LBRC)) // “
217#define US_RDQU S(ALGR(US_LBRC)) // ”
218#define US_BRKP S(ALGR(US_BSLS)) // ¦
219// Row 3
220#define US_SECT S(ALGR(US_S)) // §
221#define US_DEG S(ALGR(US_SCLN)) // °
222#define US_DIAE S(ALGR(US_QUOT)) // ¨ (dead)
223// Row 4
224#define US_CENT S(ALGR(US_C)) // ¢
225#define US_CARN S(ALGR(US_DOT)) // ˇ (dead)
226#define US_HOKA S(ALGR(US_SLSH)) // ̉ (dead)
227
diff --git a/quantum/keymap_extras/keymap_us_international.h b/quantum/keymap_extras/keymap_us_international.h
index a3bc46597..49afcc4fb 100644
--- a/quantum/keymap_extras/keymap_us_international.h
+++ b/quantum/keymap_extras/keymap_us_international.h
@@ -26,7 +26,7 @@
26 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ 26 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
27 * │     │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │  \  │ 27 * │     │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │  \  │
28 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ 28 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
29 * │      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │        │ 29 * │      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ´ │        │
30 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ 30 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
31 * │        │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │          │ 31 * │        │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │          │
32 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ 32 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
@@ -34,7 +34,7 @@
34 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘ 34 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
35 */ 35 */
36// Row 1 36// Row 1
37#define US_GRV KC_GRV // ` (dead) 37#define US_DGRV KC_GRV // ` (dead)
38#define US_1 KC_1 // 1 38#define US_1 KC_1 // 1
39#define US_2 KC_2 // 2 39#define US_2 KC_2 // 2
40#define US_3 KC_3 // 3 40#define US_3 KC_3 // 3
@@ -72,7 +72,7 @@
72#define US_K KC_K // K 72#define US_K KC_K // K
73#define US_L KC_L // L 73#define US_L KC_L // L
74#define US_SCLN KC_SCLN // ; 74#define US_SCLN KC_SCLN // ;
75#define US_QUOT KC_QUOT // ' (dead) 75#define US_ACUT KC_QUOT // ´ (dead)
76// Row 4 76// Row 4
77#define US_Z KC_Z // Z 77#define US_Z KC_Z // Z
78#define US_X KC_X // X 78#define US_X KC_X // X
@@ -91,7 +91,7 @@
91 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ 91 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
92 * │     │   │   │   │   │   │   │   │   │   │   │ { │ } │  |  │ 92 * │     │   │   │   │   │   │   │   │   │   │   │ { │ } │  |  │
93 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ 93 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
94 * │      │   │   │   │   │   │   │   │   │   │ : │ " │        │ 94 * │      │   │   │   │   │   │   │   │   │   │ : │ ¨ │        │
95 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ 95 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
96 * │        │   │   │   │   │   │   │   │ < │ > │ ? │          │ 96 * │        │   │   │   │   │   │   │   │ < │ > │ ? │          │
97 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ 97 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
@@ -99,13 +99,13 @@
99 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘ 99 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
100 */ 100 */
101// Row 1 101// Row 1
102#define US_TILD S(US_GRV) // ~ (dead) 102#define US_DTIL S(US_DGRV) // ~ (dead)
103#define US_EXLM S(US_1) // ! 103#define US_EXLM S(US_1) // !
104#define US_AT S(US_2) // " 104#define US_AT S(US_2) // @
105#define US_HASH S(US_3) // # 105#define US_HASH S(US_3) // #
106#define US_DLR S(US_4) // $ 106#define US_DLR S(US_4) // $
107#define US_PERC S(US_5) // % 107#define US_PERC S(US_5) // %
108#define US_CIRC S(US_6) // ^ 108#define US_DCIR S(US_6) // ^ (dead)
109#define US_AMPR S(US_7) // & 109#define US_AMPR S(US_7) // &
110#define US_ASTR S(US_8) // * 110#define US_ASTR S(US_8) // *
111#define US_LPRN S(US_9) // ( 111#define US_LPRN S(US_9) // (
@@ -118,7 +118,7 @@
118#define US_PIPE S(US_BSLS) // | 118#define US_PIPE S(US_BSLS) // |
119// Row 3 119// Row 3
120#define US_COLN S(US_SCLN) // : 120#define US_COLN S(US_SCLN) // :
121#define US_DQUO S(US_QUOT) // " (dead) 121#define US_DIAE S(US_ACUT) // ¨ (dead)
122// Row 4 122// Row 4
123#define US_LABK S(US_COMM) // < 123#define US_LABK S(US_COMM) // <
124#define US_RABK S(US_DOT) // > 124#define US_RABK S(US_DOT) // >
@@ -170,7 +170,7 @@
170#define US_ETH ALGR(US_D) // Ð 170#define US_ETH ALGR(US_D) // Ð
171#define US_OSTR ALGR(US_L) // Ø 171#define US_OSTR ALGR(US_L) // Ø
172#define US_PILC ALGR(US_SCLN) // ¶ 172#define US_PILC ALGR(US_SCLN) // ¶
173#define US_ACUT ALGR(US_QUOT) // ´ 173#define US_NDAC ALGR(US_ACUT) // ´
174// Row 4 174// Row 4
175#define US_AE ALGR(US_Z) // Æ 175#define US_AE ALGR(US_Z) // Æ
176#define US_COPY ALGR(US_C) // © 176#define US_COPY ALGR(US_C) // ©
@@ -201,6 +201,6 @@
201// Row 3 201// Row 3
202#define US_SECT S(ALGR(US_S)) // § 202#define US_SECT S(ALGR(US_S)) // §
203#define US_DEG S(ALGR(US_SCLN)) // ° 203#define US_DEG S(ALGR(US_SCLN)) // °
204#define US_DIAE S(ALGR(US_QUOT)) // ¨ 204#define US_NDDR S(ALGR(US_ACUT)) // ¨
205// Row 4 205// Row 4
206#define US_CENT S(ALGR(US_C)) // ¢ 206#define US_CENT S(ALGR(US_C)) // ¢
diff --git a/quantum/keymap_extras/keymap_us_international_linux.h b/quantum/keymap_extras/keymap_us_international_linux.h
new file mode 100644
index 000000000..2c3e23039
--- /dev/null
+++ b/quantum/keymap_extras/keymap_us_international_linux.h
@@ -0,0 +1,224 @@
1/* Copyright 2020
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#pragma once
18
19#include "keymap.h"
20
21// clang-format off
22
23/*
24 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
25 * │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │       │
26 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
27 * │     │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │  \  │
28 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
29 * │      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ´ │        │
30 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
31 * │        │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │          │
32 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
33 * │    │    │    │                        │    │    │    │    │
34 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
35 */
36// Row 1
37#define US_DGRV KC_GRV // ` (dead)
38#define US_1 KC_1 // 1
39#define US_2 KC_2 // 2
40#define US_3 KC_3 // 3
41#define US_4 KC_4 // 4
42#define US_5 KC_5 // 5
43#define US_6 KC_6 // 6
44#define US_7 KC_7 // 7
45#define US_8 KC_8 // 8
46#define US_9 KC_9 // 9
47#define US_0 KC_0 // 0
48#define US_MINS KC_MINS // -
49#define US_EQL KC_EQL // =
50// Row 2
51#define US_Q KC_Q // Q
52#define US_W KC_W // W
53#define US_E KC_E // E
54#define US_R KC_R // R
55#define US_T KC_T // T
56#define US_Y KC_Y // Y
57#define US_U KC_U // U
58#define US_I KC_I // I
59#define US_O KC_O // O
60#define US_P KC_P // P
61#define US_LBRC KC_LBRC // [
62#define US_RBRC KC_RBRC // ]
63#define US_BSLS KC_BSLS // (backslash)
64// Row 3
65#define US_A KC_A // A
66#define US_S KC_S // S
67#define US_D KC_D // D
68#define US_F KC_F // F
69#define US_G KC_G // G
70#define US_H KC_H // H
71#define US_J KC_J // J
72#define US_K KC_K // K
73#define US_L KC_L // L
74#define US_SCLN KC_SCLN // ;
75#define US_ACUT KC_QUOT // ´ (dead)
76// Row 4
77#define US_Z KC_Z // Z
78#define US_X KC_X // X
79#define US_C KC_C // C
80#define US_V KC_V // V
81#define US_B KC_B // B
82#define US_N KC_N // N
83#define US_M KC_M // M
84#define US_COMM KC_COMM // ,
85#define US_DOT KC_DOT // .
86#define US_SLSH KC_SLSH // /
87
88/* Shifted symbols
89 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
90 * │ ~ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ ( │ ) │ _ │ + │       │
91 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
92 * │     │   │   │   │   │   │   │   │   │   │   │ { │ } │  |  │
93 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
94 * │      │   │   │   │   │   │   │   │   │   │ : │ ¨ │        │
95 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
96 * │        │   │   │   │   │   │   │   │ < │ > │ ? │          │
97 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
98 * │    │    │    │                        │    │    │    │    │
99 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
100 */
101// Row 1
102#define US_DTIL S(US_DGRV) // ~ (dead)
103#define US_EXLM S(US_1) // !
104#define US_AT S(US_2) // @
105#define US_HASH S(US_3) // #
106#define US_DLR S(US_4) // $
107#define US_PERC S(US_5) // %
108#define US_DCIR S(US_6) // ^ (dead)
109#define US_AMPR S(US_7) // &
110#define US_ASTR S(US_8) // *
111#define US_LPRN S(US_9) // (
112#define US_RPRN S(US_0) // )
113#define US_UNDS S(US_MINS) // _
114#define US_PLUS S(US_EQL) // +
115// Row 2
116#define US_LCBR S(US_LBRC) // {
117#define US_RCBR S(US_RBRC) // }
118#define US_PIPE S(US_BSLS) // |
119// Row 3
120#define US_COLN S(US_SCLN) // :
121#define US_DIAE S(US_ACUT) // ¨ (dead)
122// Row 4
123#define US_LABK S(US_COMM) // <
124#define US_RABK S(US_DOT) // >
125#define US_QUES S(US_SLSH) // ?
126
127/* AltGr symbols
128 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
129 * │ ` │ ¡ │ ² │ ³ │ ¤ │ € │ ¼ │ ½ │ ¾ │ ‘ │ ’ │ ¥ │ × │       │
130 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
131 * │     │ Ä │ Å │ É │ ® │ Þ │ Ü │ Ú │ Í │ Ó │ Ö │ « │ » │  ¬  │
132 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
133 * │      │ Á │ ß │ Ð │   │   │   │   │ Œ │ Ø │ ¶ │ ' │        │
134 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
135 * │        │ Æ │   │ © │   │   │ Ñ │ µ │ Ç │ ˙ │ ¿ │          │
136 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
137 * │    │    │    │                        │    │    │    │    │
138 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
139 */
140
141// Row 1
142#define US_GRV ALGR(US_DGRV) // `
143#define US_IEXL ALGR(US_1) // ¡
144#define US_SUP2 ALGR(US_2) // ²
145#define US_SUP3 ALGR(US_3) // ³
146#define US_CURR ALGR(US_4) // ¤
147#define US_EURO ALGR(US_5) // €
148#define US_QRTR ALGR(US_6) // ¼
149#define US_HALF ALGR(US_7) // ½
150#define US_TQTR ALGR(US_8) // ¾
151#define US_LSQU ALGR(US_9) // ‘
152#define US_RSQU ALGR(US_0) // ’
153#define US_YEN ALGR(US_MINS) // ¥
154#define US_MUL ALGR(US_EQL) // ×
155// Row 2
156#define US_ADIA ALGR(US_Q) // Ä
157#define US_ARNG ALGR(US_W) // Å
158#define US_EACU ALGR(US_E) // É
159#define US_REGD ALGR(US_R) // ®
160#define US_THRN ALGR(US_T) // Þ
161#define US_UDIA ALGR(US_Y) // Ü
162#define US_UACU ALGR(US_U) // Ú
163#define US_IACU ALGR(US_I) // Í
164#define US_OACU ALGR(US_O) // Ó
165#define US_ODIA ALGR(US_P) // Ö
166#define US_LDAQ ALGR(US_LBRC) // «
167#define US_RDAQ ALGR(US_RBRC) // »
168#define US_NOT ALGR(US_BSLS) // ¬
169// Row 3
170#define US_AACU ALGR(US_A) // Á
171#define US_SS ALGR(US_S) // ß
172#define US_ETH ALGR(US_D) // Ð
173#define US_OE ALGR(US_K) // Œ
174#define US_OSTR ALGR(US_L) // Ø
175#define US_PILC ALGR(US_SCLN) // ¶
176#define US_QUOT ALGR(US_ACUT) // '
177// Row 4
178#define US_AE ALGR(US_Z) // Æ
179#define US_COPY ALGR(US_C) // ©
180#define US_NTIL ALGR(US_N) // Ñ
181#define US_MICR ALGR(US_M) // µ
182#define US_CCED ALGR(US_COMM) // Ç
183#define US_DOTA ALGR(US_DOT) // ˙ (dead)
184#define US_IQUE ALGR(US_SLSH) // ¿
185
186/* Shift+AltGr symbols
187 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
188 * │ ~ │ ¹ │ ˝ │ ¯ │ £ │ ¸ │ ^ │ ̛  │ ˛ │ ˘ │ ° │  ̣ │ ÷ │       │
189 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
190 * │     │   │   │   │   │   │   │   │   │   │   │ “ │ ” │  ¦  │
191 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
192 * │      │   │ § │   │   │   │   │   │   │   │ ° │ " │        │
193 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
194 * │        │   │   │ ¢ │   │   │   │   │   │ ˇ │  ̉ │          │
195 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
196 * │    │    │    │                        │    │    │    │    │
197 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
198 */
199// Row 1
200#define US_TILD S(ALGR(US_DGRV)) // ~
201#define US_SUP1 S(ALGR(US_1)) // ¹
202#define US_DACU S(ALGR(US_2)) // ˝ (dead)
203#define US_MACR S(ALGR(US_3)) // ¯ (dead)
204#define US_PND S(ALGR(US_4)) // £
205#define US_CEDL S(ALGR(US_5)) // ¸ (dead)
206#define US_CIRC S(ALGR(US_6)) // ^
207#define US_HORN S(ALGR(US_7)) // ̛ (dead)
208#define US_OGON S(ALGR(US_8)) // ˛ (dead)
209#define US_BREV S(ALGR(US_9)) // ˘ (dead)
210#define US_RNGA S(ALGR(US_0)) // ° (dead)
211#define US_DOTB S(ALGR(US_MINS)) // ̣ (dead)
212#define US_DIV S(ALGR(US_EQL)) // ÷
213// Row 2
214#define US_LDQU S(ALGR(US_LBRC)) // “
215#define US_RDQU S(ALGR(US_LBRC)) // ”
216#define US_BRKP S(ALGR(US_BSLS)) // ¦
217// Row 3
218#define US_SECT S(ALGR(US_S)) // §
219#define US_DEG S(ALGR(US_SCLN)) // °
220#define US_DQUO S(ALGR(US_ACUT)) // "
221// Row 4
222#define US_CENT S(ALGR(US_C)) // ¢
223#define US_CARN S(ALGR(US_DOT)) // ˇ (dead)
224#define US_HOKA S(ALGR(US_SLSH)) // ̉ (dead)
diff --git a/quantum/keymap_extras/sendstring_us_international.h b/quantum/keymap_extras/sendstring_us_international.h
new file mode 100644
index 000000000..53a5891fb
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_us_international.h
@@ -0,0 +1,100 @@
1/* Copyright 2019 Rys Sommefeldt
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// Sendstring lookup tables for UK layouts
18
19#pragma once
20
21#include "keymap_us_international.h"
22#include "quantum.h"
23
24// clang-format off
25
26const uint8_t ascii_to_shift_lut[16] PROGMEM = {
27 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
28 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
29 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
30 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
31
32 KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 0),
33 KCLUT_ENTRY(1, 1, 1, 1, 0, 0, 0, 0),
34 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
35 KCLUT_ENTRY(0, 0, 1, 0, 1, 0, 1, 1),
36 KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
37 KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
38 KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
39 KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 1, 1),
40 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
41 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
42 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
43 KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0),
44};
45
46__attribute__((weak)) const uint8_t ascii_to_dead_lut[16] PROGMEM = {
47 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
48 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
49 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
50 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
51
52 KCLUT_ENTRY(0, 0, 1, 0, 0, 0, 0, 1),
53 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
54 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
55 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
56 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
57 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
58 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
59 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
60 KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0),
61 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
62 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
63 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 1, 0),
64};
65
66const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
67 // NUL SOH STX ETX EOT ENQ ACK BEL
68 XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
69 // BS TAB LF VT FF CR SO SI
70 KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
71 // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
72 XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
73 // CAN EM SUB ESC FS GS RS US
74 XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
75
76 // ! " # $ % & '
77 KC_SPC, US_1, US_ACUT, US_3, US_4, US_5, US_7, US_ACUT,
78 // ( ) * + , - . /
79 US_9, US_0, US_8, US_EQL, US_COMM, US_MINS, US_DOT, US_SLSH,
80 // 0 1 2 3 4 5 6 7
81 US_0, US_1, US_2, US_3, US_4, US_5, US_6, US_7,
82 // 8 9 : ; < = > ?
83 US_8, US_9, US_SCLN, US_SCLN, US_COMM, US_EQL, US_DOT, US_SLSH,
84 // @ A B C D E F G
85 US_2, US_A, US_B, US_C, US_D, US_E, US_F, US_G,
86 // H I J K L M N O
87 US_H, US_I, US_J, US_K, US_L, US_M, US_N, US_O,
88 // P Q R S T U V W
89 US_P, US_Q, US_R, US_S, US_T, US_U, US_V, US_W,
90 // X Y Z [ \ ] ^ _
91 US_X, US_Y, US_Z, US_LBRC, US_BSLS, US_RBRC, US_6, US_MINS,
92 // ` a b c d e f g
93 US_DGRV, US_A, US_B, US_C, US_D, US_E, US_F, US_G,
94 // h i j k l m n o
95 US_H, US_I, US_J, US_K, US_L, US_M, US_N, US_O,
96 // p q r s t u v w
97 US_P, US_Q, US_R, US_S, US_T, US_U, US_V, US_W,
98 // x y z { | } ~ DEL
99 US_X, US_Y, US_Z, US_LBRC, US_BSLS, US_RBRC, US_DGRV, KC_DEL
100};
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 9083ff386..c027b7bf2 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -101,9 +101,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
101 // Start with a clear matrix row 101 // Start with a clear matrix row
102 matrix_row_t current_row_value = 0; 102 matrix_row_t current_row_value = 0;
103 103
104 // Select row and wait for row selecton to stabilize 104 // Select row
105 select_row(current_row); 105 select_row(current_row);
106 matrix_io_delay(); 106 matrix_output_select_delay();
107 107
108 // For each col... 108 // For each col...
109 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 109 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
@@ -116,6 +116,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
116 116
117 // Unselect row 117 // Unselect row
118 unselect_row(current_row); 118 unselect_row(current_row);
119 if (current_row + 1 < MATRIX_ROWS) {
120 matrix_output_unselect_delay(); // wait for row signal to go HIGH
121 }
119 122
120 // If the row has changed, store the row and return the changed flag. 123 // If the row has changed, store the row and return the changed flag.
121 if (current_matrix[current_row] != current_row_value) { 124 if (current_matrix[current_row] != current_row_value) {
@@ -147,9 +150,9 @@ static void init_pins(void) {
147static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { 150static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
148 bool matrix_changed = false; 151 bool matrix_changed = false;
149 152
150 // Select col and wait for col selecton to stabilize 153 // Select col
151 select_col(current_col); 154 select_col(current_col);
152 matrix_io_delay(); 155 matrix_output_select_delay();
153 156
154 // For each row... 157 // For each row...
155 for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) { 158 for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
@@ -175,6 +178,9 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
175 178
176 // Unselect col 179 // Unselect col
177 unselect_col(current_col); 180 unselect_col(current_col);
181 if (current_col + 1 < MATRIX_COLS) {
182 matrix_output_unselect_delay(); // wait for col signal to go HIGH
183 }
178 184
179 return matrix_changed; 185 return matrix_changed;
180} 186}
diff --git a/quantum/matrix.h b/quantum/matrix.h
index b570227a3..ce57010a4 100644
--- a/quantum/matrix.h
+++ b/quantum/matrix.h
@@ -55,6 +55,9 @@ matrix_row_t matrix_get_row(uint8_t row);
55/* print matrix for debug */ 55/* print matrix for debug */
56void matrix_print(void); 56void matrix_print(void);
57/* delay between changing matrix pin state and reading values */ 57/* delay between changing matrix pin state and reading values */
58void matrix_output_select_delay(void);
59void matrix_output_unselect_delay(void);
60/* only for backwards compatibility. delay between changing matrix pin state and reading values */
58void matrix_io_delay(void); 61void matrix_io_delay(void);
59 62
60/* power control */ 63/* power control */
diff --git a/quantum/matrix_common.c b/quantum/matrix_common.c
index 15f1e0e82..efbad6a5f 100644
--- a/quantum/matrix_common.c
+++ b/quantum/matrix_common.c
@@ -1,3 +1,4 @@
1#include "quantum.h"
1#include "matrix.h" 2#include "matrix.h"
2#include "debounce.h" 3#include "debounce.h"
3#include "wait.h" 4#include "wait.h"
@@ -68,7 +69,7 @@ void matrix_print(void) {
68 print_matrix_header(); 69 print_matrix_header();
69 70
70 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 71 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
71 phex(row); 72 print_hex8(row);
72 print(": "); 73 print(": ");
73 print_matrix_row(row); 74 print_matrix_row(row);
74 print("\n"); 75 print("\n");
@@ -83,8 +84,12 @@ uint8_t matrix_key_count(void) {
83 return count; 84 return count;
84} 85}
85 86
87/* `matrix_io_delay ()` exists for backwards compatibility. From now on, use matrix_output_unselect_delay(). */
86__attribute__((weak)) void matrix_io_delay(void) { wait_us(MATRIX_IO_DELAY); } 88__attribute__((weak)) void matrix_io_delay(void) { wait_us(MATRIX_IO_DELAY); }
87 89
90__attribute__((weak)) void matrix_output_select_delay(void) { waitInputPinDelay(); }
91__attribute__((weak)) void matrix_output_unselect_delay(void) { matrix_io_delay(); }
92
88// CUSTOM MATRIX 'LITE' 93// CUSTOM MATRIX 'LITE'
89__attribute__((weak)) void matrix_init_custom(void) {} 94__attribute__((weak)) void matrix_init_custom(void) {}
90 95
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk
index 6b11eb498..81c467c65 100644
--- a/quantum/mcu_selection.mk
+++ b/quantum/mcu_selection.mk
@@ -279,7 +279,73 @@ ifneq ($(findstring STM32F411, $(MCU)),)
279 DFU_SUFFIX_ARGS ?= -v 0483 -p DF11 279 DFU_SUFFIX_ARGS ?= -v 0483 -p DF11
280endif 280endif
281 281
282ifneq (,$(filter $(MCU),atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647 at90usb1286 at90usb1287)) 282ifneq ($(findstring STM32G431, $(MCU)),)
283 # Cortex version
284 MCU = cortex-m4
285
286 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
287 ARMV = 7
288
289 ## chip/board settings
290 # - the next two should match the directories in
291 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
292 MCU_FAMILY = STM32
293 MCU_SERIES = STM32G4xx
294
295 # Linker script to use
296 # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
297 # or <keyboard_dir>/ld/
298 MCU_LDSCRIPT ?= STM32G431xB
299
300 # Startup code to use
301 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
302 MCU_STARTUP ?= stm32g4xx
303
304 # Board: it should exist either in <chibios>/os/hal/boards/,
305 # <keyboard_dir>/boards/, or drivers/boards/
306 BOARD ?= GENERIC_STM32_G431XB
307
308 USE_FPU ?= yes
309
310 # Options to pass to dfu-util when flashing
311 DFU_ARGS ?= -d 0483:DF11 -a 0 -s 0x08000000:leave
312 DFU_SUFFIX_ARGS ?= -v 0483 -p DF11
313endif
314
315ifneq ($(findstring STM32G474, $(MCU)),)
316 # Cortex version
317 MCU = cortex-m4
318
319 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
320 ARMV = 7
321
322 ## chip/board settings
323 # - the next two should match the directories in
324 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
325 MCU_FAMILY = STM32
326 MCU_SERIES = STM32G4xx
327
328 # Linker script to use
329 # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
330 # or <keyboard_dir>/ld/
331 MCU_LDSCRIPT ?= STM32G474xE
332
333 # Startup code to use
334 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
335 MCU_STARTUP ?= stm32g4xx
336
337 # Board: it should exist either in <chibios>/os/hal/boards/,
338 # <keyboard_dir>/boards/, or drivers/boards/
339 BOARD ?= GENERIC_STM32_G474XE
340
341 USE_FPU ?= yes
342
343 # Options to pass to dfu-util when flashing
344 DFU_ARGS ?= -d 0483:DF11 -a 0 -s 0x08000000:leave
345 DFU_SUFFIX_ARGS ?= -v 0483 -p DF11
346endif
347
348ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647 at90usb1286 at90usb1287))
283 PROTOCOL = LUFA 349 PROTOCOL = LUFA
284 350
285 # Processor frequency. 351 # Processor frequency.
@@ -317,7 +383,7 @@ ifneq (,$(filter $(MCU),atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 a
317 ifeq (,$(filter $(NO_INTERRUPT_CONTROL_ENDPOINT),yes)) 383 ifeq (,$(filter $(NO_INTERRUPT_CONTROL_ENDPOINT),yes))
318 OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT 384 OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
319 endif 385 endif
320 ifneq (,$(filter $(MCU),atmega16u2 atmega32u2)) 386 ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2))
321 NO_I2C = yes 387 NO_I2C = yes
322 endif 388 endif
323endif 389endif
diff --git a/quantum/mousekey.c b/quantum/mousekey.c
new file mode 100644
index 000000000..63e74baa9
--- /dev/null
+++ b/quantum/mousekey.c
@@ -0,0 +1,488 @@
1/*
2 * Copyright 2011 Jun Wako <wakojun@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <stdint.h>
19#include "keycode.h"
20#include "host.h"
21#include "timer.h"
22#include "print.h"
23#include "debug.h"
24#include "mousekey.h"
25
26inline int8_t times_inv_sqrt2(int8_t x) {
27 // 181/256 is pretty close to 1/sqrt(2)
28 // 0.70703125 0.707106781
29 // 1 too small for x=99 and x=198
30 // This ends up being a mult and discard lower 8 bits
31 return (x * 181) >> 8;
32}
33
34static report_mouse_t mouse_report = {0};
35static void mousekey_debug(void);
36static uint8_t mousekey_accel = 0;
37static uint8_t mousekey_repeat = 0;
38static uint8_t mousekey_wheel_repeat = 0;
39#ifdef MK_KINETIC_SPEED
40static uint16_t mouse_timer = 0;
41#endif
42
43#ifndef MK_3_SPEED
44
45static uint16_t last_timer_c = 0;
46static uint16_t last_timer_w = 0;
47
48/*
49 * Mouse keys acceleration algorithm
50 * http://en.wikipedia.org/wiki/Mouse_keys
51 *
52 * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000)
53 */
54/* milliseconds between the initial key press and first repeated motion event (0-2550) */
55uint8_t mk_delay = MOUSEKEY_DELAY / 10;
56/* milliseconds between repeated motion events (0-255) */
57uint8_t mk_interval = MOUSEKEY_INTERVAL;
58/* steady speed (in action_delta units) applied each event (0-255) */
59uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED;
60/* number of events (count) accelerating to steady speed (0-255) */
61uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
62/* ramp used to reach maximum pointer speed (NOT SUPPORTED) */
63// int8_t mk_curve = 0;
64/* wheel params */
65/* milliseconds between the initial key press and first repeated motion event (0-2550) */
66uint8_t mk_wheel_delay = MOUSEKEY_WHEEL_DELAY / 10;
67/* milliseconds between repeated motion events (0-255) */
68uint8_t mk_wheel_interval = MOUSEKEY_WHEEL_INTERVAL;
69uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED;
70uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
71
72# ifndef MK_COMBINED
73
74static uint8_t move_unit(void) {
75 uint16_t unit;
76 if (mousekey_accel & (1 << 0)) {
77 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 4;
78 } else if (mousekey_accel & (1 << 1)) {
79 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2;
80 } else if (mousekey_accel & (1 << 2)) {
81 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed);
82 } else if (mousekey_repeat == 0) {
83 unit = MOUSEKEY_MOVE_DELTA;
84 } else if (mousekey_repeat >= mk_time_to_max) {
85 unit = MOUSEKEY_MOVE_DELTA * mk_max_speed;
86 } else {
87 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max;
88 }
89 return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit));
90}
91
92static uint8_t wheel_unit(void) {
93 uint16_t unit;
94 if (mousekey_accel & (1 << 0)) {
95 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 4;
96 } else if (mousekey_accel & (1 << 1)) {
97 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2;
98 } else if (mousekey_accel & (1 << 2)) {
99 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed);
100 } else if (mousekey_wheel_repeat == 0) {
101 unit = MOUSEKEY_WHEEL_DELTA;
102 } else if (mousekey_wheel_repeat >= mk_wheel_time_to_max) {
103 unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed;
104 } else {
105 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_wheel_repeat) / mk_wheel_time_to_max;
106 }
107 return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit));
108}
109
110# else /* #ifndef MK_COMBINED */
111# ifndef MK_KINETIC_SPEED
112
113/*
114 * Kinetic movement acceleration algorithm
115 *
116 * current speed = I + A * T/50 + A * 0.5 * T^2 | maximum B
117 *
118 * T: time since the mouse movement started
119 * E: mouse events per second (set through MOUSEKEY_INTERVAL, UHK sends 250, the
120 * pro micro on my Signum 3.0 sends only 125!)
121 * I: initial speed at time 0
122 * A: acceleration
123 * B: base mouse travel speed
124 */
125const uint16_t mk_accelerated_speed = MOUSEKEY_ACCELERATED_SPEED;
126const uint16_t mk_base_speed = MOUSEKEY_BASE_SPEED;
127const uint16_t mk_decelerated_speed = MOUSEKEY_DECELERATED_SPEED;
128const uint16_t mk_initial_speed = MOUSEKEY_INITIAL_SPEED;
129
130static uint8_t move_unit(void) {
131 float speed = mk_initial_speed;
132
133 if (mousekey_accel & ((1 << 0) | (1 << 2))) {
134 speed = mousekey_accel & (1 << 2) ? mk_accelerated_speed : mk_decelerated_speed;
135 } else if (mousekey_repeat && mouse_timer) {
136 const float time_elapsed = timer_elapsed(mouse_timer) / 50;
137 speed = mk_initial_speed + MOUSEKEY_MOVE_DELTA * time_elapsed + MOUSEKEY_MOVE_DELTA * 0.5 * time_elapsed * time_elapsed;
138
139 speed = speed > mk_base_speed ? mk_base_speed : speed;
140 }
141
142 /* convert speed to USB mouse speed 1 to 127 */
143 speed = (uint8_t)(speed / (1000.0f / mk_interval));
144 speed = speed < 1 ? 1 : speed;
145
146 return speed > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : speed;
147}
148
149float mk_wheel_interval = 1000.0f / MOUSEKEY_WHEEL_INITIAL_MOVEMENTS;
150
151static uint8_t wheel_unit(void) {
152 float speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS;
153
154 if (mousekey_accel & ((1 << 0) | (1 << 2))) {
155 speed = mousekey_accel & (1 << 2) ? MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS : MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS;
156 } else if (mousekey_repeat && mouse_timer) {
157 if (mk_wheel_interval != MOUSEKEY_WHEEL_BASE_MOVEMENTS) {
158 const float time_elapsed = timer_elapsed(mouse_timer) / 50;
159 speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS + 1 * time_elapsed + 1 * 0.5 * time_elapsed * time_elapsed;
160 }
161 speed = speed > MOUSEKEY_WHEEL_BASE_MOVEMENTS ? MOUSEKEY_WHEEL_BASE_MOVEMENTS : speed;
162 }
163
164 mk_wheel_interval = 1000.0f / speed;
165
166 return 1;
167}
168
169# else /* #ifndef MK_KINETIC_SPEED */
170
171static uint8_t move_unit(void) {
172 uint16_t unit;
173 if (mousekey_accel & (1 << 0)) {
174 unit = 1;
175 } else if (mousekey_accel & (1 << 1)) {
176 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2;
177 } else if (mousekey_accel & (1 << 2)) {
178 unit = MOUSEKEY_MOVE_MAX;
179 } else if (mousekey_repeat == 0) {
180 unit = MOUSEKEY_MOVE_DELTA;
181 } else if (mousekey_repeat >= mk_time_to_max) {
182 unit = MOUSEKEY_MOVE_DELTA * mk_max_speed;
183 } else {
184 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max;
185 }
186 return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit));
187}
188
189static uint8_t wheel_unit(void) {
190 uint16_t unit;
191 if (mousekey_accel & (1 << 0)) {
192 unit = 1;
193 } else if (mousekey_accel & (1 << 1)) {
194 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2;
195 } else if (mousekey_accel & (1 << 2)) {
196 unit = MOUSEKEY_WHEEL_MAX;
197 } else if (mousekey_repeat == 0) {
198 unit = MOUSEKEY_WHEEL_DELTA;
199 } else if (mousekey_repeat >= mk_wheel_time_to_max) {
200 unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed;
201 } else {
202 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max;
203 }
204 return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit));
205}
206
207# endif /* #ifndef MK_KINETIC_SPEED */
208# endif /* #ifndef MK_COMBINED */
209
210void mousekey_task(void) {
211 // report cursor and scroll movement independently
212 report_mouse_t const tmpmr = mouse_report;
213
214 mouse_report.x = 0;
215 mouse_report.y = 0;
216 mouse_report.v = 0;
217 mouse_report.h = 0;
218
219 if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > (mousekey_repeat ? mk_interval : mk_delay * 10)) {
220 if (mousekey_repeat != UINT8_MAX) mousekey_repeat++;
221 if (tmpmr.x != 0) mouse_report.x = move_unit() * ((tmpmr.x > 0) ? 1 : -1);
222 if (tmpmr.y != 0) mouse_report.y = move_unit() * ((tmpmr.y > 0) ? 1 : -1);
223
224 /* diagonal move [1/sqrt(2)] */
225 if (mouse_report.x && mouse_report.y) {
226 mouse_report.x = times_inv_sqrt2(mouse_report.x);
227 if (mouse_report.x == 0) {
228 mouse_report.x = 1;
229 }
230 mouse_report.y = times_inv_sqrt2(mouse_report.y);
231 if (mouse_report.y == 0) {
232 mouse_report.y = 1;
233 }
234 }
235 }
236 if ((tmpmr.v || tmpmr.h) && timer_elapsed(last_timer_w) > (mousekey_wheel_repeat ? mk_wheel_interval : mk_wheel_delay * 10)) {
237 if (mousekey_wheel_repeat != UINT8_MAX) mousekey_wheel_repeat++;
238 if (tmpmr.v != 0) mouse_report.v = wheel_unit() * ((tmpmr.v > 0) ? 1 : -1);
239 if (tmpmr.h != 0) mouse_report.h = wheel_unit() * ((tmpmr.h > 0) ? 1 : -1);
240
241 /* diagonal move [1/sqrt(2)] */
242 if (mouse_report.v && mouse_report.h) {
243 mouse_report.v = times_inv_sqrt2(mouse_report.v);
244 if (mouse_report.v == 0) {
245 mouse_report.v = 1;
246 }
247 mouse_report.h = times_inv_sqrt2(mouse_report.h);
248 if (mouse_report.h == 0) {
249 mouse_report.h = 1;
250 }
251 }
252 }
253
254 if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send();
255 mouse_report = tmpmr;
256}
257
258void mousekey_on(uint8_t code) {
259# ifdef MK_KINETIC_SPEED
260 if (mouse_timer == 0) {
261 mouse_timer = timer_read();
262 }
263# endif /* #ifdef MK_KINETIC_SPEED */
264
265 if (code == KC_MS_UP)
266 mouse_report.y = move_unit() * -1;
267 else if (code == KC_MS_DOWN)
268 mouse_report.y = move_unit();
269 else if (code == KC_MS_LEFT)
270 mouse_report.x = move_unit() * -1;
271 else if (code == KC_MS_RIGHT)
272 mouse_report.x = move_unit();
273 else if (code == KC_MS_WH_UP)
274 mouse_report.v = wheel_unit();
275 else if (code == KC_MS_WH_DOWN)
276 mouse_report.v = wheel_unit() * -1;
277 else if (code == KC_MS_WH_LEFT)
278 mouse_report.h = wheel_unit() * -1;
279 else if (code == KC_MS_WH_RIGHT)
280 mouse_report.h = wheel_unit();
281 else if (IS_MOUSEKEY_BUTTON(code))
282 mouse_report.buttons |= 1 << (code - KC_MS_BTN1);
283 else if (code == KC_MS_ACCEL0)
284 mousekey_accel |= (1 << 0);
285 else if (code == KC_MS_ACCEL1)
286 mousekey_accel |= (1 << 1);
287 else if (code == KC_MS_ACCEL2)
288 mousekey_accel |= (1 << 2);
289}
290
291void mousekey_off(uint8_t code) {
292 if (code == KC_MS_UP && mouse_report.y < 0)
293 mouse_report.y = 0;
294 else if (code == KC_MS_DOWN && mouse_report.y > 0)
295 mouse_report.y = 0;
296 else if (code == KC_MS_LEFT && mouse_report.x < 0)
297 mouse_report.x = 0;
298 else if (code == KC_MS_RIGHT && mouse_report.x > 0)
299 mouse_report.x = 0;
300 else if (code == KC_MS_WH_UP && mouse_report.v > 0)
301 mouse_report.v = 0;
302 else if (code == KC_MS_WH_DOWN && mouse_report.v < 0)
303 mouse_report.v = 0;
304 else if (code == KC_MS_WH_LEFT && mouse_report.h < 0)
305 mouse_report.h = 0;
306 else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0)
307 mouse_report.h = 0;
308 else if (IS_MOUSEKEY_BUTTON(code))
309 mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1));
310 else if (code == KC_MS_ACCEL0)
311 mousekey_accel &= ~(1 << 0);
312 else if (code == KC_MS_ACCEL1)
313 mousekey_accel &= ~(1 << 1);
314 else if (code == KC_MS_ACCEL2)
315 mousekey_accel &= ~(1 << 2);
316 if (mouse_report.x == 0 && mouse_report.y == 0) {
317 mousekey_repeat = 0;
318# ifdef MK_KINETIC_SPEED
319 mouse_timer = 0;
320# endif /* #ifdef MK_KINETIC_SPEED */
321 }
322 if (mouse_report.v == 0 && mouse_report.h == 0) mousekey_wheel_repeat = 0;
323}
324
325#else /* #ifndef MK_3_SPEED */
326
327enum { mkspd_unmod, mkspd_0, mkspd_1, mkspd_2, mkspd_COUNT };
328# ifndef MK_MOMENTARY_ACCEL
329static uint8_t mk_speed = mkspd_1;
330# else
331static uint8_t mk_speed = mkspd_unmod;
332static uint8_t mkspd_DEFAULT = mkspd_unmod;
333# endif
334static uint16_t last_timer_c = 0;
335static uint16_t last_timer_w = 0;
336uint16_t c_offsets[mkspd_COUNT] = {MK_C_OFFSET_UNMOD, MK_C_OFFSET_0, MK_C_OFFSET_1, MK_C_OFFSET_2};
337uint16_t c_intervals[mkspd_COUNT] = {MK_C_INTERVAL_UNMOD, MK_C_INTERVAL_0, MK_C_INTERVAL_1, MK_C_INTERVAL_2};
338uint16_t w_offsets[mkspd_COUNT] = {MK_W_OFFSET_UNMOD, MK_W_OFFSET_0, MK_W_OFFSET_1, MK_W_OFFSET_2};
339uint16_t w_intervals[mkspd_COUNT] = {MK_W_INTERVAL_UNMOD, MK_W_INTERVAL_0, MK_W_INTERVAL_1, MK_W_INTERVAL_2};
340
341void mousekey_task(void) {
342 // report cursor and scroll movement independently
343 report_mouse_t const tmpmr = mouse_report;
344 mouse_report.x = 0;
345 mouse_report.y = 0;
346 mouse_report.v = 0;
347 mouse_report.h = 0;
348
349 if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > c_intervals[mk_speed]) {
350 mouse_report.x = tmpmr.x;
351 mouse_report.y = tmpmr.y;
352 }
353 if ((tmpmr.h || tmpmr.v) && timer_elapsed(last_timer_w) > w_intervals[mk_speed]) {
354 mouse_report.v = tmpmr.v;
355 mouse_report.h = tmpmr.h;
356 }
357
358 if (mouse_report.x || mouse_report.y || mouse_report.v || mouse_report.h) mousekey_send();
359 mouse_report = tmpmr;
360}
361
362void adjust_speed(void) {
363 uint16_t const c_offset = c_offsets[mk_speed];
364 uint16_t const w_offset = w_offsets[mk_speed];
365 if (mouse_report.x > 0) mouse_report.x = c_offset;
366 if (mouse_report.x < 0) mouse_report.x = c_offset * -1;
367 if (mouse_report.y > 0) mouse_report.y = c_offset;
368 if (mouse_report.y < 0) mouse_report.y = c_offset * -1;
369 if (mouse_report.h > 0) mouse_report.h = w_offset;
370 if (mouse_report.h < 0) mouse_report.h = w_offset * -1;
371 if (mouse_report.v > 0) mouse_report.v = w_offset;
372 if (mouse_report.v < 0) mouse_report.v = w_offset * -1;
373 // adjust for diagonals
374 if (mouse_report.x && mouse_report.y) {
375 mouse_report.x = times_inv_sqrt2(mouse_report.x);
376 if (mouse_report.x == 0) {
377 mouse_report.x = 1;
378 }
379 mouse_report.y = times_inv_sqrt2(mouse_report.y);
380 if (mouse_report.y == 0) {
381 mouse_report.y = 1;
382 }
383 }
384 if (mouse_report.h && mouse_report.v) {
385 mouse_report.h = times_inv_sqrt2(mouse_report.h);
386 mouse_report.v = times_inv_sqrt2(mouse_report.v);
387 }
388}
389
390void mousekey_on(uint8_t code) {
391 uint16_t const c_offset = c_offsets[mk_speed];
392 uint16_t const w_offset = w_offsets[mk_speed];
393 uint8_t const old_speed = mk_speed;
394 if (code == KC_MS_UP)
395 mouse_report.y = c_offset * -1;
396 else if (code == KC_MS_DOWN)
397 mouse_report.y = c_offset;
398 else if (code == KC_MS_LEFT)
399 mouse_report.x = c_offset * -1;
400 else if (code == KC_MS_RIGHT)
401 mouse_report.x = c_offset;
402 else if (code == KC_MS_WH_UP)
403 mouse_report.v = w_offset;
404 else if (code == KC_MS_WH_DOWN)
405 mouse_report.v = w_offset * -1;
406 else if (code == KC_MS_WH_LEFT)
407 mouse_report.h = w_offset * -1;
408 else if (code == KC_MS_WH_RIGHT)
409 mouse_report.h = w_offset;
410 else if (IS_MOUSEKEY_BUTTON(code))
411 mouse_report.buttons |= 1 << (code - KC_MS_BTN1);
412 else if (code == KC_MS_ACCEL0)
413 mk_speed = mkspd_0;
414 else if (code == KC_MS_ACCEL1)
415 mk_speed = mkspd_1;
416 else if (code == KC_MS_ACCEL2)
417 mk_speed = mkspd_2;
418 if (mk_speed != old_speed) adjust_speed();
419}
420
421void mousekey_off(uint8_t code) {
422# ifdef MK_MOMENTARY_ACCEL
423 uint8_t const old_speed = mk_speed;
424# endif
425 if (code == KC_MS_UP && mouse_report.y < 0)
426 mouse_report.y = 0;
427 else if (code == KC_MS_DOWN && mouse_report.y > 0)
428 mouse_report.y = 0;
429 else if (code == KC_MS_LEFT && mouse_report.x < 0)
430 mouse_report.x = 0;
431 else if (code == KC_MS_RIGHT && mouse_report.x > 0)
432 mouse_report.x = 0;
433 else if (code == KC_MS_WH_UP && mouse_report.v > 0)
434 mouse_report.v = 0;
435 else if (code == KC_MS_WH_DOWN && mouse_report.v < 0)
436 mouse_report.v = 0;
437 else if (code == KC_MS_WH_LEFT && mouse_report.h < 0)
438 mouse_report.h = 0;
439 else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0)
440 mouse_report.h = 0;
441 else if (IS_MOUSEKEY_BUTTON(code))
442 mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1));
443# ifdef MK_MOMENTARY_ACCEL
444 else if (code == KC_MS_ACCEL0)
445 mk_speed = mkspd_DEFAULT;
446 else if (code == KC_MS_ACCEL1)
447 mk_speed = mkspd_DEFAULT;
448 else if (code == KC_MS_ACCEL2)
449 mk_speed = mkspd_DEFAULT;
450 if (mk_speed != old_speed) adjust_speed();
451# endif
452}
453
454#endif /* #ifndef MK_3_SPEED */
455
456void mousekey_send(void) {
457 mousekey_debug();
458 uint16_t time = timer_read();
459 if (mouse_report.x || mouse_report.y) last_timer_c = time;
460 if (mouse_report.v || mouse_report.h) last_timer_w = time;
461 host_mouse_send(&mouse_report);
462}
463
464void mousekey_clear(void) {
465 mouse_report = (report_mouse_t){};
466 mousekey_repeat = 0;
467 mousekey_wheel_repeat = 0;
468 mousekey_accel = 0;
469}
470
471static void mousekey_debug(void) {
472 if (!debug_mouse) return;
473 print("mousekey [btn|x y v h](rep/acl): [");
474 print_hex8(mouse_report.buttons);
475 print("|");
476 print_decs(mouse_report.x);
477 print(" ");
478 print_decs(mouse_report.y);
479 print(" ");
480 print_decs(mouse_report.v);
481 print(" ");
482 print_decs(mouse_report.h);
483 print("](");
484 print_dec(mousekey_repeat);
485 print("/");
486 print_dec(mousekey_accel);
487 print(")\n");
488}
diff --git a/quantum/mousekey.h b/quantum/mousekey.h
new file mode 100644
index 000000000..70dc4bb5c
--- /dev/null
+++ b/quantum/mousekey.h
@@ -0,0 +1,179 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdint.h>
21#include "host.h"
22
23#ifndef MK_3_SPEED
24
25/* max value on report descriptor */
26# ifndef MOUSEKEY_MOVE_MAX
27# define MOUSEKEY_MOVE_MAX 127
28# elif MOUSEKEY_MOVE_MAX > 127
29# error MOUSEKEY_MOVE_MAX needs to be smaller than 127
30# endif
31
32# ifndef MOUSEKEY_WHEEL_MAX
33# define MOUSEKEY_WHEEL_MAX 127
34# elif MOUSEKEY_WHEEL_MAX > 127
35# error MOUSEKEY_WHEEL_MAX needs to be smaller than 127
36# endif
37
38# ifndef MOUSEKEY_MOVE_DELTA
39# ifndef MK_KINETIC_SPEED
40# define MOUSEKEY_MOVE_DELTA 5
41# else
42# define MOUSEKEY_MOVE_DELTA 25
43# endif
44# endif
45# ifndef MOUSEKEY_WHEEL_DELTA
46# define MOUSEKEY_WHEEL_DELTA 1
47# endif
48# ifndef MOUSEKEY_DELAY
49# ifndef MK_KINETIC_SPEED
50# define MOUSEKEY_DELAY 300
51# else
52# define MOUSEKEY_DELAY 8
53# endif
54# endif
55# ifndef MOUSEKEY_INTERVAL
56# ifndef MK_KINETIC_SPEED
57# define MOUSEKEY_INTERVAL 50
58# else
59# define MOUSEKEY_INTERVAL 8
60# endif
61# endif
62# ifndef MOUSEKEY_MAX_SPEED
63# define MOUSEKEY_MAX_SPEED 10
64# endif
65# ifndef MOUSEKEY_TIME_TO_MAX
66# define MOUSEKEY_TIME_TO_MAX 20
67# endif
68# ifndef MOUSEKEY_WHEEL_DELAY
69# define MOUSEKEY_WHEEL_DELAY 300
70# endif
71# ifndef MOUSEKEY_WHEEL_INTERVAL
72# define MOUSEKEY_WHEEL_INTERVAL 100
73# endif
74# ifndef MOUSEKEY_WHEEL_MAX_SPEED
75# define MOUSEKEY_WHEEL_MAX_SPEED 8
76# endif
77# ifndef MOUSEKEY_WHEEL_TIME_TO_MAX
78# define MOUSEKEY_WHEEL_TIME_TO_MAX 40
79# endif
80
81# ifndef MOUSEKEY_INITIAL_SPEED
82# define MOUSEKEY_INITIAL_SPEED 100
83# endif
84# ifndef MOUSEKEY_BASE_SPEED
85# define MOUSEKEY_BASE_SPEED 1000
86# endif
87# ifndef MOUSEKEY_DECELERATED_SPEED
88# define MOUSEKEY_DECELERATED_SPEED 400
89# endif
90# ifndef MOUSEKEY_ACCELERATED_SPEED
91# define MOUSEKEY_ACCELERATED_SPEED 3000
92# endif
93# ifndef MOUSEKEY_WHEEL_INITIAL_MOVEMENTS
94# define MOUSEKEY_WHEEL_INITIAL_MOVEMENTS 16
95# endif
96# ifndef MOUSEKEY_WHEEL_BASE_MOVEMENTS
97# define MOUSEKEY_WHEEL_BASE_MOVEMENTS 32
98# endif
99# ifndef MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS
100# define MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS 48
101# endif
102# ifndef MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS
103# define MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS 8
104# endif
105
106#else /* #ifndef MK_3_SPEED */
107
108# ifndef MK_C_OFFSET_UNMOD
109# define MK_C_OFFSET_UNMOD 16
110# endif
111# ifndef MK_C_INTERVAL_UNMOD
112# define MK_C_INTERVAL_UNMOD 16
113# endif
114# ifndef MK_C_OFFSET_0
115# define MK_C_OFFSET_0 1
116# endif
117# ifndef MK_C_INTERVAL_0
118# define MK_C_INTERVAL_0 32
119# endif
120# ifndef MK_C_OFFSET_1
121# define MK_C_OFFSET_1 4
122# endif
123# ifndef MK_C_INTERVAL_1
124# define MK_C_INTERVAL_1 16
125# endif
126# ifndef MK_C_OFFSET_2
127# define MK_C_OFFSET_2 32
128# endif
129# ifndef MK_C_INTERVAL_2
130# define MK_C_INTERVAL_2 16
131# endif
132
133# ifndef MK_W_OFFSET_UNMOD
134# define MK_W_OFFSET_UNMOD 1
135# endif
136# ifndef MK_W_INTERVAL_UNMOD
137# define MK_W_INTERVAL_UNMOD 40
138# endif
139# ifndef MK_W_OFFSET_0
140# define MK_W_OFFSET_0 1
141# endif
142# ifndef MK_W_INTERVAL_0
143# define MK_W_INTERVAL_0 360
144# endif
145# ifndef MK_W_OFFSET_1
146# define MK_W_OFFSET_1 1
147# endif
148# ifndef MK_W_INTERVAL_1
149# define MK_W_INTERVAL_1 120
150# endif
151# ifndef MK_W_OFFSET_2
152# define MK_W_OFFSET_2 1
153# endif
154# ifndef MK_W_INTERVAL_2
155# define MK_W_INTERVAL_2 20
156# endif
157
158#endif /* #ifndef MK_3_SPEED */
159
160#ifdef __cplusplus
161extern "C" {
162#endif
163
164extern uint8_t mk_delay;
165extern uint8_t mk_interval;
166extern uint8_t mk_max_speed;
167extern uint8_t mk_time_to_max;
168extern uint8_t mk_wheel_max_speed;
169extern uint8_t mk_wheel_time_to_max;
170
171void mousekey_task(void);
172void mousekey_on(uint8_t code);
173void mousekey_off(uint8_t code);
174void mousekey_clear(void);
175void mousekey_send(void);
176
177#ifdef __cplusplus
178}
179#endif
diff --git a/quantum/quantum.c b/quantum/quantum.c
index cf16e953a..6d202c515 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -25,10 +25,6 @@
25# include "backlight.h" 25# include "backlight.h"
26#endif 26#endif
27 27
28#ifdef FAUXCLICKY_ENABLE
29# include "fauxclicky.h"
30#endif
31
32#ifdef API_ENABLE 28#ifdef API_ENABLE
33# include "api.h" 29# include "api.h"
34#endif 30#endif
@@ -310,17 +306,6 @@ bool process_record_quantum(keyrecord_t *record) {
310 case EEPROM_RESET: 306 case EEPROM_RESET:
311 eeconfig_init(); 307 eeconfig_init();
312 return false; 308 return false;
313#ifdef FAUXCLICKY_ENABLE
314 case FC_TOG:
315 FAUXCLICKY_TOGGLE;
316 return false;
317 case FC_ON:
318 FAUXCLICKY_ON;
319 return false;
320 case FC_OFF:
321 FAUXCLICKY_OFF;
322 return false;
323#endif
324#ifdef VELOCIKEY_ENABLE 309#ifdef VELOCIKEY_ENABLE
325 case VLK_TOG: 310 case VLK_TOG:
326 velocikey_toggle(); 311 velocikey_toggle();
@@ -391,6 +376,29 @@ __attribute__((weak)) const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
391 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), 376 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
392}; 377};
393 378
379/* Bit-Packed look-up table to convert an ASCII character to whether
380 * [Space] needs to be sent after the keycode
381 */
382__attribute__((weak)) const uint8_t ascii_to_dead_lut[16] PROGMEM = {
383 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
384 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
385 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
386 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
387
388 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
389 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
390 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
391 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
392 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
393 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
394 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
395 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
396 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
397 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
398 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
399 KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
400};
401
394/* Look-up table to convert an ASCII character to a keycode. 402/* Look-up table to convert an ASCII character to a keycode.
395 */ 403 */
396__attribute__((weak)) const uint8_t ascii_to_keycode_lut[128] PROGMEM = { 404__attribute__((weak)) const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
@@ -531,6 +539,7 @@ void send_char(char ascii_code) {
531 uint8_t keycode = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]); 539 uint8_t keycode = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]);
532 bool is_shifted = PGM_LOADBIT(ascii_to_shift_lut, (uint8_t)ascii_code); 540 bool is_shifted = PGM_LOADBIT(ascii_to_shift_lut, (uint8_t)ascii_code);
533 bool is_altgred = PGM_LOADBIT(ascii_to_altgr_lut, (uint8_t)ascii_code); 541 bool is_altgred = PGM_LOADBIT(ascii_to_altgr_lut, (uint8_t)ascii_code);
542 bool is_dead = PGM_LOADBIT(ascii_to_dead_lut, (uint8_t)ascii_code);
534 543
535 if (is_shifted) { 544 if (is_shifted) {
536 register_code(KC_LSFT); 545 register_code(KC_LSFT);
@@ -545,6 +554,9 @@ void send_char(char ascii_code) {
545 if (is_shifted) { 554 if (is_shifted) {
546 unregister_code(KC_LSFT); 555 unregister_code(KC_LSFT);
547 } 556 }
557 if (is_dead) {
558 tap_code(KC_SPACE);
559 }
548} 560}
549 561
550void set_single_persistent_default_layer(uint8_t default_layer) { 562void set_single_persistent_default_layer(uint8_t default_layer) {
@@ -629,6 +641,26 @@ void matrix_init_quantum() {
629} 641}
630 642
631void matrix_scan_quantum() { 643void matrix_scan_quantum() {
644#if defined(AUDIO_ENABLE)
645 // There are some tasks that need to be run a little bit
646 // after keyboard startup, or else they will not work correctly
647 // because of interaction with the USB device state, which
648 // may still be in flux...
649 //
650 // At the moment the only feature that needs this is the
651 // startup song.
652 static bool delayed_tasks_run = false;
653 static uint16_t delayed_task_timer = 0;
654 if (!delayed_tasks_run) {
655 if (!delayed_task_timer) {
656 delayed_task_timer = timer_read();
657 } else if (timer_elapsed(delayed_task_timer) > 300) {
658 audio_startup();
659 delayed_tasks_run = true;
660 }
661 }
662#endif
663
632#if defined(AUDIO_ENABLE) && !defined(NO_MUSIC_MODE) 664#if defined(AUDIO_ENABLE) && !defined(NO_MUSIC_MODE)
633 matrix_scan_music(); 665 matrix_scan_music();
634#endif 666#endif
diff --git a/quantum/quantum.h b/quantum/quantum.h
index dd2a6dd53..36a983d57 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -53,6 +53,7 @@
53#include "eeconfig.h" 53#include "eeconfig.h"
54#include "bootloader.h" 54#include "bootloader.h"
55#include "timer.h" 55#include "timer.h"
56#include "sync_timer.h"
56#include "config_common.h" 57#include "config_common.h"
57#include "gpio.h" 58#include "gpio.h"
58#include "atomic_util.h" 59#include "atomic_util.h"
@@ -194,6 +195,42 @@ extern layer_state_t layer_state;
194# include "wpm.h" 195# include "wpm.h"
195#endif 196#endif
196 197
198#ifdef USBPD_ENABLE
199# include "usbpd.h"
200#endif
201
202// Function substitutions to ease GPIO manipulation
203#if defined(__AVR__)
204
205/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal.
206 * But here's more margin to make it two clocks. */
207# if !defined(GPIO_INPUT_PIN_DELAY)
208# define GPIO_INPUT_PIN_DELAY 2
209# endif
210# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
211
212#elif defined(__ARMEL__) || defined(__ARMEB__)
213
214/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
215 * to which the GPIO is connected.
216 * The connected buses differ depending on the various series of MCUs.
217 * And since the instruction execution clock of the CPU and the bus clock of GPIO are different,
218 * there is a delay of several clocks to read the change of the input signal.
219 *
220 * Define this delay with the GPIO_INPUT_PIN_DELAY macro.
221 * If the GPIO_INPUT_PIN_DELAY macro is not defined, the following default values will be used.
222 * (A fairly large value of 0.25 microseconds is set.)
223 */
224# if !defined(GPIO_INPUT_PIN_DELAY)
225# if defined(STM32_SYSCLK)
226# define GPIO_INPUT_PIN_DELAY (STM32_SYSCLK / 1000000L / 4)
227# elif defined(KINETIS_SYSCLK_FREQUENCY)
228# define GPIO_INPUT_PIN_DELAY (KINETIS_SYSCLK_FREQUENCY / 1000000L / 4)
229# endif
230# endif
231# define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
232
233#endif
197#define SEND_STRING(string) send_string_P(PSTR(string)) 234#define SEND_STRING(string) send_string_P(PSTR(string))
198#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval) 235#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval)
199 236
@@ -201,6 +238,7 @@ extern layer_state_t layer_state;
201extern const uint8_t ascii_to_keycode_lut[128]; 238extern const uint8_t ascii_to_keycode_lut[128];
202extern const uint8_t ascii_to_shift_lut[16]; 239extern const uint8_t ascii_to_shift_lut[16];
203extern const uint8_t ascii_to_altgr_lut[16]; 240extern const uint8_t ascii_to_altgr_lut[16];
241extern const uint8_t ascii_to_dead_lut[16];
204// clang-format off 242// clang-format off
205#define KCLUT_ENTRY(a, b, c, d, e, f, g, h) \ 243#define KCLUT_ENTRY(a, b, c, d, e, f, g, h) \
206 ( ((a) ? 1 : 0) << 0 \ 244 ( ((a) ? 1 : 0) << 0 \
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index 0160c5586..e0f5dbc61 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -150,13 +150,6 @@ enum quantum_keycodes {
150 CLICKY_DOWN, 150 CLICKY_DOWN,
151 CLICKY_RESET, 151 CLICKY_RESET,
152 152
153#ifdef FAUXCLICKY_ENABLE
154 // Faux clicky
155 FC_ON,
156 FC_OFF,
157 FC_TOG,
158#endif
159
160 // Music mode on/off/toggle 153 // Music mode on/off/toggle
161 MU_ON, 154 MU_ON,
162 MU_OFF, 155 MU_OFF,
@@ -717,6 +710,9 @@ enum quantum_keycodes {
717#define CK_DOWN CLICKY_DOWN 710#define CK_DOWN CLICKY_DOWN
718#define CK_ON CLICKY_ENABLE 711#define CK_ON CLICKY_ENABLE
719#define CK_OFF CLICKY_DISABLE 712#define CK_OFF CLICKY_DISABLE
713#define FC_ON CLICKY_ENABLE
714#define FC_OFF CLICKY_DISABLE
715#define FC_TOGG CLICKY_TOGGLE
720 716
721#define RGB_MOD RGB_MODE_FORWARD 717#define RGB_MOD RGB_MODE_FORWARD
722#define RGB_RMOD RGB_MODE_REVERSE 718#define RGB_RMOD RGB_MODE_REVERSE
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
index 04af3ae9e..a945df68e 100644
--- a/quantum/rgb_matrix.c
+++ b/quantum/rgb_matrix.c
@@ -266,9 +266,9 @@ static bool rgb_matrix_none(effect_params_t *params) {
266 266
267static void rgb_task_timers(void) { 267static void rgb_task_timers(void) {
268#if defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0 268#if defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
269 uint32_t deltaTime = timer_elapsed32(rgb_timer_buffer); 269 uint32_t deltaTime = sync_timer_elapsed32(rgb_timer_buffer);
270#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0 270#endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
271 rgb_timer_buffer = timer_read32(); 271 rgb_timer_buffer = sync_timer_read32();
272 272
273 // Update double buffer timers 273 // Update double buffer timers
274#if RGB_DISABLE_TIMEOUT > 0 274#if RGB_DISABLE_TIMEOUT > 0
@@ -296,7 +296,7 @@ static void rgb_task_timers(void) {
296 296
297static void rgb_task_sync(void) { 297static void rgb_task_sync(void) {
298 // next task 298 // next task
299 if (timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING; 299 if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
300} 300}
301 301
302static void rgb_task_start(void) { 302static void rgb_task_start(void) {
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index ac4ff9bfd..7d7d015ba 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -29,7 +29,7 @@
29#endif 29#endif
30#include "wait.h" 30#include "wait.h"
31#include "progmem.h" 31#include "progmem.h"
32#include "timer.h" 32#include "sync_timer.h"
33#include "rgblight.h" 33#include "rgblight.h"
34#include "color.h" 34#include "color.h"
35#include "debug.h" 35#include "debug.h"
@@ -42,6 +42,9 @@
42#ifndef MIN 42#ifndef MIN
43# define MIN(a, b) (((a) < (b)) ? (a) : (b)) 43# define MIN(a, b) (((a) < (b)) ? (a) : (b))
44#endif 44#endif
45#ifndef MAX
46# define MAX(a, b) (((a) > (b)) ? (a) : (b))
47#endif
45 48
46#ifdef RGBLIGHT_SPLIT 49#ifdef RGBLIGHT_SPLIT
47/* for split keyboard */ 50/* for split keyboard */
@@ -700,18 +703,16 @@ static void rgblight_layers_write(void) {
700 703
701# ifdef RGBLIGHT_LAYER_BLINK 704# ifdef RGBLIGHT_LAYER_BLINK
702rgblight_layer_mask_t _blinked_layer_mask = 0; 705rgblight_layer_mask_t _blinked_layer_mask = 0;
703uint16_t _blink_duration = 0;
704static uint16_t _blink_timer; 706static uint16_t _blink_timer;
705 707
706void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { 708void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
707 rgblight_set_layer_state(layer, true); 709 rgblight_set_layer_state(layer, true);
708 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer; 710 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer;
709 _blink_timer = timer_read(); 711 _blink_timer = sync_timer_read() + duration_ms;
710 _blink_duration = duration_ms;
711} 712}
712 713
713void rgblight_unblink_layers(void) { 714void rgblight_unblink_layers(void) {
714 if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) { 715 if (_blinked_layer_mask != 0 && timer_expired(sync_timer_read(), _blink_timer)) {
715 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { 716 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
716 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) { 717 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) {
717 rgblight_set_layer_state(layer, false); 718 rgblight_set_layer_state(layer, false);
@@ -886,7 +887,7 @@ void rgblight_timer_enable(void) {
886 if (!is_static_effect(rgblight_config.mode)) { 887 if (!is_static_effect(rgblight_config.mode)) {
887 rgblight_status.timer_enabled = true; 888 rgblight_status.timer_enabled = true;
888 } 889 }
889 animation_status.last_timer = timer_read(); 890 animation_status.last_timer = sync_timer_read();
890 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; 891 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
891 dprintf("rgblight timer enabled.\n"); 892 dprintf("rgblight timer enabled.\n");
892} 893}
@@ -989,24 +990,25 @@ void rgblight_task(void) {
989# endif 990# endif
990# ifdef RGBLIGHT_EFFECT_TWINKLE 991# ifdef RGBLIGHT_EFFECT_TWINKLE
991 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { 992 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) {
992 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); 993 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30);
993 effect_func = (effect_func_t)rgblight_effect_twinkle; 994 effect_func = (effect_func_t)rgblight_effect_twinkle;
994 } 995 }
995# endif 996# endif
996 if (animation_status.restart) { 997 if (animation_status.restart) {
997 animation_status.restart = false; 998 animation_status.restart = false;
998 animation_status.last_timer = timer_read() - interval_time - 1; 999 animation_status.last_timer = sync_timer_read();
999 animation_status.pos16 = 0; // restart signal to local each effect 1000 animation_status.pos16 = 0; // restart signal to local each effect
1000 } 1001 }
1001 if (timer_elapsed(animation_status.last_timer) >= interval_time) { 1002 uint16_t now = sync_timer_read();
1003 if (timer_expired(now, animation_status.last_timer)) {
1002# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1004# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1003 static uint16_t report_last_timer = 0; 1005 static uint16_t report_last_timer = 0;
1004 static bool tick_flag = false; 1006 static bool tick_flag = false;
1005 uint16_t oldpos16; 1007 uint16_t oldpos16;
1006 if (tick_flag) { 1008 if (tick_flag) {
1007 tick_flag = false; 1009 tick_flag = false;
1008 if (timer_elapsed(report_last_timer) >= 30000) { 1010 if (timer_expired(now, report_last_timer)) {
1009 report_last_timer = timer_read(); 1011 report_last_timer += 30000;
1010 dprintf("rgblight animation tick report to slave\n"); 1012 dprintf("rgblight animation tick report to slave\n");
1011 RGBLIGHT_SPLIT_ANIMATION_TICK; 1013 RGBLIGHT_SPLIT_ANIMATION_TICK;
1012 } 1014 }
@@ -1030,8 +1032,7 @@ void rgblight_task(void) {
1030 1032
1031#endif /* RGBLIGHT_USE_TIMER */ 1033#endif /* RGBLIGHT_USE_TIMER */
1032 1034
1033// Effects 1035#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE)
1034#ifdef RGBLIGHT_EFFECT_BREATHING
1035 1036
1036# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER 1037# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
1037# ifndef RGBLIGHT_BREATHE_TABLE_SIZE 1038# ifndef RGBLIGHT_BREATHE_TABLE_SIZE
@@ -1040,17 +1041,24 @@ void rgblight_task(void) {
1040# include <rgblight_breathe_table.h> 1041# include <rgblight_breathe_table.h>
1041# endif 1042# endif
1042 1043
1043__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; 1044static uint8_t breathe_calc(uint8_t pos) {
1044
1045void rgblight_effect_breathing(animation_status_t *anim) {
1046 float val;
1047
1048 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ 1045 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
1049# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE 1046# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
1050 val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]); 1047 return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]);
1051# else 1048# else
1052 val = (exp(sin((anim->pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); 1049 return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
1053# endif 1050# endif
1051}
1052
1053#endif
1054
1055// Effects
1056#ifdef RGBLIGHT_EFFECT_BREATHING
1057
1058__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
1059
1060void rgblight_effect_breathing(animation_status_t *anim) {
1061 uint8_t val = breathe_calc(anim->pos);
1054 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); 1062 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
1055 anim->pos = (anim->pos + 1); 1063 anim->pos = (anim->pos + 1);
1056} 1064}
@@ -1302,48 +1310,54 @@ void rgblight_effect_alternating(animation_status_t *anim) {
1302#endif 1310#endif
1303 1311
1304#ifdef RGBLIGHT_EFFECT_TWINKLE 1312#ifdef RGBLIGHT_EFFECT_TWINKLE
1305__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; 1313__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5};
1306 1314
1307typedef struct PACKED { 1315typedef struct PACKED {
1308 HSV hsv; 1316 HSV hsv;
1309 uint8_t life; 1317 uint8_t life;
1310 bool up; 1318 uint8_t max_life;
1311} TwinkleState; 1319} TwinkleState;
1312 1320
1313static TwinkleState led_twinkle_state[RGBLED_NUM]; 1321static TwinkleState led_twinkle_state[RGBLED_NUM];
1314 1322
1315void rgblight_effect_twinkle(animation_status_t *anim) { 1323void rgblight_effect_twinkle(animation_status_t *anim) {
1316 bool random_color = anim->delta / 3; 1324 const bool random_color = anim->delta / 3;
1317 bool restart = anim->pos == 0; 1325 const bool restart = anim->pos == 0;
1318 anim->pos = 1; 1326 anim->pos = 1;
1327
1328 const uint8_t bottom = breathe_calc(0);
1329 const uint8_t top = breathe_calc(127);
1330
1331 uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; }
1332 uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; }
1319 1333
1320 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1334 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1321 TwinkleState *t = &(led_twinkle_state[i]); 1335 TwinkleState *t = &(led_twinkle_state[i]);
1322 HSV * c = &(t->hsv); 1336 HSV * c = &(t->hsv);
1337
1338 if (!random_color) {
1339 c->h = rgblight_config.hue;
1340 c->s = rgblight_config.sat;
1341 }
1342
1323 if (restart) { 1343 if (restart) {
1324 // Restart 1344 // Restart
1325 t->life = 0; 1345 t->life = 0;
1326 t->hsv.v = 0; 1346 c->v = 0;
1327 } else if (t->life) { 1347 } else if (t->life) {
1328 // This LED is already on, either brightening or dimming 1348 // This LED is already on, either brightening or dimming
1329 t->life--; 1349 t->life--;
1330 uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; 1350 uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom);
1331 c->v = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; 1351 c->v = scale(rgblight_config.val, unscaled);
1332 if (t->life == 0 && t->up) { 1352 } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) {
1333 t->up = false;
1334 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE;
1335 }
1336 if (!random_color) {
1337 c->h = rgblight_config.hue;
1338 c->s = rgblight_config.sat;
1339 }
1340 } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) {
1341 // This LED is off, but was randomly selected to start brightening 1353 // This LED is off, but was randomly selected to start brightening
1342 c->h = random_color ? rand() % 0xFF : rgblight_config.hue; 1354 if (random_color) {
1343 c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; 1355 c->h = rand() % 0xFF;
1344 c->v = 0; 1356 c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2);
1345 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; 1357 }
1346 t->up = true; 1358 c->v = 0;
1359 t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val));
1360 t->life = t->max_life;
1347 } else { 1361 } else {
1348 // This LED is off, and was NOT selected to start brightening 1362 // This LED is off, and was NOT selected to start brightening
1349 } 1363 }
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index 1854fee99..028b3ea41 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -150,7 +150,7 @@ enum RGBLIGHT_EFFECT_MODE {
150# endif 150# endif
151 151
152# ifndef RGBLIGHT_EFFECT_TWINKLE_LIFE 152# ifndef RGBLIGHT_EFFECT_TWINKLE_LIFE
153# define RGBLIGHT_EFFECT_TWINKLE_LIFE 75 153# define RGBLIGHT_EFFECT_TWINKLE_LIFE 200
154# endif 154# endif
155 155
156# ifndef RGBLIGHT_EFFECT_TWINKLE_PROBABILITY 156# ifndef RGBLIGHT_EFFECT_TWINKLE_PROBABILITY
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 51bf8b109..bad762b49 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -114,9 +114,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
114 // Start with a clear matrix row 114 // Start with a clear matrix row
115 matrix_row_t current_row_value = 0; 115 matrix_row_t current_row_value = 0;
116 116
117 // Select row and wait for row selecton to stabilize 117 // Select row
118 select_row(current_row); 118 select_row(current_row);
119 matrix_io_delay(); 119 matrix_output_select_delay();
120 120
121 // For each col... 121 // For each col...
122 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 122 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
@@ -129,6 +129,9 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
129 129
130 // Unselect row 130 // Unselect row
131 unselect_row(current_row); 131 unselect_row(current_row);
132 if (current_row + 1 < MATRIX_ROWS) {
133 matrix_output_unselect_delay(); // wait for row signal to go HIGH
134 }
132 135
133 // If the row has changed, store the row and return the changed flag. 136 // If the row has changed, store the row and return the changed flag.
134 if (current_matrix[current_row] != current_row_value) { 137 if (current_matrix[current_row] != current_row_value) {
@@ -160,9 +163,9 @@ static void init_pins(void) {
160static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { 163static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
161 bool matrix_changed = false; 164 bool matrix_changed = false;
162 165
163 // Select col and wait for col selecton to stabilize 166 // Select col
164 select_col(current_col); 167 select_col(current_col);
165 matrix_io_delay(); 168 matrix_output_select_delay();
166 169
167 // For each row... 170 // For each row...
168 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) { 171 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
@@ -188,6 +191,9 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
188 191
189 // Unselect col 192 // Unselect col
190 unselect_col(current_col); 193 unselect_col(current_col);
194 if (current_col + 1 < MATRIX_COLS) {
195 matrix_output_unselect_delay(); // wait for col signal to go HIGH
196 }
191 197
192 return matrix_changed; 198 return matrix_changed;
193} 199}
@@ -245,21 +251,33 @@ void matrix_init(void) {
245 split_post_init(); 251 split_post_init();
246} 252}
247 253
248void matrix_post_scan(void) { 254bool matrix_post_scan(void) {
255 bool changed = false;
249 if (is_keyboard_master()) { 256 if (is_keyboard_master()) {
250 static uint8_t error_count; 257 static uint8_t error_count;
251 258
252 if (!transport_master(matrix + thatHand)) { 259 matrix_row_t slave_matrix[ROWS_PER_HAND] = {0};
260 if (!transport_master(slave_matrix)) {
253 error_count++; 261 error_count++;
254 262
255 if (error_count > ERROR_DISCONNECT_COUNT) { 263 if (error_count > ERROR_DISCONNECT_COUNT) {
256 // reset other half if disconnected 264 // reset other half if disconnected
257 for (int i = 0; i < ROWS_PER_HAND; ++i) { 265 for (int i = 0; i < ROWS_PER_HAND; ++i) {
258 matrix[thatHand + i] = 0; 266 matrix[thatHand + i] = 0;
267 slave_matrix[i] = 0;
259 } 268 }
269
270 changed = true;
260 } 271 }
261 } else { 272 } else {
262 error_count = 0; 273 error_count = 0;
274
275 for (int i = 0; i < ROWS_PER_HAND; ++i) {
276 if (matrix[thatHand + i] != slave_matrix[i]) {
277 matrix[thatHand + i] = slave_matrix[i];
278 changed = true;
279 }
280 }
263 } 281 }
264 282
265 matrix_scan_quantum(); 283 matrix_scan_quantum();
@@ -268,25 +286,27 @@ void matrix_post_scan(void) {
268 286
269 matrix_slave_scan_user(); 287 matrix_slave_scan_user();
270 } 288 }
289
290 return changed;
271} 291}
272 292
273uint8_t matrix_scan(void) { 293uint8_t matrix_scan(void) {
274 bool changed = false; 294 bool local_changed = false;
275 295
276#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW) 296#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
277 // Set row, read cols 297 // Set row, read cols
278 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) { 298 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
279 changed |= read_cols_on_row(raw_matrix, current_row); 299 local_changed |= read_cols_on_row(raw_matrix, current_row);
280 } 300 }
281#elif (DIODE_DIRECTION == ROW2COL) 301#elif (DIODE_DIRECTION == ROW2COL)
282 // Set col, read rows 302 // Set col, read rows
283 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 303 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
284 changed |= read_rows_on_col(raw_matrix, current_col); 304 local_changed |= read_rows_on_col(raw_matrix, current_col);
285 } 305 }
286#endif 306#endif
287 307
288 debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed); 308 debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, local_changed);
289 309
290 matrix_post_scan(); 310 bool remote_changed = matrix_post_scan();
291 return (uint8_t)changed; 311 return (uint8_t)(local_changed || remote_changed);
292} 312}
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index 467ff81a9..b45ba92c3 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -6,6 +6,7 @@
6#include "quantum.h" 6#include "quantum.h"
7 7
8#define ROWS_PER_HAND (MATRIX_ROWS / 2) 8#define ROWS_PER_HAND (MATRIX_ROWS / 2)
9#define SYNC_TIMER_OFFSET 2
9 10
10#ifdef RGBLIGHT_ENABLE 11#ifdef RGBLIGHT_ENABLE
11# include "rgblight.h" 12# include "rgblight.h"
@@ -27,8 +28,20 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
27# include "i2c_slave.h" 28# include "i2c_slave.h"
28 29
29typedef struct _I2C_slave_buffer_t { 30typedef struct _I2C_slave_buffer_t {
31# ifndef DISABLE_SYNC_TIMER
32 uint32_t sync_timer;
33# endif
30 matrix_row_t smatrix[ROWS_PER_HAND]; 34 matrix_row_t smatrix[ROWS_PER_HAND];
31 uint8_t backlight_level; 35# ifdef SPLIT_MODS_ENABLE
36 uint8_t real_mods;
37 uint8_t weak_mods;
38# ifndef NO_ACTION_ONESHOT
39 uint8_t oneshot_mods;
40# endif
41# endif
42# ifdef BACKLIGHT_ENABLE
43 uint8_t backlight_level;
44# endif
32# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) 45# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
33 rgblight_syncinfo_t rgblight_sync; 46 rgblight_syncinfo_t rgblight_sync;
34# endif 47# endif
@@ -42,9 +55,13 @@ typedef struct _I2C_slave_buffer_t {
42 55
43static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg; 56static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg;
44 57
58# define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer)
59# define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
60# define I2C_REAL_MODS_START offsetof(I2C_slave_buffer_t, real_mods)
61# define I2C_WEAK_MODS_START offsetof(I2C_slave_buffer_t, weak_mods)
62# define I2C_ONESHOT_MODS_START offsetof(I2C_slave_buffer_t, oneshot_mods)
45# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level) 63# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
46# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync) 64# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
47# define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
48# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state) 65# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
49# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm) 66# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)
50 67
@@ -91,10 +108,43 @@ bool transport_master(matrix_row_t matrix[]) {
91 } 108 }
92 } 109 }
93# endif 110# endif
111
112# ifdef SPLIT_MODS_ENABLE
113 uint8_t real_mods = get_mods();
114 if (real_mods != i2c_buffer->real_mods) {
115 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_REAL_MODS_START, (void *)&real_mods, sizeof(real_mods), TIMEOUT) >= 0) {
116 i2c_buffer->real_mods = real_mods;
117 }
118 }
119
120 uint8_t weak_mods = get_weak_mods();
121 if (weak_mods != i2c_buffer->weak_mods) {
122 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WEAK_MODS_START, (void *)&weak_mods, sizeof(weak_mods), TIMEOUT) >= 0) {
123 i2c_buffer->weak_mods = weak_mods;
124 }
125 }
126
127# ifndef NO_ACTION_ONESHOT
128 uint8_t oneshot_mods = get_oneshot_mods();
129 if (oneshot_mods != i2c_buffer->oneshot_mods) {
130 if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_ONESHOT_MODS_START, (void *)&oneshot_mods, sizeof(oneshot_mods), TIMEOUT) >= 0) {
131 i2c_buffer->oneshot_mods = oneshot_mods;
132 }
133 }
134# endif
135# endif
136
137# ifndef DISABLE_SYNC_TIMER
138 i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
139 i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT);
140# endif
94 return true; 141 return true;
95} 142}
96 143
97void transport_slave(matrix_row_t matrix[]) { 144void transport_slave(matrix_row_t matrix[]) {
145# ifndef DISABLE_SYNC_TIMER
146 sync_timer_update(i2c_buffer->sync_timer);
147# endif
98 // Copy matrix to I2C buffer 148 // Copy matrix to I2C buffer
99 memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix)); 149 memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
100 150
@@ -118,6 +168,14 @@ void transport_slave(matrix_row_t matrix[]) {
118# ifdef WPM_ENABLE 168# ifdef WPM_ENABLE
119 set_current_wpm(i2c_buffer->current_wpm); 169 set_current_wpm(i2c_buffer->current_wpm);
120# endif 170# endif
171
172# ifdef SPLIT_MODS_ENABLE
173 set_mods(i2c_buffer->real_mods);
174 set_weak_mods(i2c_buffer->weak_mods);
175# ifndef NO_ACTION_ONESHOT
176 set_oneshot_mods(i2c_buffer->oneshot_mods);
177# endif
178# endif
121} 179}
122 180
123void transport_master_init(void) { i2c_init(); } 181void transport_master_init(void) { i2c_init(); }
@@ -139,11 +197,21 @@ typedef struct _Serial_s2m_buffer_t {
139} Serial_s2m_buffer_t; 197} Serial_s2m_buffer_t;
140 198
141typedef struct _Serial_m2s_buffer_t { 199typedef struct _Serial_m2s_buffer_t {
200# ifdef SPLIT_MODS_ENABLE
201 uint8_t real_mods;
202 uint8_t weak_mods;
203# ifndef NO_ACTION_ONESHOT
204 uint8_t oneshot_mods;
205# endif
206# endif
207# ifndef DISABLE_SYNC_TIMER
208 uint32_t sync_timer;
209# endif
142# ifdef BACKLIGHT_ENABLE 210# ifdef BACKLIGHT_ENABLE
143 uint8_t backlight_level; 211 uint8_t backlight_level;
144# endif 212# endif
145# ifdef WPM_ENABLE 213# ifdef WPM_ENABLE
146 uint8_t current_wpm; 214 uint8_t current_wpm;
147# endif 215# endif
148} Serial_m2s_buffer_t; 216} Serial_m2s_buffer_t;
149 217
@@ -249,13 +317,28 @@ bool transport_master(matrix_row_t matrix[]) {
249 317
250# ifdef WPM_ENABLE 318# ifdef WPM_ENABLE
251 // Write wpm to slave 319 // Write wpm to slave
252 serial_m2s_buffer.current_wpm = get_current_wpm(); 320 serial_m2s_buffer.current_wpm = get_current_wpm();
321# endif
322
323# ifdef SPLIT_MODS_ENABLE
324 serial_m2s_buffer.real_mods = get_mods();
325 serial_m2s_buffer.weak_mods = get_weak_mods();
326# ifndef NO_ACTION_ONESHOT
327 serial_m2s_buffer.oneshot_mods = get_oneshot_mods();
328# endif
329# endif
330# ifndef DISABLE_SYNC_TIMER
331 serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
253# endif 332# endif
254 return true; 333 return true;
255} 334}
256 335
257void transport_slave(matrix_row_t matrix[]) { 336void transport_slave(matrix_row_t matrix[]) {
258 transport_rgblight_slave(); 337 transport_rgblight_slave();
338# ifndef DISABLE_SYNC_TIMER
339 sync_timer_update(serial_m2s_buffer.sync_timer);
340# endif
341
259 // TODO: if MATRIX_COLS > 8 change to pack() 342 // TODO: if MATRIX_COLS > 8 change to pack()
260 for (int i = 0; i < ROWS_PER_HAND; ++i) { 343 for (int i = 0; i < ROWS_PER_HAND; ++i) {
261 serial_s2m_buffer.smatrix[i] = matrix[i]; 344 serial_s2m_buffer.smatrix[i] = matrix[i];
@@ -271,6 +354,14 @@ void transport_slave(matrix_row_t matrix[]) {
271# ifdef WPM_ENABLE 354# ifdef WPM_ENABLE
272 set_current_wpm(serial_m2s_buffer.current_wpm); 355 set_current_wpm(serial_m2s_buffer.current_wpm);
273# endif 356# endif
357
358# ifdef SPLIT_MODS_ENABLE
359 set_mods(serial_m2s_buffer.real_mods);
360 set_weak_mods(serial_m2s_buffer.weak_mods);
361# ifndef NO_ACTION_ONESHOT
362 set_oneshot_mods(serial_m2s_buffer.oneshot_mods);
363# endif
364# endif
274} 365}
275 366
276#endif 367#endif