aboutsummaryrefslogtreecommitdiff
path: root/quantum/audio
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/audio')
-rw-r--r--quantum/audio/audio.c539
-rw-r--r--quantum/audio/audio.h281
-rw-r--r--quantum/audio/audio_avr.c812
-rw-r--r--quantum/audio/audio_chibios.c721
-rw-r--r--quantum/audio/audio_pwm.c606
-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.h77
-rw-r--r--quantum/audio/voices.c170
-rw-r--r--quantum/audio/voices.h21
-rw-r--r--quantum/audio/wave.h36
17 files changed, 2337 insertions, 2319 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 dccf03d5f..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,62 +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);
52 96
53// Vibrato rate functions 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
54 110
55#ifdef VIBRATO_ENABLE 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);
56 125
57void set_vibrato_rate(float rate); 126/**
58void increase_vibrato_rate(float change); 127 * @brief stop a given tone/frequency
59void decrease_vibrato_rate(float change); 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);
60 137
61# ifdef VIBRATO_STRENGTH_ENABLE 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);
62 149
63void set_vibrato_strength(float strength); 150/**
64void increase_vibrato_strength(float change); 151 * @brief play a short tone of a specific frequency to emulate a 'click'
65void decrease_vibrato_strength(float change); 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);
66 162
67# endif 163/**
164 * @brief stops all playback
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);
68 170
69#endif 171/**
172 * @brief query if one/multiple tones are playing
173 */
174bool audio_is_playing_note(void);
70 175
71// Polyphony functions 176/**
177 * @brief query if a melody/SONG is playing
178 */
179bool audio_is_playing_melody(void);
72 180
73void set_polyphony_rate(float rate); 181// These macros are used to allow audio_play_melody to play an array of indeterminate
74void enable_polyphony(void); 182// length. This works around the limitation of C's sizeof operation on pointers.
75void disable_polyphony(void); 183// The global float array for the song must be used here.
76void increase_polyphony_rate(float change); 184#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
77void decrease_polyphony_rate(float change);
78 185
79void set_timbre(float timbre); 186/**
80void set_tempo(uint8_t tempo); 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)
81 195
82void increase_tempo(uint8_t tempo_change); 196// Tone-Multiplexing functions
83void decrease_tempo(uint8_t tempo_change); 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);
209#endif
210
211// Tempo functions
212
213void audio_set_tempo(uint8_t tempo);
214void audio_increase_tempo(uint8_t tempo_change);
215void audio_decrease_tempo(uint8_t tempo_change);
216
217// conversion macros, from 64parts-to-a-beat to milliseconds and back
218uint16_t audio_duration_to_ms(uint16_t duration_bpm);
219uint16_t audio_ms_to_duration(uint16_t duration_ms);
84 220
85void audio_init(void);
86void audio_startup(void); 221void audio_startup(void);
87 222
88#ifdef PWM_AUDIO 223// hardware interface
89void play_sample(uint8_t* s, uint16_t l, bool r);
90#endif
91void play_note(float freq, int vol);
92void stop_note(float freq);
93void stop_all_notes(void);
94void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat);
95 224
96#define SCALE \ 225// implementation in the driver_avr/arm_* respective parts
97 (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), } 226void audio_driver_initialize(void);
227void audio_driver_start(void);
228void audio_driver_stop(void);
98 229
99// These macros are used to allow play_notes to play an array of indeterminate 230/**
100// length. This works around the limitation of C's sizeof operation on pointers. 231 * @brief get the number of currently active tones
101// The global float array for the song must be used here. 232 * @return number, 0=none active
102#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) 233 */
103#define PLAY_SONG(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), false) 234uint8_t audio_get_number_of_active_tones(void);
104#define PLAY_LOOP(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), true) 235
236/**
237 * @brief access to the raw/unprocessed frequency for a specific tone
238 * @details each active tone has a frequency associated with it, which
239 * the internal state keeps track of, and is usually influenced
240 * by various effects
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)
105 280
106bool 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 1bac43bb4..000000000
--- a/quantum/audio/audio_avr.c
+++ /dev/null
@@ -1,812 +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
232void audio_startup() {
233 if (audio_config.enable) {
234 PLAY_SONG(startup_song);
235 }
236}
237
238void stop_all_notes() {
239 dprintf("audio stop all notes");
240
241 if (!audio_initialized) {
242 audio_init();
243 }
244 voices = 0;
245
246#ifdef CPIN_AUDIO
247 DISABLE_AUDIO_COUNTER_3_ISR;
248 DISABLE_AUDIO_COUNTER_3_OUTPUT;
249#endif
250
251#ifdef BPIN_AUDIO
252 DISABLE_AUDIO_COUNTER_1_ISR;
253 DISABLE_AUDIO_COUNTER_1_OUTPUT;
254#endif
255
256 playing_notes = false;
257 playing_note = false;
258 frequency = 0;
259 frequency_alt = 0;
260 volume = 0;
261
262 for (uint8_t i = 0; i < 8; i++) {
263 frequencies[i] = 0;
264 volumes[i] = 0;
265 }
266}
267
268void stop_note(float freq) {
269 dprintf("audio stop note freq=%d", (int)freq);
270
271 if (playing_note) {
272 if (!audio_initialized) {
273 audio_init();
274 }
275 for (int i = 7; i >= 0; i--) {
276 if (frequencies[i] == freq) {
277 frequencies[i] = 0;
278 volumes[i] = 0;
279 for (int j = i; (j < 7); j++) {
280 frequencies[j] = frequencies[j + 1];
281 frequencies[j + 1] = 0;
282 volumes[j] = volumes[j + 1];
283 volumes[j + 1] = 0;
284 }
285 break;
286 }
287 }
288 voices--;
289 if (voices < 0) voices = 0;
290 if (voice_place >= voices) {
291 voice_place = 0;
292 }
293 if (voices == 0) {
294#ifdef CPIN_AUDIO
295 DISABLE_AUDIO_COUNTER_3_ISR;
296 DISABLE_AUDIO_COUNTER_3_OUTPUT;
297#endif
298#ifdef BPIN_AUDIO
299 DISABLE_AUDIO_COUNTER_1_ISR;
300 DISABLE_AUDIO_COUNTER_1_OUTPUT;
301#endif
302 frequency = 0;
303 frequency_alt = 0;
304 volume = 0;
305 playing_note = false;
306 }
307 }
308}
309
310#ifdef VIBRATO_ENABLE
311
312float mod(float a, int b) {
313 float r = fmod(a, b);
314 return r < 0 ? r + b : r;
315}
316
317float vibrato(float average_freq) {
318# ifdef VIBRATO_STRENGTH_ENABLE
319 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
320# else
321 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
322# endif
323 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
324 return vibrated_freq;
325}
326
327#endif
328
329#ifdef CPIN_AUDIO
330ISR(TIMER3_AUDIO_vect) {
331 float freq;
332
333 if (playing_note) {
334 if (voices > 0) {
335# ifdef BPIN_AUDIO
336 float freq_alt = 0;
337 if (voices > 1) {
338 if (polyphony_rate == 0) {
339 if (glissando) {
340 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 if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) {
343 frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2);
344 } else {
345 frequency_alt = frequencies[voices - 2];
346 }
347 } else {
348 frequency_alt = frequencies[voices - 2];
349 }
350
351# ifdef VIBRATO_ENABLE
352 if (vibrato_strength > 0) {
353 freq_alt = vibrato(frequency_alt);
354 } else {
355 freq_alt = frequency_alt;
356 }
357# else
358 freq_alt = frequency_alt;
359# endif
360 }
361
362 if (envelope_index < 65535) {
363 envelope_index++;
364 }
365
366 freq_alt = voice_envelope(freq_alt);
367
368 if (freq_alt < 30.517578125) {
369 freq_alt = 30.52;
370 }
371
372 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq_alt * CPU_PRESCALER));
373 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq_alt * CPU_PRESCALER)) * note_timbre);
374 }
375# endif
376
377 if (polyphony_rate > 0) {
378 if (voices > 1) {
379 voice_place %= voices;
380 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
381 voice_place = (voice_place + 1) % voices;
382 place = 0.0;
383 }
384 }
385
386# ifdef VIBRATO_ENABLE
387 if (vibrato_strength > 0) {
388 freq = vibrato(frequencies[voice_place]);
389 } else {
390 freq = frequencies[voice_place];
391 }
392# else
393 freq = frequencies[voice_place];
394# endif
395 } else {
396 if (glissando) {
397 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 if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
400 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
401 } else {
402 frequency = frequencies[voices - 1];
403 }
404 } else {
405 frequency = frequencies[voices - 1];
406 }
407
408# ifdef VIBRATO_ENABLE
409 if (vibrato_strength > 0) {
410 freq = vibrato(frequency);
411 } else {
412 freq = frequency;
413 }
414# else
415 freq = frequency;
416# endif
417 }
418
419 if (envelope_index < 65535) {
420 envelope_index++;
421 }
422
423 freq = voice_envelope(freq);
424
425 if (freq < 30.517578125) {
426 freq = 30.52;
427 }
428
429 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
430 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
431 }
432 }
433
434 if (playing_notes) {
435 if (note_frequency > 0) {
436# ifdef VIBRATO_ENABLE
437 if (vibrato_strength > 0) {
438 freq = vibrato(note_frequency);
439 } else {
440 freq = note_frequency;
441 }
442# else
443 freq = note_frequency;
444# endif
445
446 if (envelope_index < 65535) {
447 envelope_index++;
448 }
449 freq = voice_envelope(freq);
450
451 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
452 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
453 } else {
454 TIMER_3_PERIOD = 0;
455 TIMER_3_DUTY_CYCLE = 0;
456 }
457
458 note_position++;
459 bool end_of_note = false;
460 if (TIMER_3_PERIOD > 0) {
461 if (!note_resting)
462 end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF - 1));
463 else
464 end_of_note = (note_position >= (note_length));
465 } else {
466 end_of_note = (note_position >= (note_length));
467 }
468
469 if (end_of_note) {
470 current_note++;
471 if (current_note >= notes_count) {
472 if (notes_repeat) {
473 current_note = 0;
474 } else {
475 DISABLE_AUDIO_COUNTER_3_ISR;
476 DISABLE_AUDIO_COUNTER_3_OUTPUT;
477 playing_notes = false;
478 return;
479 }
480 }
481 if (!note_resting) {
482 note_resting = true;
483 current_note--;
484 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
485 note_frequency = 0;
486 note_length = 1;
487 } else {
488 note_frequency = (*notes_pointer)[current_note][0];
489 note_length = 1;
490 }
491 } else {
492 note_resting = false;
493 envelope_index = 0;
494 note_frequency = (*notes_pointer)[current_note][0];
495 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
496 }
497
498 note_position = 0;
499 }
500 }
501
502 if (!audio_config.enable) {
503 playing_notes = false;
504 playing_note = false;
505 }
506}
507#endif
508
509#ifdef BPIN_AUDIO
510ISR(TIMER1_AUDIO_vect) {
511# if defined(BPIN_AUDIO) && !defined(CPIN_AUDIO)
512 float freq = 0;
513
514 if (playing_note) {
515 if (voices > 0) {
516 if (polyphony_rate > 0) {
517 if (voices > 1) {
518 voice_place %= voices;
519 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
520 voice_place = (voice_place + 1) % voices;
521 place = 0.0;
522 }
523 }
524
525# ifdef VIBRATO_ENABLE
526 if (vibrato_strength > 0) {
527 freq = vibrato(frequencies[voice_place]);
528 } else {
529 freq = frequencies[voice_place];
530 }
531# else
532 freq = frequencies[voice_place];
533# endif
534 } else {
535 if (glissando) {
536 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 if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
539 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
540 } else {
541 frequency = frequencies[voices - 1];
542 }
543 } else {
544 frequency = frequencies[voices - 1];
545 }
546
547# ifdef VIBRATO_ENABLE
548 if (vibrato_strength > 0) {
549 freq = vibrato(frequency);
550 } else {
551 freq = frequency;
552 }
553# else
554 freq = frequency;
555# endif
556 }
557
558 if (envelope_index < 65535) {
559 envelope_index++;
560 }
561
562 freq = voice_envelope(freq);
563
564 if (freq < 30.517578125) {
565 freq = 30.52;
566 }
567
568 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
569 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
570 }
571 }
572
573 if (playing_notes) {
574 if (note_frequency > 0) {
575# ifdef VIBRATO_ENABLE
576 if (vibrato_strength > 0) {
577 freq = vibrato(note_frequency);
578 } else {
579 freq = note_frequency;
580 }
581# else
582 freq = note_frequency;
583# endif
584
585 if (envelope_index < 65535) {
586 envelope_index++;
587 }
588 freq = voice_envelope(freq);
589
590 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
591 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
592 } else {
593 TIMER_1_PERIOD = 0;
594 TIMER_1_DUTY_CYCLE = 0;
595 }
596
597 note_position++;
598 bool end_of_note = false;
599 if (TIMER_1_PERIOD > 0) {
600 if (!note_resting)
601 end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF - 1));
602 else
603 end_of_note = (note_position >= (note_length));
604 } else {
605 end_of_note = (note_position >= (note_length));
606 }
607
608 if (end_of_note) {
609 current_note++;
610 if (current_note >= notes_count) {
611 if (notes_repeat) {
612 current_note = 0;
613 } else {
614 DISABLE_AUDIO_COUNTER_1_ISR;
615 DISABLE_AUDIO_COUNTER_1_OUTPUT;
616 playing_notes = false;
617 return;
618 }
619 }
620 if (!note_resting) {
621 note_resting = true;
622 current_note--;
623 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
624 note_frequency = 0;
625 note_length = 1;
626 } else {
627 note_frequency = (*notes_pointer)[current_note][0];
628 note_length = 1;
629 }
630 } else {
631 note_resting = false;
632 envelope_index = 0;
633 note_frequency = (*notes_pointer)[current_note][0];
634 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
635 }
636
637 note_position = 0;
638 }
639 }
640
641 if (!audio_config.enable) {
642 playing_notes = false;
643 playing_note = false;
644 }
645# endif
646}
647#endif
648
649void play_note(float freq, int vol) {
650 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
651
652 if (!audio_initialized) {
653 audio_init();
654 }
655
656 if (audio_config.enable && voices < 8) {
657#ifdef CPIN_AUDIO
658 DISABLE_AUDIO_COUNTER_3_ISR;
659#endif
660#ifdef BPIN_AUDIO
661 DISABLE_AUDIO_COUNTER_1_ISR;
662#endif
663
664 // Cancel notes if notes are playing
665 if (playing_notes) stop_all_notes();
666
667 playing_note = true;
668
669 envelope_index = 0;
670
671 if (freq > 0) {
672 frequencies[voices] = freq;
673 volumes[voices] = vol;
674 voices++;
675 }
676
677#ifdef CPIN_AUDIO
678 ENABLE_AUDIO_COUNTER_3_ISR;
679 ENABLE_AUDIO_COUNTER_3_OUTPUT;
680#endif
681#ifdef BPIN_AUDIO
682# ifdef CPIN_AUDIO
683 if (voices > 1) {
684 ENABLE_AUDIO_COUNTER_1_ISR;
685 ENABLE_AUDIO_COUNTER_1_OUTPUT;
686 }
687# else
688 ENABLE_AUDIO_COUNTER_1_ISR;
689 ENABLE_AUDIO_COUNTER_1_OUTPUT;
690# endif
691#endif
692 }
693}
694
695void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) {
696 if (!audio_initialized) {
697 audio_init();
698 }
699
700 if (audio_config.enable) {
701#ifdef CPIN_AUDIO
702 DISABLE_AUDIO_COUNTER_3_ISR;
703#endif
704#ifdef BPIN_AUDIO
705 DISABLE_AUDIO_COUNTER_1_ISR;
706#endif
707
708 // Cancel note if a note is playing
709 if (playing_note) stop_all_notes();
710
711 playing_notes = true;
712
713 notes_pointer = np;
714 notes_count = n_count;
715 notes_repeat = n_repeat;
716
717 place = 0;
718 current_note = 0;
719
720 note_frequency = (*notes_pointer)[current_note][0];
721 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
722 note_position = 0;
723
724#ifdef CPIN_AUDIO
725 ENABLE_AUDIO_COUNTER_3_ISR;
726 ENABLE_AUDIO_COUNTER_3_OUTPUT;
727#endif
728#ifdef BPIN_AUDIO
729# ifndef CPIN_AUDIO
730 ENABLE_AUDIO_COUNTER_1_ISR;
731 ENABLE_AUDIO_COUNTER_1_OUTPUT;
732# endif
733#endif
734 }
735}
736
737bool is_playing_notes(void) { return playing_notes; }
738
739bool is_audio_on(void) { return (audio_config.enable != 0); }
740
741void audio_toggle(void) {
742 audio_config.enable ^= 1;
743 eeconfig_update_audio(audio_config.raw);
744 if (audio_config.enable) audio_on_user();
745}
746
747void audio_on(void) {
748 audio_config.enable = 1;
749 eeconfig_update_audio(audio_config.raw);
750 audio_on_user();
751 PLAY_SONG(audio_on_song);
752}
753
754void audio_off(void) {
755 PLAY_SONG(audio_off_song);
756 wait_ms(100);
757 stop_all_notes();
758 audio_config.enable = 0;
759 eeconfig_update_audio(audio_config.raw);
760}
761
762#ifdef VIBRATO_ENABLE
763
764// Vibrato rate functions
765
766void set_vibrato_rate(float rate) { vibrato_rate = rate; }
767
768void increase_vibrato_rate(float change) { vibrato_rate *= change; }
769
770void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
771
772# ifdef VIBRATO_STRENGTH_ENABLE
773
774void set_vibrato_strength(float strength) { vibrato_strength = strength; }
775
776void increase_vibrato_strength(float change) { vibrato_strength *= change; }
777
778void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
779
780# endif /* VIBRATO_STRENGTH_ENABLE */
781
782#endif /* VIBRATO_ENABLE */
783
784// Polyphony functions
785
786void set_polyphony_rate(float rate) { polyphony_rate = rate; }
787
788void enable_polyphony() { polyphony_rate = 5; }
789
790void disable_polyphony() { polyphony_rate = 0; }
791
792void increase_polyphony_rate(float change) { polyphony_rate *= change; }
793
794void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
795
796// Timbre function
797
798void set_timbre(float timbre) { note_timbre = timbre; }
799
800// Tempo functions
801
802void set_tempo(uint8_t tempo) { note_tempo = tempo; }
803
804void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
805
806void increase_tempo(uint8_t tempo_change) {
807 if (note_tempo - tempo_change < 10) {
808 note_tempo = 10;
809 } else {
810 note_tempo -= tempo_change;
811 }
812}
diff --git a/quantum/audio/audio_chibios.c b/quantum/audio/audio_chibios.c
deleted file mode 100644
index b267e5746..000000000
--- a/quantum/audio/audio_chibios.c
+++ /dev/null
@@ -1,721 +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 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG)
91#define START_CHANNEL_2() \
92 gptStart(&GPTD7, &gpt7cfg1); \
93 gptStartContinuous(&GPTD7, 2U); \
94 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG)
95#define STOP_CHANNEL_1() \
96 gptStopTimer(&GPTD6); \
97 palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL); \
98 palSetPad(GPIOA, 4)
99#define STOP_CHANNEL_2() \
100 gptStopTimer(&GPTD7); \
101 palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); \
102 palSetPad(GPIOA, 5)
103#define RESTART_CHANNEL_1() \
104 STOP_CHANNEL_1(); \
105 START_CHANNEL_1()
106#define RESTART_CHANNEL_2() \
107 STOP_CHANNEL_2(); \
108 START_CHANNEL_2()
109#define UPDATE_CHANNEL_1_FREQ(freq) \
110 gpt6cfg1.frequency = freq * DAC_BUFFER_SIZE; \
111 RESTART_CHANNEL_1()
112#define UPDATE_CHANNEL_2_FREQ(freq) \
113 gpt7cfg1.frequency = freq * DAC_BUFFER_SIZE; \
114 RESTART_CHANNEL_2()
115#define GET_CHANNEL_1_FREQ (uint16_t)(gpt6cfg1.frequency * DAC_BUFFER_SIZE)
116#define GET_CHANNEL_2_FREQ (uint16_t)(gpt7cfg1.frequency * DAC_BUFFER_SIZE)
117
118/*
119 * GPT6 configuration.
120 */
121// static const GPTConfig gpt6cfg1 = {
122// .frequency = 1000000U,
123// .callback = NULL,
124// .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
125// .dier = 0U
126// };
127
128GPTConfig gpt6cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE,
129 .callback = NULL,
130 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
131 .dier = 0U};
132
133GPTConfig gpt7cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE,
134 .callback = NULL,
135 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
136 .dier = 0U};
137
138GPTConfig gpt8cfg1 = {.frequency = 10,
139 .callback = gpt_cb8,
140 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
141 .dier = 0U};
142
143/*
144 * DAC test buffer (sine wave).
145 */
146// static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = {
147// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437,
148// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846,
149// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221,
150// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544,
151// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801,
152// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982,
153// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078,
154// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086,
155// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004,
156// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837,
157// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591,
158// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278,
159// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912,
160// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507,
161// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082,
162// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657,
163// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248,
164// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873,
165// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550,
166// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293,
167// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112,
168// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16,
169// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8,
170// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90,
171// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257,
172// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503,
173// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816,
174// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182,
175// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587,
176// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012
177// };
178
179// static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = {
180// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8,
181// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90,
182// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257,
183// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503,
184// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816,
185// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182,
186// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587,
187// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012,
188// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437,
189// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846,
190// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221,
191// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544,
192// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801,
193// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982,
194// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078,
195// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086,
196// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004,
197// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837,
198// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591,
199// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278,
200// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912,
201// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507,
202// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082,
203// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657,
204// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248,
205// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873,
206// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550,
207// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293,
208// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112,
209// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16
210// };
211
212// squarewave
213static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = {
214 // First half is max, second half is 0
215 [0 ... DAC_BUFFER_SIZE / 2 - 1] = DAC_SAMPLE_MAX,
216 [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = 0,
217};
218
219// squarewave
220static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = {
221 // opposite of dac_buffer above
222 [0 ... DAC_BUFFER_SIZE / 2 - 1] = 0,
223 [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = DAC_SAMPLE_MAX,
224};
225
226/*
227 * DAC streaming callback.
228 */
229size_t nz = 0;
230static void end_cb1(DACDriver *dacp) {
231 (void)dacp;
232
233 nz++;
234 if ((nz % 1000) == 0) {
235 // palTogglePad(GPIOD, GPIOD_LED3);
236 }
237}
238
239/*
240 * DAC error callback.
241 */
242static void error_cb1(DACDriver *dacp, dacerror_t err) {
243 (void)dacp;
244 (void)err;
245
246 chSysHalt("DAC failure");
247}
248
249static const DACConfig dac1cfg1 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT};
250
251static const DACConversionGroup dacgrpcfg1 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)};
252
253static const DACConfig dac1cfg2 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT};
254
255static const DACConversionGroup dacgrpcfg2 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)};
256
257void audio_init() {
258 if (audio_initialized) {
259 return;
260 }
261
262// Check EEPROM
263#ifdef EEPROM_ENABLE
264 if (!eeconfig_is_enabled()) {
265 eeconfig_init();
266 }
267 audio_config.raw = eeconfig_read_audio();
268#else // ARM EEPROM
269 audio_config.enable = true;
270# ifdef AUDIO_CLICKY_ON
271 audio_config.clicky_enable = true;
272# endif
273#endif // ARM EEPROM
274
275 /*
276 * Starting DAC1 driver, setting up the output pin as analog as suggested
277 * by the Reference Manual.
278 */
279 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
280 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
281 dacStart(&DACD1, &dac1cfg1);
282 dacStart(&DACD2, &dac1cfg2);
283
284 /*
285 * Start the note timer
286 */
287 gptStart(&GPTD8, &gpt8cfg1);
288 gptStartContinuous(&GPTD8, 2U);
289
290 /*
291 * Starting GPT6/7 driver, it is used for triggering the DAC.
292 */
293 START_CHANNEL_1();
294 START_CHANNEL_2();
295
296 /*
297 * Starting a continuous conversion.
298 */
299 dacStartConversion(&DACD1, &dacgrpcfg1, (dacsample_t *)dac_buffer, DAC_BUFFER_SIZE);
300 dacStartConversion(&DACD2, &dacgrpcfg2, (dacsample_t *)dac_buffer_2, DAC_BUFFER_SIZE);
301
302 audio_initialized = true;
303
304 stop_all_notes();
305}
306
307void audio_startup() {
308 if (audio_config.enable) {
309 PLAY_SONG(startup_song);
310 }
311}
312
313void stop_all_notes() {
314 dprintf("audio stop all notes");
315
316 if (!audio_initialized) {
317 audio_init();
318 }
319 voices = 0;
320
321 gptStopTimer(&GPTD6);
322 gptStopTimer(&GPTD7);
323 gptStopTimer(&GPTD8);
324
325 playing_notes = false;
326 playing_note = false;
327 frequency = 0;
328 frequency_alt = 0;
329 volume = 0;
330
331 for (uint8_t i = 0; i < 8; i++) {
332 frequencies[i] = 0;
333 volumes[i] = 0;
334 }
335}
336
337void stop_note(float freq) {
338 dprintf("audio stop note freq=%d", (int)freq);
339
340 if (playing_note) {
341 if (!audio_initialized) {
342 audio_init();
343 }
344 for (int i = 7; i >= 0; i--) {
345 if (frequencies[i] == freq) {
346 frequencies[i] = 0;
347 volumes[i] = 0;
348 for (int j = i; (j < 7); j++) {
349 frequencies[j] = frequencies[j + 1];
350 frequencies[j + 1] = 0;
351 volumes[j] = volumes[j + 1];
352 volumes[j + 1] = 0;
353 }
354 break;
355 }
356 }
357 voices--;
358 if (voices < 0) {
359 voices = 0;
360 }
361 if (voice_place >= voices) {
362 voice_place = 0;
363 }
364 if (voices == 0) {
365 STOP_CHANNEL_1();
366 STOP_CHANNEL_2();
367 gptStopTimer(&GPTD8);
368 frequency = 0;
369 frequency_alt = 0;
370 volume = 0;
371 playing_note = false;
372 }
373 }
374}
375
376#ifdef VIBRATO_ENABLE
377
378float mod(float a, int b) {
379 float r = fmod(a, b);
380 return r < 0 ? r + b : r;
381}
382
383float vibrato(float average_freq) {
384# ifdef VIBRATO_STRENGTH_ENABLE
385 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
386# else
387 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
388# endif
389 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
390 return vibrated_freq;
391}
392
393#endif
394
395static void gpt_cb8(GPTDriver *gptp) {
396 float freq;
397
398 if (playing_note) {
399 if (voices > 0) {
400 float freq_alt = 0;
401 if (voices > 1) {
402 if (polyphony_rate == 0) {
403 if (glissando) {
404 if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) {
405 frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2);
406 } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) {
407 frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2);
408 } else {
409 frequency_alt = frequencies[voices - 2];
410 }
411 } else {
412 frequency_alt = frequencies[voices - 2];
413 }
414
415#ifdef VIBRATO_ENABLE
416 if (vibrato_strength > 0) {
417 freq_alt = vibrato(frequency_alt);
418 } else {
419 freq_alt = frequency_alt;
420 }
421#else
422 freq_alt = frequency_alt;
423#endif
424 }
425
426 if (envelope_index < 65535) {
427 envelope_index++;
428 }
429
430 freq_alt = voice_envelope(freq_alt);
431
432 if (freq_alt < 30.517578125) {
433 freq_alt = 30.52;
434 }
435
436 if (GET_CHANNEL_2_FREQ != (uint16_t)freq_alt) {
437 UPDATE_CHANNEL_2_FREQ(freq_alt);
438 } else {
439 RESTART_CHANNEL_2();
440 }
441 // note_timbre;
442 }
443
444 if (polyphony_rate > 0) {
445 if (voices > 1) {
446 voice_place %= voices;
447 if (place++ > (frequencies[voice_place] / polyphony_rate)) {
448 voice_place = (voice_place + 1) % voices;
449 place = 0.0;
450 }
451 }
452
453#ifdef VIBRATO_ENABLE
454 if (vibrato_strength > 0) {
455 freq = vibrato(frequencies[voice_place]);
456 } else {
457 freq = frequencies[voice_place];
458 }
459#else
460 freq = frequencies[voice_place];
461#endif
462 } else {
463 if (glissando) {
464 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
465 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
466 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
467 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
468 } else {
469 frequency = frequencies[voices - 1];
470 }
471 } else {
472 frequency = frequencies[voices - 1];
473 }
474
475#ifdef VIBRATO_ENABLE
476 if (vibrato_strength > 0) {
477 freq = vibrato(frequency);
478 } else {
479 freq = frequency;
480 }
481#else
482 freq = frequency;
483#endif
484 }
485
486 if (envelope_index < 65535) {
487 envelope_index++;
488 }
489
490 freq = voice_envelope(freq);
491
492 if (freq < 30.517578125) {
493 freq = 30.52;
494 }
495
496 if (GET_CHANNEL_1_FREQ != (uint16_t)freq) {
497 UPDATE_CHANNEL_1_FREQ(freq);
498 } else {
499 RESTART_CHANNEL_1();
500 }
501 // note_timbre;
502 }
503 }
504
505 if (playing_notes) {
506 if (note_frequency > 0) {
507#ifdef VIBRATO_ENABLE
508 if (vibrato_strength > 0) {
509 freq = vibrato(note_frequency);
510 } else {
511 freq = note_frequency;
512 }
513#else
514 freq = note_frequency;
515#endif
516
517 if (envelope_index < 65535) {
518 envelope_index++;
519 }
520 freq = voice_envelope(freq);
521
522 if (GET_CHANNEL_1_FREQ != (uint16_t)freq) {
523 UPDATE_CHANNEL_1_FREQ(freq);
524 UPDATE_CHANNEL_2_FREQ(freq);
525 }
526 // note_timbre;
527 } else {
528 // gptStopTimer(&GPTD6);
529 // gptStopTimer(&GPTD7);
530 }
531
532 note_position++;
533 bool end_of_note = false;
534 if (GET_CHANNEL_1_FREQ > 0) {
535 if (!note_resting)
536 end_of_note = (note_position >= (note_length * 8 - 1));
537 else
538 end_of_note = (note_position >= (note_length * 8));
539 } else {
540 end_of_note = (note_position >= (note_length * 8));
541 }
542
543 if (end_of_note) {
544 current_note++;
545 if (current_note >= notes_count) {
546 if (notes_repeat) {
547 current_note = 0;
548 } else {
549 STOP_CHANNEL_1();
550 STOP_CHANNEL_2();
551 // gptStopTimer(&GPTD8);
552 playing_notes = false;
553 return;
554 }
555 }
556 if (!note_resting) {
557 note_resting = true;
558 current_note--;
559 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
560 note_frequency = 0;
561 note_length = 1;
562 } else {
563 note_frequency = (*notes_pointer)[current_note][0];
564 note_length = 1;
565 }
566 } else {
567 note_resting = false;
568 envelope_index = 0;
569 note_frequency = (*notes_pointer)[current_note][0];
570 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
571 }
572
573 note_position = 0;
574 }
575 }
576
577 if (!audio_config.enable) {
578 playing_notes = false;
579 playing_note = false;
580 }
581}
582
583void play_note(float freq, int vol) {
584 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
585
586 if (!audio_initialized) {
587 audio_init();
588 }
589
590 if (audio_config.enable && voices < 8) {
591 // Cancel notes if notes are playing
592 if (playing_notes) {
593 stop_all_notes();
594 }
595
596 playing_note = true;
597
598 envelope_index = 0;
599
600 if (freq > 0) {
601 frequencies[voices] = freq;
602 volumes[voices] = vol;
603 voices++;
604 }
605
606 gptStart(&GPTD8, &gpt8cfg1);
607 gptStartContinuous(&GPTD8, 2U);
608 RESTART_CHANNEL_1();
609 RESTART_CHANNEL_2();
610 }
611}
612
613void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) {
614 if (!audio_initialized) {
615 audio_init();
616 }
617
618 if (audio_config.enable) {
619 // Cancel note if a note is playing
620 if (playing_note) {
621 stop_all_notes();
622 }
623
624 playing_notes = true;
625
626 notes_pointer = np;
627 notes_count = n_count;
628 notes_repeat = n_repeat;
629
630 place = 0;
631 current_note = 0;
632
633 note_frequency = (*notes_pointer)[current_note][0];
634 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
635 note_position = 0;
636
637 gptStart(&GPTD8, &gpt8cfg1);
638 gptStartContinuous(&GPTD8, 2U);
639 RESTART_CHANNEL_1();
640 RESTART_CHANNEL_2();
641 }
642}
643
644bool is_playing_notes(void) { return playing_notes; }
645
646bool is_audio_on(void) { return (audio_config.enable != 0); }
647
648void audio_toggle(void) {
649 if (audio_config.enable) {
650 stop_all_notes();
651 }
652 audio_config.enable ^= 1;
653 eeconfig_update_audio(audio_config.raw);
654 if (audio_config.enable) {
655 audio_on_user();
656 }
657}
658
659void audio_on(void) {
660 audio_config.enable = 1;
661 eeconfig_update_audio(audio_config.raw);
662 audio_on_user();
663}
664
665void audio_off(void) {
666 stop_all_notes();
667 audio_config.enable = 0;
668 eeconfig_update_audio(audio_config.raw);
669}
670
671#ifdef VIBRATO_ENABLE
672
673// Vibrato rate functions
674
675void set_vibrato_rate(float rate) { vibrato_rate = rate; }
676
677void increase_vibrato_rate(float change) { vibrato_rate *= change; }
678
679void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
680
681# ifdef VIBRATO_STRENGTH_ENABLE
682
683void set_vibrato_strength(float strength) { vibrato_strength = strength; }
684
685void increase_vibrato_strength(float change) { vibrato_strength *= change; }
686
687void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
688
689# endif /* VIBRATO_STRENGTH_ENABLE */
690
691#endif /* VIBRATO_ENABLE */
692
693// Polyphony functions
694
695void set_polyphony_rate(float rate) { polyphony_rate = rate; }
696
697void enable_polyphony() { polyphony_rate = 5; }
698
699void disable_polyphony() { polyphony_rate = 0; }
700
701void increase_polyphony_rate(float change) { polyphony_rate *= change; }
702
703void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
704
705// Timbre function
706
707void set_timbre(float timbre) { note_timbre = timbre; }
708
709// Tempo functions
710
711void set_tempo(uint8_t tempo) { note_tempo = tempo; }
712
713void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
714
715void increase_tempo(uint8_t tempo_change) {
716 if (note_tempo - tempo_change < 10) {
717 note_tempo = 10;
718 } else {
719 note_tempo -= tempo_change;
720 }
721}
diff --git a/quantum/audio/audio_pwm.c b/quantum/audio/audio_pwm.c
deleted file mode 100644
index d93ac4bb4..000000000
--- a/quantum/audio/audio_pwm.c
+++ /dev/null
@@ -1,606 +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#ifndef STARTUP_SONG
33# define STARTUP_SONG SONG(STARTUP_SOUND)
34#endif
35float startup_song[][2] = STARTUP_SONG;
36
37// Timer Abstractions
38
39// TIMSK3 - Timer/Counter #3 Interrupt Mask Register
40// Turn on/off 3A interputs, stopping/enabling the ISR calls
41#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
42#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
43
44// TCCR3A: Timer/Counter #3 Control Register
45// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
46#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
47#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
48
49#define NOTE_PERIOD ICR3
50#define NOTE_DUTY_CYCLE OCR3A
51
52#ifdef PWM_AUDIO
53# include "wave.h"
54# define SAMPLE_DIVIDER 39
55# define SAMPLE_RATE (2000000.0 / SAMPLE_DIVIDER / 2048)
56// Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
57
58float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
59uint16_t place_int = 0;
60bool repeat = true;
61#endif
62
63void delay_us(int count) {
64 while (count--) {
65 _delay_us(1);
66 }
67}
68
69int voices = 0;
70int voice_place = 0;
71float frequency = 0;
72int volume = 0;
73long position = 0;
74
75float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
76int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
77bool sliding = false;
78
79float place = 0;
80
81uint8_t* sample;
82uint16_t sample_length = 0;
83// float freq = 0;
84
85bool playing_notes = false;
86bool playing_note = false;
87float note_frequency = 0;
88float note_length = 0;
89uint8_t note_tempo = TEMPO_DEFAULT;
90float note_timbre = TIMBRE_DEFAULT;
91uint16_t note_position = 0;
92float (*notes_pointer)[][2];
93uint16_t notes_count;
94bool notes_repeat;
95float notes_rest;
96bool note_resting = false;
97
98uint16_t current_note = 0;
99uint8_t rest_counter = 0;
100
101#ifdef VIBRATO_ENABLE
102float vibrato_counter = 0;
103float vibrato_strength = .5;
104float vibrato_rate = 0.125;
105#endif
106
107float polyphony_rate = 0;
108
109static bool audio_initialized = false;
110
111audio_config_t audio_config;
112
113uint16_t envelope_index = 0;
114
115void audio_init() {
116 // Check EEPROM
117 if (!eeconfig_is_enabled()) {
118 eeconfig_init();
119 }
120 audio_config.raw = eeconfig_read_audio();
121
122#ifdef PWM_AUDIO
123
124 PLLFRQ = _BV(PDIV2);
125 PLLCSR = _BV(PLLE);
126 while (!(PLLCSR & _BV(PLOCK)))
127 ;
128 PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
129
130 /* Init a fast PWM on Timer4 */
131 TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
132 TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
133 OCR4A = 0;
134
135 /* Enable the OC4A output */
136 DDRC |= _BV(PORTC6);
137
138 DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs
139
140 TCCR3A = 0x0; // Options not needed
141 TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
142 OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
143
144#else
145
146 // Set port PC6 (OC3A and /OC4A) as output
147 DDRC |= _BV(PORTC6);
148
149 DISABLE_AUDIO_COUNTER_3_ISR;
150
151 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
152 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
153 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
154 // Clock Select (CS3n) = 0b010 = Clock / 8
155 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
156 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
157
158#endif
159
160 audio_initialized = true;
161}
162
163void audio_startup() {
164 if (audio_config.enable) {
165 PLAY_SONG(startup_song);
166 }
167}
168
169void stop_all_notes() {
170 if (!audio_initialized) {
171 audio_init();
172 }
173 voices = 0;
174#ifdef PWM_AUDIO
175 DISABLE_AUDIO_COUNTER_3_ISR;
176#else
177 DISABLE_AUDIO_COUNTER_3_ISR;
178 DISABLE_AUDIO_COUNTER_3_OUTPUT;
179#endif
180
181 playing_notes = false;
182 playing_note = false;
183 frequency = 0;
184 volume = 0;
185
186 for (uint8_t i = 0; i < 8; i++) {
187 frequencies[i] = 0;
188 volumes[i] = 0;
189 }
190}
191
192void stop_note(float freq) {
193 if (playing_note) {
194 if (!audio_initialized) {
195 audio_init();
196 }
197#ifdef PWM_AUDIO
198 freq = freq / SAMPLE_RATE;
199#endif
200 for (int i = 7; i >= 0; i--) {
201 if (frequencies[i] == freq) {
202 frequencies[i] = 0;
203 volumes[i] = 0;
204 for (int j = i; (j < 7); j++) {
205 frequencies[j] = frequencies[j + 1];
206 frequencies[j + 1] = 0;
207 volumes[j] = volumes[j + 1];
208 volumes[j + 1] = 0;
209 }
210 break;
211 }
212 }
213 voices--;
214 if (voices < 0) voices = 0;
215 if (voice_place >= voices) {
216 voice_place = 0;
217 }
218 if (voices == 0) {
219#ifdef PWM_AUDIO
220 DISABLE_AUDIO_COUNTER_3_ISR;
221#else
222 DISABLE_AUDIO_COUNTER_3_ISR;
223 DISABLE_AUDIO_COUNTER_3_OUTPUT;
224#endif
225 frequency = 0;
226 volume = 0;
227 playing_note = false;
228 }
229 }
230}
231
232#ifdef VIBRATO_ENABLE
233
234float mod(float a, int b) {
235 float r = fmod(a, b);
236 return r < 0 ? r + b : r;
237}
238
239float vibrato(float average_freq) {
240# ifdef VIBRATO_STRENGTH_ENABLE
241 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
242# else
243 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
244# endif
245 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
246 return vibrated_freq;
247}
248
249#endif
250
251ISR(TIMER3_COMPA_vect) {
252 if (playing_note) {
253#ifdef PWM_AUDIO
254 if (voices == 1) {
255 // SINE
256 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
257
258 // SQUARE
259 // if (((int)place) >= 1024){
260 // OCR4A = 0xFF >> 2;
261 // } else {
262 // OCR4A = 0x00;
263 // }
264
265 // SAWTOOTH
266 // OCR4A = (int)place / 4;
267
268 // TRIANGLE
269 // if (((int)place) >= 1024) {
270 // OCR4A = (int)place / 2;
271 // } else {
272 // OCR4A = 2048 - (int)place / 2;
273 // }
274
275 place += frequency;
276
277 if (place >= SINE_LENGTH) place -= SINE_LENGTH;
278
279 } else {
280 int sum = 0;
281 for (int i = 0; i < voices; i++) {
282 // SINE
283 sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
284
285 // SQUARE
286 // if (((int)places[i]) >= 1024){
287 // sum += 0xFF >> 2;
288 // } else {
289 // sum += 0x00;
290 // }
291
292 places[i] += frequencies[i];
293
294 if (places[i] >= SINE_LENGTH) places[i] -= SINE_LENGTH;
295 }
296 OCR4A = sum;
297 }
298#else
299 if (voices > 0) {
300 float freq;
301 if (polyphony_rate > 0) {
302 if (voices > 1) {
303 voice_place %= voices;
304 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
305 voice_place = (voice_place + 1) % voices;
306 place = 0.0;
307 }
308 }
309# ifdef VIBRATO_ENABLE
310 if (vibrato_strength > 0) {
311 freq = vibrato(frequencies[voice_place]);
312 } else {
313# else
314 {
315# endif
316 freq = frequencies[voice_place];
317 }
318 } else {
319 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
320 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
321 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
322 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
323 } else {
324 frequency = frequencies[voices - 1];
325 }
326
327# ifdef VIBRATO_ENABLE
328 if (vibrato_strength > 0) {
329 freq = vibrato(frequency);
330 } else {
331# else
332 {
333# endif
334 freq = frequency;
335 }
336 }
337
338 if (envelope_index < 65535) {
339 envelope_index++;
340 }
341 freq = voice_envelope(freq);
342
343 if (freq < 30.517578125) freq = 30.52;
344 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
345 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
346 }
347#endif
348 }
349
350 // SAMPLE
351 // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
352
353 // place_int++;
354
355 // if (place_int >= sample_length)
356 // if (repeat)
357 // place_int -= sample_length;
358 // else
359 // DISABLE_AUDIO_COUNTER_3_ISR;
360
361 if (playing_notes) {
362#ifdef PWM_AUDIO
363 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
364
365 place += note_frequency;
366 if (place >= SINE_LENGTH) place -= SINE_LENGTH;
367#else
368 if (note_frequency > 0) {
369 float freq;
370
371# ifdef VIBRATO_ENABLE
372 if (vibrato_strength > 0) {
373 freq = vibrato(note_frequency);
374 } else {
375# else
376 {
377# endif
378 freq = note_frequency;
379 }
380
381 if (envelope_index < 65535) {
382 envelope_index++;
383 }
384 freq = voice_envelope(freq);
385
386 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
387 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
388 } else {
389 NOTE_PERIOD = 0;
390 NOTE_DUTY_CYCLE = 0;
391 }
392#endif
393
394 note_position++;
395 bool end_of_note = false;
396 if (NOTE_PERIOD > 0)
397 end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF));
398 else
399 end_of_note = (note_position >= (note_length * 0x7FF));
400 if (end_of_note) {
401 current_note++;
402 if (current_note >= notes_count) {
403 if (notes_repeat) {
404 current_note = 0;
405 } else {
406#ifdef PWM_AUDIO
407 DISABLE_AUDIO_COUNTER_3_ISR;
408#else
409 DISABLE_AUDIO_COUNTER_3_ISR;
410 DISABLE_AUDIO_COUNTER_3_OUTPUT;
411#endif
412 playing_notes = false;
413 return;
414 }
415 }
416 if (!note_resting && (notes_rest > 0)) {
417 note_resting = true;
418 note_frequency = 0;
419 note_length = notes_rest;
420 current_note--;
421 } else {
422 note_resting = false;
423#ifdef PWM_AUDIO
424 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
425 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
426#else
427 envelope_index = 0;
428 note_frequency = (*notes_pointer)[current_note][0];
429 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
430#endif
431 }
432 note_position = 0;
433 }
434 }
435
436 if (!audio_config.enable) {
437 playing_notes = false;
438 playing_note = false;
439 }
440}
441
442void play_note(float freq, int vol) {
443 if (!audio_initialized) {
444 audio_init();
445 }
446
447 if (audio_config.enable && voices < 8) {
448 DISABLE_AUDIO_COUNTER_3_ISR;
449
450 // Cancel notes if notes are playing
451 if (playing_notes) stop_all_notes();
452
453 playing_note = true;
454
455 envelope_index = 0;
456
457#ifdef PWM_AUDIO
458 freq = freq / SAMPLE_RATE;
459#endif
460 if (freq > 0) {
461 frequencies[voices] = freq;
462 volumes[voices] = vol;
463 voices++;
464 }
465
466#ifdef PWM_AUDIO
467 ENABLE_AUDIO_COUNTER_3_ISR;
468#else
469 ENABLE_AUDIO_COUNTER_3_ISR;
470 ENABLE_AUDIO_COUNTER_3_OUTPUT;
471#endif
472 }
473}
474
475void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) {
476 if (!audio_initialized) {
477 audio_init();
478 }
479
480 if (audio_config.enable) {
481 DISABLE_AUDIO_COUNTER_3_ISR;
482
483 // Cancel note if a note is playing
484 if (playing_note) stop_all_notes();
485
486 playing_notes = true;
487
488 notes_pointer = np;
489 notes_count = n_count;
490 notes_repeat = n_repeat;
491 notes_rest = n_rest;
492
493 place = 0;
494 current_note = 0;
495
496#ifdef PWM_AUDIO
497 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
498 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
499#else
500 note_frequency = (*notes_pointer)[current_note][0];
501 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
502#endif
503 note_position = 0;
504
505#ifdef PWM_AUDIO
506 ENABLE_AUDIO_COUNTER_3_ISR;
507#else
508 ENABLE_AUDIO_COUNTER_3_ISR;
509 ENABLE_AUDIO_COUNTER_3_OUTPUT;
510#endif
511 }
512}
513
514#ifdef PWM_AUDIO
515void play_sample(uint8_t* s, uint16_t l, bool r) {
516 if (!audio_initialized) {
517 audio_init();
518 }
519
520 if (audio_config.enable) {
521 DISABLE_AUDIO_COUNTER_3_ISR;
522 stop_all_notes();
523 place_int = 0;
524 sample = s;
525 sample_length = l;
526 repeat = r;
527
528 ENABLE_AUDIO_COUNTER_3_ISR;
529 }
530}
531#endif
532
533void audio_toggle(void) {
534 audio_config.enable ^= 1;
535 eeconfig_update_audio(audio_config.raw);
536}
537
538void audio_on(void) {
539 audio_config.enable = 1;
540 eeconfig_update_audio(audio_config.raw);
541}
542
543void audio_off(void) {
544 audio_config.enable = 0;
545 eeconfig_update_audio(audio_config.raw);
546}
547
548#ifdef VIBRATO_ENABLE
549
550// Vibrato rate functions
551
552void set_vibrato_rate(float rate) { vibrato_rate = rate; }
553
554void increase_vibrato_rate(float change) { vibrato_rate *= change; }
555
556void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
557
558# ifdef VIBRATO_STRENGTH_ENABLE
559
560void set_vibrato_strength(float strength) { vibrato_strength = strength; }
561
562void increase_vibrato_strength(float change) { vibrato_strength *= change; }
563
564void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
565
566# endif /* VIBRATO_STRENGTH_ENABLE */
567
568#endif /* VIBRATO_ENABLE */
569
570// Polyphony functions
571
572void set_polyphony_rate(float rate) { polyphony_rate = rate; }
573
574void enable_polyphony() { polyphony_rate = 5; }
575
576void disable_polyphony() { polyphony_rate = 0; }
577
578void increase_polyphony_rate(float change) { polyphony_rate *= change; }
579
580void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
581
582// Timbre function
583
584void set_timbre(float timbre) { note_timbre = timbre; }
585
586// Tempo functions
587
588void set_tempo(uint8_t tempo) { note_tempo = tempo; }
589
590void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
591
592void increase_tempo(uint8_t tempo_change) {
593 if (note_tempo - tempo_change < 10) {
594 note_tempo = 10;
595 } else {
596 note_tempo -= tempo_change;
597 }
598}
599
600//------------------------------------------------------------------------------
601// Override these functions in your keymap file to play different tunes on
602// startup and bootloader jump
603__attribute__((weak)) void play_startup_tone() {}
604
605__attribute__((weak)) void play_goodbye_tone() {}
606//------------------------------------------------------------------------------
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..9a1c9a8c1
--- /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 0ba572c34..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,12 +14,11 @@
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
20#ifndef TEMPO_DEFAULT 19#ifndef TEMPO_DEFAULT
21# define TEMPO_DEFAULT 100 20# define TEMPO_DEFAULT 120
21// in beats-per-minute
22#endif 22#endif
23 23
24#define SONG(notes...) \ 24#define SONG(notes...) \
@@ -27,12 +27,14 @@
27// Note Types 27// Note Types
28#define MUSICAL_NOTE(note, duration) \ 28#define MUSICAL_NOTE(note, duration) \
29 { (NOTE##note), duration } 29 { (NOTE##note), duration }
30
30#define BREVE_NOTE(note) MUSICAL_NOTE(note, 128) 31#define BREVE_NOTE(note) MUSICAL_NOTE(note, 128)
31#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64) 32#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64)
32#define HALF_NOTE(note) MUSICAL_NOTE(note, 32) 33#define HALF_NOTE(note) MUSICAL_NOTE(note, 32)
33#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16) 34#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16)
34#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8) 35#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8)
35#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)
36 38
37#define BREVE_DOT_NOTE(note) MUSICAL_NOTE(note, 128 + 64) 39#define BREVE_DOT_NOTE(note) MUSICAL_NOTE(note, 128 + 64)
38#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64 + 32) 40#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64 + 32)
@@ -40,6 +42,9 @@
40#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16 + 8) 42#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16 + 8)
41#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8 + 4) 43#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8 + 4)
42#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
43 48
44// Note Type Shortcuts 49// Note Type Shortcuts
45#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration) 50#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration)
@@ -49,56 +54,52 @@
49#define Q__NOTE(n) QUARTER_NOTE(n) 54#define Q__NOTE(n) QUARTER_NOTE(n)
50#define E__NOTE(n) EIGHTH_NOTE(n) 55#define E__NOTE(n) EIGHTH_NOTE(n)
51#define S__NOTE(n) SIXTEENTH_NOTE(n) 56#define S__NOTE(n) SIXTEENTH_NOTE(n)
57#define T__NOTE(n) THIRTYSECOND_NOTE(n)
52#define BD_NOTE(n) BREVE_DOT_NOTE(n) 58#define BD_NOTE(n) BREVE_DOT_NOTE(n)
53#define WD_NOTE(n) WHOLE_DOT_NOTE(n) 59#define WD_NOTE(n) WHOLE_DOT_NOTE(n)
54#define HD_NOTE(n) HALF_DOT_NOTE(n) 60#define HD_NOTE(n) HALF_DOT_NOTE(n)
55#define QD_NOTE(n) QUARTER_DOT_NOTE(n) 61#define QD_NOTE(n) QUARTER_DOT_NOTE(n)
56#define ED_NOTE(n) EIGHTH_DOT_NOTE(n) 62#define ED_NOTE(n) EIGHTH_DOT_NOTE(n)
57#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)
58 65
59// Note Timbre 66// Note Timbre
60// Changes how the notes sound 67// Changes how the notes sound
61#define TIMBRE_12 0.125f 68#define TIMBRE_12 12
62#define TIMBRE_25 0.250f 69#define TIMBRE_25 25
63#define TIMBRE_50 0.500f 70#define TIMBRE_50 50
64#define TIMBRE_75 0.750f 71#define TIMBRE_75 75
65#ifndef TIMBRE_DEFAULT 72#ifndef TIMBRE_DEFAULT
66# define TIMBRE_DEFAULT TIMBRE_50 73# define TIMBRE_DEFAULT TIMBRE_50
67#endif 74#endif
68// Notes - # = Octave
69 75
70#ifdef __arm__ 76// Notes - # = Octave
71# define NOTE_REST 1.00f
72#else
73# define NOTE_REST 0.00f
74#endif
75 77
76/* These notes are currently bugged 78#define NOTE_REST 0.00f
77#define NOTE_C0 16.35f
78#define NOTE_CS0 17.32f
79#define NOTE_D0 18.35f
80#define NOTE_DS0 19.45f
81#define NOTE_E0 20.60f
82#define NOTE_F0 21.83f
83#define NOTE_FS0 23.12f
84#define NOTE_G0 24.50f
85#define NOTE_GS0 25.96f
86#define NOTE_A0 27.50f
87#define NOTE_AS0 29.14f
88#define NOTE_B0 30.87f
89#define NOTE_C1 32.70f
90#define NOTE_CS1 34.65f
91#define NOTE_D1 36.71f
92#define NOTE_DS1 38.89f
93#define NOTE_E1 41.20f
94#define NOTE_F1 43.65f
95#define NOTE_FS1 46.25f
96#define NOTE_G1 49.00f
97#define NOTE_GS1 51.91f
98#define NOTE_A1 55.00f
99#define NOTE_AS1 58.27f
100*/
101 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
102#define NOTE_B1 61.74f 103#define NOTE_B1 61.74f
103#define NOTE_C2 65.41f 104#define NOTE_C2 65.41f
104#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};