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.h280
-rw-r--r--quantum/audio/audio_avr.c810
-rw-r--r--quantum/audio/audio_chibios.c702
-rw-r--r--quantum/audio/audio_pwm.c595
-rw-r--r--quantum/audio/driver_avr_pwm.h17
-rw-r--r--quantum/audio/driver_avr_pwm_hardware.c322
-rw-r--r--quantum/audio/driver_chibios_dac.h126
-rw-r--r--quantum/audio/driver_chibios_dac_additive.c335
-rw-r--r--quantum/audio/driver_chibios_dac_basic.c245
-rw-r--r--quantum/audio/driver_chibios_pwm.h40
-rw-r--r--quantum/audio/driver_chibios_pwm_hardware.c144
-rw-r--r--quantum/audio/driver_chibios_pwm_software.c164
-rw-r--r--quantum/audio/musical_notes.h82
-rw-r--r--quantum/audio/voices.c170
-rw-r--r--quantum/audio/voices.h21
-rw-r--r--quantum/audio/wave.h36
17 files changed, 2341 insertions, 2287 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
new file mode 100644
index 000000000..46277dd70
--- /dev/null
+++ b/quantum/audio/audio.c
@@ -0,0 +1,539 @@
1/* Copyright 2016-2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#include "audio.h"
18#include "eeconfig.h"
19#include "timer.h"
20#include "wait.h"
21
22/* audio system:
23 *
24 * audio.[ch] takes care of all overall state, tracking the actively playing
25 * notes/tones; the notes a SONG consists of;
26 * ...
27 * = everything audio-related that is platform agnostic
28 *
29 * driver_[avr|chibios]_[dac|pwm] take care of the lower hardware dependent parts,
30 * specific to each platform and the used subsystem/driver to drive
31 * the output pins/channels with the calculated frequencies for each
32 * active tone
33 * as part of this, the driver has to trigger regular state updates by
34 * calling 'audio_update_state' through some sort of timer - be it a
35 * dedicated one or piggybacking on for example the timer used to
36 * generate a pwm signal/clock.
37 *
38 *
39 * A Note on terminology:
40 * tone, pitch and frequency are used somewhat interchangeably, in a strict Wikipedia-sense:
41 * "(Musical) tone, a sound characterized by its duration, pitch (=frequency),
42 * intensity (=volume), and timbre"
43 * - intensity/volume is currently not handled at all, although the 'dac_additive' driver could do so
44 * - timbre is handled globally (TODO: only used with the pwm drivers at the moment)
45 *
46 * in musical_note.h a 'note' is the combination of a pitch and a duration
47 * these are used to create SONG arrays; during playback their frequencies
48 * are handled as single successive tones, while the durations are
49 * kept track of in 'audio_update_state'
50 *
51 * 'voice' as it is used here, equates to a sort of instrument with its own
52 * characteristics sound and effects
53 * the audio system as-is deals only with (possibly multiple) tones of one
54 * instrument/voice at a time (think: chords). since the number of tones that
55 * can be reproduced depends on the hardware/driver in use: pwm can only
56 * reproduce one tone per output/speaker; DACs can reproduce/mix multiple
57 * when doing additive synthesis.
58 *
59 * 'duration' can either be in the beats-per-minute related unit found in
60 * musical_notes.h, OR in ms; keyboards create SONGs with the former, while
61 * the internal state of the audio system does its calculations with the later - ms
62 */
63
64#ifndef AUDIO_TONE_STACKSIZE
65# define AUDIO_TONE_STACKSIZE 8
66#endif
67uint8_t active_tones = 0; // number of tones pushed onto the stack by audio_play_tone - might be more than the hardware is able to reproduce at any single time
68musical_tone_t tones[AUDIO_TONE_STACKSIZE]; // stack of currently active tones
69
70bool playing_melody = false; // playing a SONG?
71bool playing_note = false; // or (possibly multiple simultaneous) tones
72bool state_changed = false; // global flag, which is set if anything changes with the active_tones
73
74// melody/SONG related state variables
75float (*notes_pointer)[][2]; // SONG, an array of MUSICAL_NOTEs
76uint16_t notes_count; // length of the notes_pointer array
77bool notes_repeat; // PLAY_SONG or PLAY_LOOP?
78uint16_t melody_current_note_duration = 0; // duration of the currently playing note from the active melody, in ms
79uint8_t note_tempo = TEMPO_DEFAULT; // beats-per-minute
80uint16_t current_note = 0; // index into the array at notes_pointer
81bool note_resting = false; // if a short pause was introduced between two notes with the same frequency while playing a melody
82uint16_t last_timestamp = 0;
83
84#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
85# ifndef AUDIO_MAX_SIMULTANEOUS_TONES
86# define AUDIO_MAX_SIMULTANEOUS_TONES 3
87# endif
88uint16_t tone_multiplexing_rate = AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT;
89uint8_t tone_multiplexing_index_shift = 0; // offset used on active-tone array access
90#endif
91
92// provided and used by voices.c
93extern uint8_t note_timbre;
94extern bool glissando;
95extern bool vibrato;
96extern uint16_t voices_timer;
97
98#ifndef STARTUP_SONG
99# define STARTUP_SONG SONG(STARTUP_SOUND)
100#endif
101#ifndef AUDIO_ON_SONG
102# define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND)
103#endif
104#ifndef AUDIO_OFF_SONG
105# define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND)
106#endif
107float startup_song[][2] = STARTUP_SONG;
108float audio_on_song[][2] = AUDIO_ON_SONG;
109float audio_off_song[][2] = AUDIO_OFF_SONG;
110
111static bool audio_initialized = false;
112static bool audio_driver_stopped = true;
113audio_config_t audio_config;
114
115void audio_init() {
116 if (audio_initialized) {
117 return;
118 }
119
120 // Check EEPROM
121#ifdef EEPROM_ENABLE
122 if (!eeconfig_is_enabled()) {
123 eeconfig_init();
124 }
125 audio_config.raw = eeconfig_read_audio();
126#else // EEPROM settings
127 audio_config.enable = true;
128# ifdef AUDIO_CLICKY_ON
129 audio_config.clicky_enable = true;
130# endif
131#endif // EEPROM settings
132
133 for (uint8_t i = 0; i < AUDIO_TONE_STACKSIZE; i++) {
134 tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
135 }
136
137 if (!audio_initialized) {
138 audio_driver_initialize();
139 audio_initialized = true;
140 }
141 stop_all_notes();
142}
143
144void audio_startup(void) {
145 if (audio_config.enable) {
146 PLAY_SONG(startup_song);
147 }
148
149 last_timestamp = timer_read();
150}
151
152void audio_toggle(void) {
153 if (audio_config.enable) {
154 stop_all_notes();
155 }
156 audio_config.enable ^= 1;
157 eeconfig_update_audio(audio_config.raw);
158 if (audio_config.enable) {
159 audio_on_user();
160 }
161}
162
163void audio_on(void) {
164 audio_config.enable = 1;
165 eeconfig_update_audio(audio_config.raw);
166 audio_on_user();
167 PLAY_SONG(audio_on_song);
168}
169
170void audio_off(void) {
171 PLAY_SONG(audio_off_song);
172 wait_ms(100);
173 audio_stop_all();
174 audio_config.enable = 0;
175 eeconfig_update_audio(audio_config.raw);
176}
177
178bool audio_is_on(void) { return (audio_config.enable != 0); }
179
180void audio_stop_all() {
181 if (audio_driver_stopped) {
182 return;
183 }
184
185 active_tones = 0;
186
187 audio_driver_stop();
188
189 playing_melody = false;
190 playing_note = false;
191
192 melody_current_note_duration = 0;
193
194 for (uint8_t i = 0; i < AUDIO_TONE_STACKSIZE; i++) {
195 tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
196 }
197
198 audio_driver_stopped = true;
199}
200
201void audio_stop_tone(float pitch) {
202 if (pitch < 0.0f) {
203 pitch = -1 * pitch;
204 }
205
206 if (playing_note) {
207 if (!audio_initialized) {
208 audio_init();
209 }
210 bool found = false;
211 for (int i = AUDIO_TONE_STACKSIZE - 1; i >= 0; i--) {
212 found = (tones[i].pitch == pitch);
213 if (found) {
214 tones[i] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
215 for (int j = i; (j < AUDIO_TONE_STACKSIZE - 1); j++) {
216 tones[j] = tones[j + 1];
217 tones[j + 1] = (musical_tone_t){.time_started = 0, .pitch = -1.0f, .duration = 0};
218 }
219 break;
220 }
221 }
222 if (!found) {
223 return;
224 }
225
226 state_changed = true;
227 active_tones--;
228 if (active_tones < 0) active_tones = 0;
229#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
230 if (tone_multiplexing_index_shift >= active_tones) {
231 tone_multiplexing_index_shift = 0;
232 }
233#endif
234 if (active_tones == 0) {
235 audio_driver_stop();
236 audio_driver_stopped = true;
237 playing_note = false;
238 }
239 }
240}
241
242void audio_play_note(float pitch, uint16_t duration) {
243 if (!audio_config.enable) {
244 return;
245 }
246
247 if (!audio_initialized) {
248 audio_init();
249 }
250
251 if (pitch < 0.0f) {
252 pitch = -1 * pitch;
253 }
254
255 // round-robin: shifting out old tones, keeping only unique ones
256 // if the new frequency is already amongst the active tones, shift it to the top of the stack
257 bool found = false;
258 for (int i = active_tones - 1; i >= 0; i--) {
259 found = (tones[i].pitch == pitch);
260 if (found) {
261 for (int j = i; (j < active_tones - 1); j++) {
262 tones[j] = tones[j + 1];
263 tones[j + 1] = (musical_tone_t){.time_started = timer_read(), .pitch = pitch, .duration = duration};
264 }
265 return; // since this frequency played already, the hardware was already started
266 }
267 }
268
269 // frequency/tone is actually new, so we put it on the top of the stack
270 active_tones++;
271 if (active_tones > AUDIO_TONE_STACKSIZE) {
272 active_tones = AUDIO_TONE_STACKSIZE;
273 // shift out the oldest tone to make room
274 for (int i = 0; i < active_tones - 1; i++) {
275 tones[i] = tones[i + 1];
276 }
277 }
278 state_changed = true;
279 playing_note = true;
280 tones[active_tones - 1] = (musical_tone_t){.time_started = timer_read(), .pitch = pitch, .duration = duration};
281
282 // TODO: needs to be handled per note/tone -> use its timestamp instead?
283 voices_timer = timer_read(); // reset to zero, for the effects added by voices.c
284
285 if (audio_driver_stopped) {
286 audio_driver_start();
287 audio_driver_stopped = false;
288 }
289}
290
291void audio_play_tone(float pitch) { audio_play_note(pitch, 0xffff); }
292
293void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat) {
294 if (!audio_config.enable) {
295 audio_stop_all();
296 return;
297 }
298
299 if (!audio_initialized) {
300 audio_init();
301 }
302
303 // Cancel note if a note is playing
304 if (playing_note) audio_stop_all();
305
306 playing_melody = true;
307 note_resting = false;
308
309 notes_pointer = np;
310 notes_count = n_count;
311 notes_repeat = n_repeat;
312
313 current_note = 0; // note in the melody-array/list at note_pointer
314
315 // start first note manually, which also starts the audio_driver
316 // all following/remaining notes are played by 'audio_update_state'
317 audio_play_note((*notes_pointer)[current_note][0], audio_duration_to_ms((*notes_pointer)[current_note][1]));
318 last_timestamp = timer_read();
319 melody_current_note_duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
320}
321
322float click[2][2];
323void audio_play_click(uint16_t delay, float pitch, uint16_t duration) {
324 uint16_t duration_tone = audio_ms_to_duration(duration);
325 uint16_t duration_delay = audio_ms_to_duration(delay);
326
327 if (delay <= 0.0f) {
328 click[0][0] = pitch;
329 click[0][1] = duration_tone;
330 click[1][0] = 0.0f;
331 click[1][1] = 0.0f;
332 audio_play_melody(&click, 1, false);
333 } else {
334 // first note is a rest/pause
335 click[0][0] = 0.0f;
336 click[0][1] = duration_delay;
337 // second note is the actual click
338 click[1][0] = pitch;
339 click[1][1] = duration_tone;
340 audio_play_melody(&click, 2, false);
341 }
342}
343
344bool audio_is_playing_note(void) { return playing_note; }
345
346bool audio_is_playing_melody(void) { return playing_melody; }
347
348uint8_t audio_get_number_of_active_tones(void) { return active_tones; }
349
350float audio_get_frequency(uint8_t tone_index) {
351 if (tone_index >= active_tones) {
352 return 0.0f;
353 }
354 return tones[active_tones - tone_index - 1].pitch;
355}
356
357float audio_get_processed_frequency(uint8_t tone_index) {
358 if (tone_index >= active_tones) {
359 return 0.0f;
360 }
361
362 int8_t index = active_tones - tone_index - 1;
363 // new tones are stacked on top (= appended at the end), so the most recent/current is MAX-1
364
365#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
366 index = index - tone_multiplexing_index_shift;
367 if (index < 0) // wrap around
368 index += active_tones;
369#endif
370
371 if (tones[index].pitch <= 0.0f) {
372 return 0.0f;
373 }
374
375 return voice_envelope(tones[index].pitch);
376}
377
378bool audio_update_state(void) {
379 if (!playing_note && !playing_melody) {
380 return false;
381 }
382
383 bool goto_next_note = false;
384 uint16_t current_time = timer_read();
385
386 if (playing_melody) {
387 goto_next_note = timer_elapsed(last_timestamp) >= melody_current_note_duration;
388 if (goto_next_note) {
389 uint16_t delta = timer_elapsed(last_timestamp) - melody_current_note_duration;
390 last_timestamp = current_time;
391 uint16_t previous_note = current_note;
392 current_note++;
393 voices_timer = timer_read(); // reset to zero, for the effects added by voices.c
394
395 if (current_note >= notes_count) {
396 if (notes_repeat) {
397 current_note = 0;
398 } else {
399 audio_stop_all();
400 return false;
401 }
402 }
403
404 if (!note_resting && (*notes_pointer)[previous_note][0] == (*notes_pointer)[current_note][0]) {
405 note_resting = true;
406
407 // special handling for successive notes of the same frequency:
408 // insert a short pause to separate them audibly
409 audio_play_note(0.0f, audio_duration_to_ms(2));
410 current_note = previous_note;
411 melody_current_note_duration = audio_duration_to_ms(2);
412
413 } else {
414 note_resting = false;
415
416 // TODO: handle glissando here (or remember previous and current tone)
417 /* there would need to be a freq(here we are) -> freq(next note)
418 * and do slide/glissando in between problem here is to know which
419 * frequency on the stack relates to what other? e.g. a melody starts
420 * tones in a sequence, and stops expiring one, so the most recently
421 * stopped is the starting point for a glissando to the most recently started?
422 * how to detect and preserve this relation?
423 * and what about user input, chords, ...?
424 */
425
426 // '- delta': Skip forward in the next note's length if we've over shot
427 // the last, so the overall length of the song is the same
428 uint16_t duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
429
430 // Skip forward past any completely missed notes
431 while (delta > duration && current_note < notes_count - 1) {
432 delta -= duration;
433 current_note++;
434 duration = audio_duration_to_ms((*notes_pointer)[current_note][1]);
435 }
436
437 if (delta < duration) {
438 duration -= delta;
439 } else {
440 // Only way to get here is if it is the last note and
441 // we have completely missed it. Play it for 1ms...
442 duration = 1;
443 }
444
445 audio_play_note((*notes_pointer)[current_note][0], duration);
446 melody_current_note_duration = duration;
447 }
448 }
449 }
450
451 if (playing_note) {
452#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
453 tone_multiplexing_index_shift = (int)(current_time / tone_multiplexing_rate) % MIN(AUDIO_MAX_SIMULTANEOUS_TONES, active_tones);
454 goto_next_note = true;
455#endif
456 if (vibrato || glissando) {
457 // force update on each cycle, since vibrato shifts the frequency slightly
458 goto_next_note = true;
459 }
460
461 // housekeeping: stop notes that have no playtime left
462 for (int i = 0; i < active_tones; i++) {
463 if ((tones[i].duration != 0xffff) // indefinitely playing notes, started by 'audio_play_tone'
464 && (tones[i].duration != 0) // 'uninitialized'
465 ) {
466 if (timer_elapsed(tones[i].time_started) >= tones[i].duration) {
467 audio_stop_tone(tones[i].pitch); // also sets 'state_changed=true'
468 }
469 }
470 }
471 }
472
473 // state-changes have a higher priority, always triggering the hardware to update
474 if (state_changed) {
475 state_changed = false;
476 return true;
477 }
478
479 return goto_next_note;
480}
481
482// Tone-multiplexing functions
483#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
484void audio_set_tone_multiplexing_rate(uint16_t rate) { tone_multiplexing_rate = rate; }
485void audio_enable_tone_multiplexing(void) { tone_multiplexing_rate = AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT; }
486void audio_disable_tone_multiplexing(void) { tone_multiplexing_rate = 0; }
487void audio_increase_tone_multiplexing_rate(uint16_t change) {
488 if ((0xffff - change) > tone_multiplexing_rate) {
489 tone_multiplexing_rate += change;
490 }
491}
492void audio_decrease_tone_multiplexing_rate(uint16_t change) {
493 if (change <= tone_multiplexing_rate) {
494 tone_multiplexing_rate -= change;
495 }
496}
497#endif
498
499// Tempo functions
500
501void audio_set_tempo(uint8_t tempo) {
502 if (tempo < 10) note_tempo = 10;
503 // else if (tempo > 250)
504 // note_tempo = 250;
505 else
506 note_tempo = tempo;
507}
508
509void audio_increase_tempo(uint8_t tempo_change) {
510 if (tempo_change > 255 - note_tempo)
511 note_tempo = 255;
512 else
513 note_tempo += tempo_change;
514}
515
516void audio_decrease_tempo(uint8_t tempo_change) {
517 if (tempo_change >= note_tempo - 10)
518 note_tempo = 10;
519 else
520 note_tempo -= tempo_change;
521}
522
523// TODO in the int-math version are some bugs; songs sometimes abruptly end - maybe an issue with the timer/system-tick wrapping around?
524uint16_t audio_duration_to_ms(uint16_t duration_bpm) {
525#if defined(__AVR__)
526 // doing int-math saves us some bytes in the overall firmware size, but the intermediate result is less accurate before being cast to/returned as uint
527 return ((uint32_t)duration_bpm * 60 * 1000) / (64 * note_tempo);
528 // NOTE: beware of uint16_t overflows when note_tempo is low and/or the duration is long
529#else
530 return ((float)duration_bpm * 60) / (64 * note_tempo) * 1000;
531#endif
532}
533uint16_t audio_ms_to_duration(uint16_t duration_ms) {
534#if defined(__AVR__)
535 return ((uint32_t)duration_ms * 64 * note_tempo) / 60 / 1000;
536#else
537 return ((float)duration_ms * 64 * note_tempo) / 60 / 1000;
538#endif
539}
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
index bc00cd19e..56b9158a1 100644
--- a/quantum/audio/audio.h
+++ b/quantum/audio/audio.h
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016-2020 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
@@ -13,28 +14,30 @@
13 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 16 */
16
17#pragma once 17#pragma once
18 18
19#include <stdint.h> 19#include <stdint.h>
20#include <stdbool.h> 20#include <stdbool.h>
21#if defined(__AVR__)
22# include <avr/io.h>
23#endif
24#include "wait.h"
25#include "musical_notes.h" 21#include "musical_notes.h"
26#include "song_list.h" 22#include "song_list.h"
27#include "voices.h" 23#include "voices.h"
28#include "quantum.h" 24#include "quantum.h"
29#include <math.h> 25#include <math.h>
30 26
31// Largely untested PWM audio mode (doesn't sound as good) 27#if defined(__AVR__)
32// #define PWM_AUDIO 28# include <avr/io.h>
33 29# if defined(AUDIO_DRIVER_PWM)
34// #define VIBRATO_ENABLE 30# include "driver_avr_pwm.h"
31# endif
32#endif
35 33
36// Enable vibrato strength/amplitude - slows down ISR too much 34#if defined(PROTOCOL_CHIBIOS)
37// #define VIBRATO_STRENGTH_ENABLE 35# if defined(AUDIO_DRIVER_PWM)
36# include "driver_chibios_pwm.h"
37# elif defined(AUDIO_DRIVER_DAC)
38# include "driver_chibios_dac.h"
39# endif
40#endif
38 41
39typedef union { 42typedef union {
40 uint8_t raw; 43 uint8_t raw;
@@ -45,61 +48,238 @@ typedef union {
45 }; 48 };
46} audio_config_t; 49} audio_config_t;
47 50
48bool is_audio_on(void); 51// AVR/LUFA has a MIN, arm/chibios does not
52#ifndef MIN
53# define MIN(a, b) (((a) < (b)) ? (a) : (b))
54#endif
55
56/*
57 * a 'musical note' is represented by pitch and duration; a 'musical tone' adds intensity and timbre
58 * https://en.wikipedia.org/wiki/Musical_tone
59 * "A musical tone is characterized by its duration, pitch, intensity (or loudness), and timbre (or quality)"
60 */
61typedef struct {
62 uint16_t time_started; // timestamp the tone/note was started, system time runs with 1ms resolution -> 16bit timer overflows every ~64 seconds, long enough under normal circumstances; but might be too soon for long-duration notes when the note_tempo is set to a very low value
63 float pitch; // aka frequency, in Hz
64 uint16_t duration; // in ms, converted from the musical_notes.h unit which has 64parts to a beat, factoring in the current tempo in beats-per-minute
65 // float intensity; // aka volume [0,1] TODO: not used at the moment; pwm drivers can't handle it
66 // uint8_t timbre; // range: [0,100] TODO: this currently kept track of globally, should we do this per tone instead?
67} musical_tone_t;
68
69// public interface
70
71/**
72 * @brief one-time initialization called by quantum/quantum.c
73 * @details usually done lazy, when some tones are to be played
74 *
75 * @post audio system (and hardware) initialized and ready to play tones
76 */
77void audio_init(void);
78void audio_startup(void);
79
80/**
81 * @brief en-/disable audio output, save this choice to the eeprom
82 */
49void audio_toggle(void); 83void audio_toggle(void);
84/**
85 * @brief enable audio output, save this choice to the eeprom
86 */
50void audio_on(void); 87void audio_on(void);
88/**
89 * @brief disable audio output, save this choice to the eeprom
90 */
51void audio_off(void); 91void audio_off(void);
92/**
93 * @brief query the if audio output is enabled
94 */
95bool audio_is_on(void);
96
97/**
98 * @brief start playback of a tone with the given frequency and duration
99 *
100 * @details starts the playback of a given note, which is automatically stopped
101 * at the the end of its duration = fire&forget
102 *
103 * @param[in] pitch frequency of the tone be played
104 * @param[in] duration in milliseconds, use 'audio_duration_to_ms' to convert
105 * from the musical_notes.h unit to ms
106 */
107void audio_play_note(float pitch, uint16_t duration);
108// TODO: audio_play_note(float pitch, uint16_t duration, float intensity, float timbre);
109// audio_play_note_with_instrument ifdef AUDIO_ENABLE_VOICES
110
111/**
112 * @brief start playback of a tone with the given frequency
113 *
114 * @details the 'frequency' is put on-top the internal stack of active tones,
115 * as a new tone with indefinite duration. this tone is played by
116 * the hardware until a call to 'audio_stop_tone'.
117 * should a tone with that frequency already be active, its entry
118 * is put on the top of said internal stack - so no duplicate
119 * entries are kept.
120 * 'hardware_start' is called upon the first note.
121 *
122 * @param[in] pitch frequency of the tone be played
123 */
124void audio_play_tone(float pitch);
125
126/**
127 * @brief stop a given tone/frequency
128 *
129 * @details removes a tone matching the given frequency from the internal
130 * playback stack
131 * the hardware is stopped in case this was the last/only frequency
132 * being played.
133 *
134 * @param[in] pitch tone/frequency to be stopped
135 */
136void audio_stop_tone(float pitch);
52 137
53// Vibrato rate functions 138/**
139 * @brief play a melody
140 *
141 * @details starts playback of a melody passed in from a SONG definition - an
142 * array of {pitch, duration} float-tuples
143 *
144 * @param[in] np note-pointer to the SONG array
145 * @param[in] n_count number of MUSICAL_NOTES of the SONG
146 * @param[in] n_repeat false for onetime, true for looped playback
147 */
148void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat);
54 149
55#ifdef VIBRATO_ENABLE 150/**
151 * @brief play a short tone of a specific frequency to emulate a 'click'
152 *
153 * @details constructs a two-note melody (one pause plus a note) and plays it through
154 * audio_play_melody. very short durations might not quite work due to
155 * hardware limitations (DAC: added pulses from zero-crossing feature;...)
156 *
157 * @param[in] delay in milliseconds, length for the pause before the pulses, can be zero
158 * @param[in] pitch
159 * @param[in] duration in milliseconds, length of the 'click'
160 */
161void audio_play_click(uint16_t delay, float pitch, uint16_t duration);
56 162
57void set_vibrato_rate(float rate); 163/**
58void increase_vibrato_rate(float change); 164 * @brief stops all playback
59void decrease_vibrato_rate(float change); 165 *
166 * @details stops playback of both a melody as well as single tones, resetting
167 * the internal state
168 */
169void audio_stop_all(void);
60 170
61# ifdef VIBRATO_STRENGTH_ENABLE 171/**
172 * @brief query if one/multiple tones are playing
173 */
174bool audio_is_playing_note(void);
62 175
63void set_vibrato_strength(float strength); 176/**
64void increase_vibrato_strength(float change); 177 * @brief query if a melody/SONG is playing
65void decrease_vibrato_strength(float change); 178 */
179bool audio_is_playing_melody(void);
66 180
67# endif 181// These macros are used to allow audio_play_melody to play an array of indeterminate
182// length. This works around the limitation of C's sizeof operation on pointers.
183// The global float array for the song must be used here.
184#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
185
186/**
187 * @brief convenience macro, to play a melody/SONG once
188 */
189#define PLAY_SONG(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), false)
190// TODO: a 'song' is a melody plus singing/vocals -> PLAY_MELODY
191/**
192 * @brief convenience macro, to play a melody/SONG in a loop, until stopped by 'audio_stop_all'
193 */
194#define PLAY_LOOP(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), true)
68 195
196// Tone-Multiplexing functions
197// this feature only makes sense for hardware setups which can't do proper
198// audio-wave synthesis = have no DAC and need to use PWM for tone generation
199#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
200# ifndef AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT
201# define AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 0
202// 0=off, good starting value is 4; the lower the value the higher the cpu-load
203# endif
204void audio_set_tone_multiplexing_rate(uint16_t rate);
205void audio_enable_tone_multiplexing(void);
206void audio_disable_tone_multiplexing(void);
207void audio_increase_tone_multiplexing_rate(uint16_t change);
208void audio_decrease_tone_multiplexing_rate(uint16_t change);
69#endif 209#endif
70 210
71// Polyphony functions 211// Tempo functions
72 212
73void set_polyphony_rate(float rate); 213void audio_set_tempo(uint8_t tempo);
74void enable_polyphony(void); 214void audio_increase_tempo(uint8_t tempo_change);
75void disable_polyphony(void); 215void audio_decrease_tempo(uint8_t tempo_change);
76void increase_polyphony_rate(float change);
77void decrease_polyphony_rate(float change);
78 216
79void set_timbre(float timbre); 217// conversion macros, from 64parts-to-a-beat to milliseconds and back
80void set_tempo(uint8_t tempo); 218uint16_t audio_duration_to_ms(uint16_t duration_bpm);
219uint16_t audio_ms_to_duration(uint16_t duration_ms);
81 220
82void increase_tempo(uint8_t tempo_change); 221void audio_startup(void);
83void decrease_tempo(uint8_t tempo_change);
84 222
85void audio_init(void); 223// hardware interface
86 224
87#ifdef PWM_AUDIO 225// implementation in the driver_avr/arm_* respective parts
88void play_sample(uint8_t* s, uint16_t l, bool r); 226void audio_driver_initialize(void);
89#endif 227void audio_driver_start(void);
90void play_note(float freq, int vol); 228void audio_driver_stop(void);
91void stop_note(float freq);
92void stop_all_notes(void);
93void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat);
94 229
95#define SCALE \ 230/**
96 (int8_t[]) { 0 + (12 * 0), 2 + (12 * 0), 4 + (12 * 0), 5 + (12 * 0), 7 + (12 * 0), 9 + (12 * 0), 11 + (12 * 0), 0 + (12 * 1), 2 + (12 * 1), 4 + (12 * 1), 5 + (12 * 1), 7 + (12 * 1), 9 + (12 * 1), 11 + (12 * 1), 0 + (12 * 2), 2 + (12 * 2), 4 + (12 * 2), 5 + (12 * 2), 7 + (12 * 2), 9 + (12 * 2), 11 + (12 * 2), 0 + (12 * 3), 2 + (12 * 3), 4 + (12 * 3), 5 + (12 * 3), 7 + (12 * 3), 9 + (12 * 3), 11 + (12 * 3), 0 + (12 * 4), 2 + (12 * 4), 4 + (12 * 4), 5 + (12 * 4), 7 + (12 * 4), 9 + (12 * 4), 11 + (12 * 4), } 231 * @brief get the number of currently active tones
232 * @return number, 0=none active
233 */
234uint8_t audio_get_number_of_active_tones(void);
97 235
98// These macros are used to allow play_notes to play an array of indeterminate 236/**
99// length. This works around the limitation of C's sizeof operation on pointers. 237 * @brief access to the raw/unprocessed frequency for a specific tone
100// The global float array for the song must be used here. 238 * @details each active tone has a frequency associated with it, which
101#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) 239 * the internal state keeps track of, and is usually influenced
102#define PLAY_SONG(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), false) 240 * by various effects
103#define PLAY_LOOP(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), true) 241 * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
242 * first being the most recent and each increment yielding the next
243 * older one
244 * @return a positive frequency, in Hz; or zero if the tone is a pause
245 */
246float audio_get_frequency(uint8_t tone_index);
247
248/**
249 * @brief calculate and return the frequency for the requested tone
250 * @details effects like glissando, vibrato, ... are post-processed onto the
251 * each active tones 'base'-frequency; this function returns the
252 * post-processed result.
253 * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
254 * first being the most recent and each increment yielding the next
255 * older one
256 * @return a positive frequency, in Hz; or zero if the tone is a pause
257 */
258float audio_get_processed_frequency(uint8_t tone_index);
259
260/**
261 * @brief update audio internal state: currently playing and active tones,...
262 * @details This function is intended to be called by the audio-hardware
263 * specific implementation on a somewhat regular basis while a SONG
264 * or notes (pitch+duration) are playing to 'advance' the internal
265 * state (current playing notes, position in the melody, ...)
266 *
267 * @return true if something changed in the currently active tones, which the
268 * hardware might need to react to
269 */
270bool audio_update_state(void);
271
272// legacy and back-warts compatibility stuff
273
274#define is_audio_on() audio_is_on()
275#define is_playing_notes() audio_is_playing_melody()
276#define is_playing_note() audio_is_playing_note()
277#define stop_all_notes() audio_stop_all()
278#define stop_note(f) audio_stop_tone(f)
279#define play_note(f, v) audio_play_tone(f)
104 280
105bool is_playing_notes(void); 281#define set_timbre(t) voice_set_timbre(t)
282#define set_tempo(t) audio_set_tempo(t)
283#define increase_tempo(t) audio_increase_tempo(t)
284#define decrease_tempo(t) audio_decrease_tempo(t)
285// vibrato functions are not used in any keyboards
diff --git a/quantum/audio/audio_avr.c b/quantum/audio/audio_avr.c
deleted file mode 100644
index 5a96bf643..000000000
--- a/quantum/audio/audio_avr.c
+++ /dev/null
@@ -1,810 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <stdio.h>
18#include <string.h>
19//#include <math.h>
20#if defined(__AVR__)
21# include <avr/pgmspace.h>
22# include <avr/interrupt.h>
23# include <avr/io.h>
24#endif
25#include "print.h"
26#include "audio.h"
27#include "keymap.h"
28#include "wait.h"
29
30#include "eeconfig.h"
31
32#define CPU_PRESCALER 8
33
34// -----------------------------------------------------------------------------
35// Timer Abstractions
36// -----------------------------------------------------------------------------
37
38// Currently we support timers 1 and 3 used at the sime time, channels A-C,
39// pins PB5, PB6, PB7, PC4, PC5, and PC6
40#if defined(C6_AUDIO)
41# define CPIN_AUDIO
42# define CPIN_SET_DIRECTION DDRC |= _BV(PORTC6);
43# define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
44# define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
45# define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
46# define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
47# define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
48# define TIMER_3_PERIOD ICR3
49# define TIMER_3_DUTY_CYCLE OCR3A
50# define TIMER3_AUDIO_vect TIMER3_COMPA_vect
51#endif
52#if defined(C5_AUDIO)
53# define CPIN_AUDIO
54# define CPIN_SET_DIRECTION DDRC |= _BV(PORTC5);
55# define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3B1) | (0 << COM3B0) | (1 << WGM31) | (0 << WGM30);
56# define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3B)
57# define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3B)
58# define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3B1);
59# define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3B1) | _BV(COM3B0));
60# define TIMER_3_PERIOD ICR3
61# define TIMER_3_DUTY_CYCLE OCR3B
62# define TIMER3_AUDIO_vect TIMER3_COMPB_vect
63#endif
64#if defined(C4_AUDIO)
65# define CPIN_AUDIO
66# define CPIN_SET_DIRECTION DDRC |= _BV(PORTC4);
67# define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3C1) | (0 << COM3C0) | (1 << WGM31) | (0 << WGM30);
68# define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3C)
69# define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3C)
70# define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3C1);
71# define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3C1) | _BV(COM3C0));
72# define TIMER_3_PERIOD ICR3
73# define TIMER_3_DUTY_CYCLE OCR3C
74# define TIMER3_AUDIO_vect TIMER3_COMPC_vect
75#endif
76
77#if defined(B5_AUDIO)
78# define BPIN_AUDIO
79# define BPIN_SET_DIRECTION DDRB |= _BV(PORTB5);
80# define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << WGM11) | (0 << WGM10);
81# define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1A)
82# define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1A)
83# define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1A1);
84# define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0));
85# define TIMER_1_PERIOD ICR1
86# define TIMER_1_DUTY_CYCLE OCR1A
87# define TIMER1_AUDIO_vect TIMER1_COMPA_vect
88#endif
89#if defined(B6_AUDIO)
90# define BPIN_AUDIO
91# define BPIN_SET_DIRECTION DDRB |= _BV(PORTB6);
92# define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1B1) | (0 << COM1B0) | (1 << WGM11) | (0 << WGM10);
93# define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1B)
94# define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1B)
95# define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1B1);
96# define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1B1) | _BV(COM1B0));
97# define TIMER_1_PERIOD ICR1
98# define TIMER_1_DUTY_CYCLE OCR1B
99# define TIMER1_AUDIO_vect TIMER1_COMPB_vect
100#endif
101#if defined(B7_AUDIO)
102# define BPIN_AUDIO
103# define BPIN_SET_DIRECTION DDRB |= _BV(PORTB7);
104# define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1C1) | (0 << COM1C0) | (1 << WGM11) | (0 << WGM10);
105# define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1C)
106# define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1C)
107# define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1C1);
108# define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1C1) | _BV(COM1C0));
109# define TIMER_1_PERIOD ICR1
110# define TIMER_1_DUTY_CYCLE OCR1C
111# define TIMER1_AUDIO_vect TIMER1_COMPC_vect
112#endif
113
114#if !defined(BPIN_AUDIO) && !defined(CPIN_AUDIO)
115# error "Audio feature enabled, but no suitable pin selected - see docs/feature_audio.md under the AVR settings for available options."
116#endif
117
118// -----------------------------------------------------------------------------
119
120int voices = 0;
121int voice_place = 0;
122float frequency = 0;
123float frequency_alt = 0;
124int volume = 0;
125long position = 0;
126
127float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
128int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
129bool sliding = false;
130
131float place = 0;
132
133uint8_t* sample;
134uint16_t sample_length = 0;
135
136bool playing_notes = false;
137bool playing_note = false;
138float note_frequency = 0;
139float note_length = 0;
140uint8_t note_tempo = TEMPO_DEFAULT;
141float note_timbre = TIMBRE_DEFAULT;
142uint16_t note_position = 0;
143float (*notes_pointer)[][2];
144uint16_t notes_count;
145bool notes_repeat;
146bool note_resting = false;
147
148uint16_t current_note = 0;
149uint8_t rest_counter = 0;
150
151#ifdef VIBRATO_ENABLE
152float vibrato_counter = 0;
153float vibrato_strength = .5;
154float vibrato_rate = 0.125;
155#endif
156
157float polyphony_rate = 0;
158
159static bool audio_initialized = false;
160
161audio_config_t audio_config;
162
163uint16_t envelope_index = 0;
164bool glissando = true;
165
166#ifndef STARTUP_SONG
167# define STARTUP_SONG SONG(STARTUP_SOUND)
168#endif
169#ifndef AUDIO_ON_SONG
170# define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND)
171#endif
172#ifndef AUDIO_OFF_SONG
173# define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND)
174#endif
175float startup_song[][2] = STARTUP_SONG;
176float audio_on_song[][2] = AUDIO_ON_SONG;
177float audio_off_song[][2] = AUDIO_OFF_SONG;
178
179void audio_init() {
180 // Check EEPROM
181 if (!eeconfig_is_enabled()) {
182 eeconfig_init();
183 }
184 audio_config.raw = eeconfig_read_audio();
185
186 if (!audio_initialized) {
187// Set audio ports as output
188#ifdef CPIN_AUDIO
189 CPIN_SET_DIRECTION
190 DISABLE_AUDIO_COUNTER_3_ISR;
191#endif
192#ifdef BPIN_AUDIO
193 BPIN_SET_DIRECTION
194 DISABLE_AUDIO_COUNTER_1_ISR;
195#endif
196
197// TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
198// Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
199// OC3A -- PC6
200// OC3B -- PC5
201// OC3C -- PC4
202// OC1A -- PB5
203// OC1B -- PB6
204// OC1C -- PB7
205
206// Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
207// OCR3A - PC6
208// OCR3B - PC5
209// OCR3C - PC4
210// OCR1A - PB5
211// OCR1B - PB6
212// OCR1C - PB7
213
214// Clock Select (CS3n) = 0b010 = Clock / 8
215#ifdef CPIN_AUDIO
216 INIT_AUDIO_COUNTER_3
217 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
218 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER));
219 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre);
220#endif
221#ifdef BPIN_AUDIO
222 INIT_AUDIO_COUNTER_1
223 TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10);
224 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER));
225 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre);
226#endif
227
228 audio_initialized = true;
229 }
230
231 if (audio_config.enable) {
232 PLAY_SONG(startup_song);
233 }
234}
235
236void stop_all_notes() {
237 dprintf("audio stop all notes");
238
239 if (!audio_initialized) {
240 audio_init();
241 }
242 voices = 0;
243
244#ifdef CPIN_AUDIO
245 DISABLE_AUDIO_COUNTER_3_ISR;
246 DISABLE_AUDIO_COUNTER_3_OUTPUT;
247#endif
248
249#ifdef BPIN_AUDIO
250 DISABLE_AUDIO_COUNTER_1_ISR;
251 DISABLE_AUDIO_COUNTER_1_OUTPUT;
252#endif
253
254 playing_notes = false;
255 playing_note = false;
256 frequency = 0;
257 frequency_alt = 0;
258 volume = 0;
259
260 for (uint8_t i = 0; i < 8; i++) {
261 frequencies[i] = 0;
262 volumes[i] = 0;
263 }
264}
265
266void stop_note(float freq) {
267 dprintf("audio stop note freq=%d", (int)freq);
268
269 if (playing_note) {
270 if (!audio_initialized) {
271 audio_init();
272 }
273 for (int i = 7; i >= 0; i--) {
274 if (frequencies[i] == freq) {
275 frequencies[i] = 0;
276 volumes[i] = 0;
277 for (int j = i; (j < 7); j++) {
278 frequencies[j] = frequencies[j + 1];
279 frequencies[j + 1] = 0;
280 volumes[j] = volumes[j + 1];
281 volumes[j + 1] = 0;
282 }
283 break;
284 }
285 }
286 voices--;
287 if (voices < 0) voices = 0;
288 if (voice_place >= voices) {
289 voice_place = 0;
290 }
291 if (voices == 0) {
292#ifdef CPIN_AUDIO
293 DISABLE_AUDIO_COUNTER_3_ISR;
294 DISABLE_AUDIO_COUNTER_3_OUTPUT;
295#endif
296#ifdef BPIN_AUDIO
297 DISABLE_AUDIO_COUNTER_1_ISR;
298 DISABLE_AUDIO_COUNTER_1_OUTPUT;
299#endif
300 frequency = 0;
301 frequency_alt = 0;
302 volume = 0;
303 playing_note = false;
304 }
305 }
306}
307
308#ifdef VIBRATO_ENABLE
309
310float mod(float a, int b) {
311 float r = fmod(a, b);
312 return r < 0 ? r + b : r;
313}
314
315float vibrato(float average_freq) {
316# ifdef VIBRATO_STRENGTH_ENABLE
317 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
318# else
319 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
320# endif
321 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
322 return vibrated_freq;
323}
324
325#endif
326
327#ifdef CPIN_AUDIO
328ISR(TIMER3_AUDIO_vect) {
329 float freq;
330
331 if (playing_note) {
332 if (voices > 0) {
333# ifdef BPIN_AUDIO
334 float freq_alt = 0;
335 if (voices > 1) {
336 if (polyphony_rate == 0) {
337 if (glissando) {
338 if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) {
339 frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2);
340 } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) {
341 frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2);
342 } else {
343 frequency_alt = frequencies[voices - 2];
344 }
345 } else {
346 frequency_alt = frequencies[voices - 2];
347 }
348
349# ifdef VIBRATO_ENABLE
350 if (vibrato_strength > 0) {
351 freq_alt = vibrato(frequency_alt);
352 } else {
353 freq_alt = frequency_alt;
354 }
355# else
356 freq_alt = frequency_alt;
357# endif
358 }
359
360 if (envelope_index < 65535) {
361 envelope_index++;
362 }
363
364 freq_alt = voice_envelope(freq_alt);
365
366 if (freq_alt < 30.517578125) {
367 freq_alt = 30.52;
368 }
369
370 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq_alt * CPU_PRESCALER));
371 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq_alt * CPU_PRESCALER)) * note_timbre);
372 }
373# endif
374
375 if (polyphony_rate > 0) {
376 if (voices > 1) {
377 voice_place %= voices;
378 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
379 voice_place = (voice_place + 1) % voices;
380 place = 0.0;
381 }
382 }
383
384# ifdef VIBRATO_ENABLE
385 if (vibrato_strength > 0) {
386 freq = vibrato(frequencies[voice_place]);
387 } else {
388 freq = frequencies[voice_place];
389 }
390# else
391 freq = frequencies[voice_place];
392# endif
393 } else {
394 if (glissando) {
395 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
396 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
397 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
398 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
399 } else {
400 frequency = frequencies[voices - 1];
401 }
402 } else {
403 frequency = frequencies[voices - 1];
404 }
405
406# ifdef VIBRATO_ENABLE
407 if (vibrato_strength > 0) {
408 freq = vibrato(frequency);
409 } else {
410 freq = frequency;
411 }
412# else
413 freq = frequency;
414# endif
415 }
416
417 if (envelope_index < 65535) {
418 envelope_index++;
419 }
420
421 freq = voice_envelope(freq);
422
423 if (freq < 30.517578125) {
424 freq = 30.52;
425 }
426
427 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
428 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
429 }
430 }
431
432 if (playing_notes) {
433 if (note_frequency > 0) {
434# ifdef VIBRATO_ENABLE
435 if (vibrato_strength > 0) {
436 freq = vibrato(note_frequency);
437 } else {
438 freq = note_frequency;
439 }
440# else
441 freq = note_frequency;
442# endif
443
444 if (envelope_index < 65535) {
445 envelope_index++;
446 }
447 freq = voice_envelope(freq);
448
449 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
450 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
451 } else {
452 TIMER_3_PERIOD = 0;
453 TIMER_3_DUTY_CYCLE = 0;
454 }
455
456 note_position++;
457 bool end_of_note = false;
458 if (TIMER_3_PERIOD > 0) {
459 if (!note_resting)
460 end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF - 1));
461 else
462 end_of_note = (note_position >= (note_length));
463 } else {
464 end_of_note = (note_position >= (note_length));
465 }
466
467 if (end_of_note) {
468 current_note++;
469 if (current_note >= notes_count) {
470 if (notes_repeat) {
471 current_note = 0;
472 } else {
473 DISABLE_AUDIO_COUNTER_3_ISR;
474 DISABLE_AUDIO_COUNTER_3_OUTPUT;
475 playing_notes = false;
476 return;
477 }
478 }
479 if (!note_resting) {
480 note_resting = true;
481 current_note--;
482 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
483 note_frequency = 0;
484 note_length = 1;
485 } else {
486 note_frequency = (*notes_pointer)[current_note][0];
487 note_length = 1;
488 }
489 } else {
490 note_resting = false;
491 envelope_index = 0;
492 note_frequency = (*notes_pointer)[current_note][0];
493 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
494 }
495
496 note_position = 0;
497 }
498 }
499
500 if (!audio_config.enable) {
501 playing_notes = false;
502 playing_note = false;
503 }
504}
505#endif
506
507#ifdef BPIN_AUDIO
508ISR(TIMER1_AUDIO_vect) {
509# if defined(BPIN_AUDIO) && !defined(CPIN_AUDIO)
510 float freq = 0;
511
512 if (playing_note) {
513 if (voices > 0) {
514 if (polyphony_rate > 0) {
515 if (voices > 1) {
516 voice_place %= voices;
517 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
518 voice_place = (voice_place + 1) % voices;
519 place = 0.0;
520 }
521 }
522
523# ifdef VIBRATO_ENABLE
524 if (vibrato_strength > 0) {
525 freq = vibrato(frequencies[voice_place]);
526 } else {
527 freq = frequencies[voice_place];
528 }
529# else
530 freq = frequencies[voice_place];
531# endif
532 } else {
533 if (glissando) {
534 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
535 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
536 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
537 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
538 } else {
539 frequency = frequencies[voices - 1];
540 }
541 } else {
542 frequency = frequencies[voices - 1];
543 }
544
545# ifdef VIBRATO_ENABLE
546 if (vibrato_strength > 0) {
547 freq = vibrato(frequency);
548 } else {
549 freq = frequency;
550 }
551# else
552 freq = frequency;
553# endif
554 }
555
556 if (envelope_index < 65535) {
557 envelope_index++;
558 }
559
560 freq = voice_envelope(freq);
561
562 if (freq < 30.517578125) {
563 freq = 30.52;
564 }
565
566 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
567 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
568 }
569 }
570
571 if (playing_notes) {
572 if (note_frequency > 0) {
573# ifdef VIBRATO_ENABLE
574 if (vibrato_strength > 0) {
575 freq = vibrato(note_frequency);
576 } else {
577 freq = note_frequency;
578 }
579# else
580 freq = note_frequency;
581# endif
582
583 if (envelope_index < 65535) {
584 envelope_index++;
585 }
586 freq = voice_envelope(freq);
587
588 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
589 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
590 } else {
591 TIMER_1_PERIOD = 0;
592 TIMER_1_DUTY_CYCLE = 0;
593 }
594
595 note_position++;
596 bool end_of_note = false;
597 if (TIMER_1_PERIOD > 0) {
598 if (!note_resting)
599 end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF - 1));
600 else
601 end_of_note = (note_position >= (note_length));
602 } else {
603 end_of_note = (note_position >= (note_length));
604 }
605
606 if (end_of_note) {
607 current_note++;
608 if (current_note >= notes_count) {
609 if (notes_repeat) {
610 current_note = 0;
611 } else {
612 DISABLE_AUDIO_COUNTER_1_ISR;
613 DISABLE_AUDIO_COUNTER_1_OUTPUT;
614 playing_notes = false;
615 return;
616 }
617 }
618 if (!note_resting) {
619 note_resting = true;
620 current_note--;
621 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
622 note_frequency = 0;
623 note_length = 1;
624 } else {
625 note_frequency = (*notes_pointer)[current_note][0];
626 note_length = 1;
627 }
628 } else {
629 note_resting = false;
630 envelope_index = 0;
631 note_frequency = (*notes_pointer)[current_note][0];
632 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
633 }
634
635 note_position = 0;
636 }
637 }
638
639 if (!audio_config.enable) {
640 playing_notes = false;
641 playing_note = false;
642 }
643# endif
644}
645#endif
646
647void play_note(float freq, int vol) {
648 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
649
650 if (!audio_initialized) {
651 audio_init();
652 }
653
654 if (audio_config.enable && voices < 8) {
655#ifdef CPIN_AUDIO
656 DISABLE_AUDIO_COUNTER_3_ISR;
657#endif
658#ifdef BPIN_AUDIO
659 DISABLE_AUDIO_COUNTER_1_ISR;
660#endif
661
662 // Cancel notes if notes are playing
663 if (playing_notes) stop_all_notes();
664
665 playing_note = true;
666
667 envelope_index = 0;
668
669 if (freq > 0) {
670 frequencies[voices] = freq;
671 volumes[voices] = vol;
672 voices++;
673 }
674
675#ifdef CPIN_AUDIO
676 ENABLE_AUDIO_COUNTER_3_ISR;
677 ENABLE_AUDIO_COUNTER_3_OUTPUT;
678#endif
679#ifdef BPIN_AUDIO
680# ifdef CPIN_AUDIO
681 if (voices > 1) {
682 ENABLE_AUDIO_COUNTER_1_ISR;
683 ENABLE_AUDIO_COUNTER_1_OUTPUT;
684 }
685# else
686 ENABLE_AUDIO_COUNTER_1_ISR;
687 ENABLE_AUDIO_COUNTER_1_OUTPUT;
688# endif
689#endif
690 }
691}
692
693void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) {
694 if (!audio_initialized) {
695 audio_init();
696 }
697
698 if (audio_config.enable) {
699#ifdef CPIN_AUDIO
700 DISABLE_AUDIO_COUNTER_3_ISR;
701#endif
702#ifdef BPIN_AUDIO
703 DISABLE_AUDIO_COUNTER_1_ISR;
704#endif
705
706 // Cancel note if a note is playing
707 if (playing_note) stop_all_notes();
708
709 playing_notes = true;
710
711 notes_pointer = np;
712 notes_count = n_count;
713 notes_repeat = n_repeat;
714
715 place = 0;
716 current_note = 0;
717
718 note_frequency = (*notes_pointer)[current_note][0];
719 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
720 note_position = 0;
721
722#ifdef CPIN_AUDIO
723 ENABLE_AUDIO_COUNTER_3_ISR;
724 ENABLE_AUDIO_COUNTER_3_OUTPUT;
725#endif
726#ifdef BPIN_AUDIO
727# ifndef CPIN_AUDIO
728 ENABLE_AUDIO_COUNTER_1_ISR;
729 ENABLE_AUDIO_COUNTER_1_OUTPUT;
730# endif
731#endif
732 }
733}
734
735bool is_playing_notes(void) { return playing_notes; }
736
737bool is_audio_on(void) { return (audio_config.enable != 0); }
738
739void audio_toggle(void) {
740 audio_config.enable ^= 1;
741 eeconfig_update_audio(audio_config.raw);
742 if (audio_config.enable) audio_on_user();
743}
744
745void audio_on(void) {
746 audio_config.enable = 1;
747 eeconfig_update_audio(audio_config.raw);
748 audio_on_user();
749 PLAY_SONG(audio_on_song);
750}
751
752void audio_off(void) {
753 PLAY_SONG(audio_off_song);
754 wait_ms(100);
755 stop_all_notes();
756 audio_config.enable = 0;
757 eeconfig_update_audio(audio_config.raw);
758}
759
760#ifdef VIBRATO_ENABLE
761
762// Vibrato rate functions
763
764void set_vibrato_rate(float rate) { vibrato_rate = rate; }
765
766void increase_vibrato_rate(float change) { vibrato_rate *= change; }
767
768void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
769
770# ifdef VIBRATO_STRENGTH_ENABLE
771
772void set_vibrato_strength(float strength) { vibrato_strength = strength; }
773
774void increase_vibrato_strength(float change) { vibrato_strength *= change; }
775
776void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
777
778# endif /* VIBRATO_STRENGTH_ENABLE */
779
780#endif /* VIBRATO_ENABLE */
781
782// Polyphony functions
783
784void set_polyphony_rate(float rate) { polyphony_rate = rate; }
785
786void enable_polyphony() { polyphony_rate = 5; }
787
788void disable_polyphony() { polyphony_rate = 0; }
789
790void increase_polyphony_rate(float change) { polyphony_rate *= change; }
791
792void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
793
794// Timbre function
795
796void set_timbre(float timbre) { note_timbre = timbre; }
797
798// Tempo functions
799
800void set_tempo(uint8_t tempo) { note_tempo = tempo; }
801
802void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
803
804void increase_tempo(uint8_t tempo_change) {
805 if (note_tempo - tempo_change < 10) {
806 note_tempo = 10;
807 } else {
808 note_tempo -= tempo_change;
809 }
810}
diff --git a/quantum/audio/audio_chibios.c b/quantum/audio/audio_chibios.c
deleted file mode 100644
index 1f147f2c9..000000000
--- a/quantum/audio/audio_chibios.c
+++ /dev/null
@@ -1,702 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "audio.h"
18#include <ch.h>
19#include <hal.h>
20
21#include <string.h>
22#include "print.h"
23#include "keymap.h"
24
25#include "eeconfig.h"
26
27// -----------------------------------------------------------------------------
28
29int voices = 0;
30int voice_place = 0;
31float frequency = 0;
32float frequency_alt = 0;
33int volume = 0;
34long position = 0;
35
36float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
37int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
38bool sliding = false;
39
40float place = 0;
41
42uint8_t *sample;
43uint16_t sample_length = 0;
44
45bool playing_notes = false;
46bool playing_note = false;
47float note_frequency = 0;
48float note_length = 0;
49uint8_t note_tempo = TEMPO_DEFAULT;
50float note_timbre = TIMBRE_DEFAULT;
51uint16_t note_position = 0;
52float (*notes_pointer)[][2];
53uint16_t notes_count;
54bool notes_repeat;
55bool note_resting = false;
56
57uint16_t current_note = 0;
58uint8_t rest_counter = 0;
59
60#ifdef VIBRATO_ENABLE
61float vibrato_counter = 0;
62float vibrato_strength = .5;
63float vibrato_rate = 0.125;
64#endif
65
66float polyphony_rate = 0;
67
68static bool audio_initialized = false;
69
70audio_config_t audio_config;
71
72uint16_t envelope_index = 0;
73bool glissando = true;
74
75#ifndef STARTUP_SONG
76# define STARTUP_SONG SONG(STARTUP_SOUND)
77#endif
78float startup_song[][2] = STARTUP_SONG;
79
80static void gpt_cb8(GPTDriver *gptp);
81
82#define DAC_BUFFER_SIZE 100
83#ifndef DAC_SAMPLE_MAX
84# define DAC_SAMPLE_MAX 65535U
85#endif
86
87#define START_CHANNEL_1() \
88 gptStart(&GPTD6, &gpt6cfg1); \
89 gptStartContinuous(&GPTD6, 2U)
90#define START_CHANNEL_2() \
91 gptStart(&GPTD7, &gpt7cfg1); \
92 gptStartContinuous(&GPTD7, 2U)
93#define STOP_CHANNEL_1() gptStopTimer(&GPTD6)
94#define STOP_CHANNEL_2() gptStopTimer(&GPTD7)
95#define RESTART_CHANNEL_1() \
96 STOP_CHANNEL_1(); \
97 START_CHANNEL_1()
98#define RESTART_CHANNEL_2() \
99 STOP_CHANNEL_2(); \
100 START_CHANNEL_2()
101#define UPDATE_CHANNEL_1_FREQ(freq) \
102 gpt6cfg1.frequency = freq * DAC_BUFFER_SIZE; \
103 RESTART_CHANNEL_1()
104#define UPDATE_CHANNEL_2_FREQ(freq) \
105 gpt7cfg1.frequency = freq * DAC_BUFFER_SIZE; \
106 RESTART_CHANNEL_2()
107#define GET_CHANNEL_1_FREQ (uint16_t)(gpt6cfg1.frequency * DAC_BUFFER_SIZE)
108#define GET_CHANNEL_2_FREQ (uint16_t)(gpt7cfg1.frequency * DAC_BUFFER_SIZE)
109
110/*
111 * GPT6 configuration.
112 */
113// static const GPTConfig gpt6cfg1 = {
114// .frequency = 1000000U,
115// .callback = NULL,
116// .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
117// .dier = 0U
118// };
119
120GPTConfig gpt6cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE,
121 .callback = NULL,
122 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
123 .dier = 0U};
124
125GPTConfig gpt7cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE,
126 .callback = NULL,
127 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
128 .dier = 0U};
129
130GPTConfig gpt8cfg1 = {.frequency = 10,
131 .callback = gpt_cb8,
132 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
133 .dier = 0U};
134
135/*
136 * DAC test buffer (sine wave).
137 */
138// static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = {
139// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437,
140// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846,
141// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221,
142// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544,
143// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801,
144// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982,
145// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078,
146// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086,
147// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004,
148// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837,
149// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591,
150// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278,
151// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912,
152// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507,
153// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082,
154// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657,
155// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248,
156// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873,
157// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550,
158// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293,
159// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112,
160// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16,
161// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8,
162// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90,
163// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257,
164// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503,
165// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816,
166// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182,
167// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587,
168// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012
169// };
170
171// static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = {
172// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8,
173// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90,
174// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257,
175// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503,
176// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816,
177// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182,
178// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587,
179// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012,
180// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437,
181// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846,
182// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221,
183// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544,
184// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801,
185// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982,
186// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078,
187// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086,
188// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004,
189// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837,
190// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591,
191// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278,
192// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912,
193// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507,
194// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082,
195// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657,
196// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248,
197// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873,
198// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550,
199// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293,
200// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112,
201// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16
202// };
203
204// squarewave
205static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = {
206 // First half is max, second half is 0
207 [0 ... DAC_BUFFER_SIZE / 2 - 1] = DAC_SAMPLE_MAX,
208 [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = 0,
209};
210
211// squarewave
212static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = {
213 // opposite of dac_buffer above
214 [0 ... DAC_BUFFER_SIZE / 2 - 1] = 0,
215 [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = DAC_SAMPLE_MAX,
216};
217
218/*
219 * DAC streaming callback.
220 */
221size_t nz = 0;
222static void end_cb1(DACDriver *dacp) {
223 (void)dacp;
224
225 nz++;
226 if ((nz % 1000) == 0) {
227 // palTogglePad(GPIOD, GPIOD_LED3);
228 }
229}
230
231/*
232 * DAC error callback.
233 */
234static void error_cb1(DACDriver *dacp, dacerror_t err) {
235 (void)dacp;
236 (void)err;
237
238 chSysHalt("DAC failure");
239}
240
241static const DACConfig dac1cfg1 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT};
242
243static const DACConversionGroup dacgrpcfg1 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)};
244
245static const DACConfig dac1cfg2 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT};
246
247static const DACConversionGroup dacgrpcfg2 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)};
248
249void audio_init() {
250 if (audio_initialized) {
251 return;
252 }
253
254// Check EEPROM
255#ifdef EEPROM_ENABLE
256 if (!eeconfig_is_enabled()) {
257 eeconfig_init();
258 }
259 audio_config.raw = eeconfig_read_audio();
260#else // ARM EEPROM
261 audio_config.enable = true;
262# ifdef AUDIO_CLICKY_ON
263 audio_config.clicky_enable = true;
264# endif
265#endif // ARM EEPROM
266
267 /*
268 * Starting DAC1 driver, setting up the output pin as analog as suggested
269 * by the Reference Manual.
270 */
271 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
272 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
273 dacStart(&DACD1, &dac1cfg1);
274 dacStart(&DACD2, &dac1cfg2);
275
276 /*
277 * Starting GPT6/7 driver, it is used for triggering the DAC.
278 */
279 START_CHANNEL_1();
280 START_CHANNEL_2();
281
282 /*
283 * Starting a continuous conversion.
284 */
285 dacStartConversion(&DACD1, &dacgrpcfg1, (dacsample_t *)dac_buffer, DAC_BUFFER_SIZE);
286 dacStartConversion(&DACD2, &dacgrpcfg2, (dacsample_t *)dac_buffer_2, DAC_BUFFER_SIZE);
287
288 audio_initialized = true;
289
290 if (audio_config.enable) {
291 PLAY_SONG(startup_song);
292 } else {
293 stop_all_notes();
294 }
295}
296
297void stop_all_notes() {
298 dprintf("audio stop all notes");
299
300 if (!audio_initialized) {
301 audio_init();
302 }
303 voices = 0;
304
305 gptStopTimer(&GPTD6);
306 gptStopTimer(&GPTD7);
307 gptStopTimer(&GPTD8);
308
309 playing_notes = false;
310 playing_note = false;
311 frequency = 0;
312 frequency_alt = 0;
313 volume = 0;
314
315 for (uint8_t i = 0; i < 8; i++) {
316 frequencies[i] = 0;
317 volumes[i] = 0;
318 }
319}
320
321void stop_note(float freq) {
322 dprintf("audio stop note freq=%d", (int)freq);
323
324 if (playing_note) {
325 if (!audio_initialized) {
326 audio_init();
327 }
328 for (int i = 7; i >= 0; i--) {
329 if (frequencies[i] == freq) {
330 frequencies[i] = 0;
331 volumes[i] = 0;
332 for (int j = i; (j < 7); j++) {
333 frequencies[j] = frequencies[j + 1];
334 frequencies[j + 1] = 0;
335 volumes[j] = volumes[j + 1];
336 volumes[j + 1] = 0;
337 }
338 break;
339 }
340 }
341 voices--;
342 if (voices < 0) {
343 voices = 0;
344 }
345 if (voice_place >= voices) {
346 voice_place = 0;
347 }
348 if (voices == 0) {
349 STOP_CHANNEL_1();
350 STOP_CHANNEL_2();
351 gptStopTimer(&GPTD8);
352 frequency = 0;
353 frequency_alt = 0;
354 volume = 0;
355 playing_note = false;
356 }
357 }
358}
359
360#ifdef VIBRATO_ENABLE
361
362float mod(float a, int b) {
363 float r = fmod(a, b);
364 return r < 0 ? r + b : r;
365}
366
367float vibrato(float average_freq) {
368# ifdef VIBRATO_STRENGTH_ENABLE
369 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
370# else
371 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
372# endif
373 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
374 return vibrated_freq;
375}
376
377#endif
378
379static void gpt_cb8(GPTDriver *gptp) {
380 float freq;
381
382 if (playing_note) {
383 if (voices > 0) {
384 float freq_alt = 0;
385 if (voices > 1) {
386 if (polyphony_rate == 0) {
387 if (glissando) {
388 if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) {
389 frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2);
390 } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) {
391 frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2);
392 } else {
393 frequency_alt = frequencies[voices - 2];
394 }
395 } else {
396 frequency_alt = frequencies[voices - 2];
397 }
398
399#ifdef VIBRATO_ENABLE
400 if (vibrato_strength > 0) {
401 freq_alt = vibrato(frequency_alt);
402 } else {
403 freq_alt = frequency_alt;
404 }
405#else
406 freq_alt = frequency_alt;
407#endif
408 }
409
410 if (envelope_index < 65535) {
411 envelope_index++;
412 }
413
414 freq_alt = voice_envelope(freq_alt);
415
416 if (freq_alt < 30.517578125) {
417 freq_alt = 30.52;
418 }
419
420 if (GET_CHANNEL_2_FREQ != (uint16_t)freq_alt) {
421 UPDATE_CHANNEL_2_FREQ(freq_alt);
422 } else {
423 RESTART_CHANNEL_2();
424 }
425 // note_timbre;
426 }
427
428 if (polyphony_rate > 0) {
429 if (voices > 1) {
430 voice_place %= voices;
431 if (place++ > (frequencies[voice_place] / polyphony_rate)) {
432 voice_place = (voice_place + 1) % voices;
433 place = 0.0;
434 }
435 }
436
437#ifdef VIBRATO_ENABLE
438 if (vibrato_strength > 0) {
439 freq = vibrato(frequencies[voice_place]);
440 } else {
441 freq = frequencies[voice_place];
442 }
443#else
444 freq = frequencies[voice_place];
445#endif
446 } else {
447 if (glissando) {
448 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
449 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
450 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
451 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
452 } else {
453 frequency = frequencies[voices - 1];
454 }
455 } else {
456 frequency = frequencies[voices - 1];
457 }
458
459#ifdef VIBRATO_ENABLE
460 if (vibrato_strength > 0) {
461 freq = vibrato(frequency);
462 } else {
463 freq = frequency;
464 }
465#else
466 freq = frequency;
467#endif
468 }
469
470 if (envelope_index < 65535) {
471 envelope_index++;
472 }
473
474 freq = voice_envelope(freq);
475
476 if (freq < 30.517578125) {
477 freq = 30.52;
478 }
479
480 if (GET_CHANNEL_1_FREQ != (uint16_t)freq) {
481 UPDATE_CHANNEL_1_FREQ(freq);
482 } else {
483 RESTART_CHANNEL_1();
484 }
485 // note_timbre;
486 }
487 }
488
489 if (playing_notes) {
490 if (note_frequency > 0) {
491#ifdef VIBRATO_ENABLE
492 if (vibrato_strength > 0) {
493 freq = vibrato(note_frequency);
494 } else {
495 freq = note_frequency;
496 }
497#else
498 freq = note_frequency;
499#endif
500
501 if (envelope_index < 65535) {
502 envelope_index++;
503 }
504 freq = voice_envelope(freq);
505
506 if (GET_CHANNEL_1_FREQ != (uint16_t)freq) {
507 UPDATE_CHANNEL_1_FREQ(freq);
508 UPDATE_CHANNEL_2_FREQ(freq);
509 }
510 // note_timbre;
511 } else {
512 // gptStopTimer(&GPTD6);
513 // gptStopTimer(&GPTD7);
514 }
515
516 note_position++;
517 bool end_of_note = false;
518 if (GET_CHANNEL_1_FREQ > 0) {
519 if (!note_resting)
520 end_of_note = (note_position >= (note_length * 8 - 1));
521 else
522 end_of_note = (note_position >= (note_length * 8));
523 } else {
524 end_of_note = (note_position >= (note_length * 8));
525 }
526
527 if (end_of_note) {
528 current_note++;
529 if (current_note >= notes_count) {
530 if (notes_repeat) {
531 current_note = 0;
532 } else {
533 STOP_CHANNEL_1();
534 STOP_CHANNEL_2();
535 // gptStopTimer(&GPTD8);
536 playing_notes = false;
537 return;
538 }
539 }
540 if (!note_resting) {
541 note_resting = true;
542 current_note--;
543 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
544 note_frequency = 0;
545 note_length = 1;
546 } else {
547 note_frequency = (*notes_pointer)[current_note][0];
548 note_length = 1;
549 }
550 } else {
551 note_resting = false;
552 envelope_index = 0;
553 note_frequency = (*notes_pointer)[current_note][0];
554 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
555 }
556
557 note_position = 0;
558 }
559 }
560
561 if (!audio_config.enable) {
562 playing_notes = false;
563 playing_note = false;
564 }
565}
566
567void play_note(float freq, int vol) {
568 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
569
570 if (!audio_initialized) {
571 audio_init();
572 }
573
574 if (audio_config.enable && voices < 8) {
575 // Cancel notes if notes are playing
576 if (playing_notes) {
577 stop_all_notes();
578 }
579
580 playing_note = true;
581
582 envelope_index = 0;
583
584 if (freq > 0) {
585 frequencies[voices] = freq;
586 volumes[voices] = vol;
587 voices++;
588 }
589
590 gptStart(&GPTD8, &gpt8cfg1);
591 gptStartContinuous(&GPTD8, 2U);
592 RESTART_CHANNEL_1();
593 RESTART_CHANNEL_2();
594 }
595}
596
597void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) {
598 if (!audio_initialized) {
599 audio_init();
600 }
601
602 if (audio_config.enable) {
603 // Cancel note if a note is playing
604 if (playing_note) {
605 stop_all_notes();
606 }
607
608 playing_notes = true;
609
610 notes_pointer = np;
611 notes_count = n_count;
612 notes_repeat = n_repeat;
613
614 place = 0;
615 current_note = 0;
616
617 note_frequency = (*notes_pointer)[current_note][0];
618 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
619 note_position = 0;
620
621 gptStart(&GPTD8, &gpt8cfg1);
622 gptStartContinuous(&GPTD8, 2U);
623 RESTART_CHANNEL_1();
624 RESTART_CHANNEL_2();
625 }
626}
627
628bool is_playing_notes(void) { return playing_notes; }
629
630bool is_audio_on(void) { return (audio_config.enable != 0); }
631
632void audio_toggle(void) {
633 audio_config.enable ^= 1;
634 eeconfig_update_audio(audio_config.raw);
635 if (audio_config.enable) {
636 audio_on_user();
637 }
638}
639
640void audio_on(void) {
641 audio_config.enable = 1;
642 eeconfig_update_audio(audio_config.raw);
643 audio_on_user();
644}
645
646void audio_off(void) {
647 stop_all_notes();
648 audio_config.enable = 0;
649 eeconfig_update_audio(audio_config.raw);
650}
651
652#ifdef VIBRATO_ENABLE
653
654// Vibrato rate functions
655
656void set_vibrato_rate(float rate) { vibrato_rate = rate; }
657
658void increase_vibrato_rate(float change) { vibrato_rate *= change; }
659
660void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
661
662# ifdef VIBRATO_STRENGTH_ENABLE
663
664void set_vibrato_strength(float strength) { vibrato_strength = strength; }
665
666void increase_vibrato_strength(float change) { vibrato_strength *= change; }
667
668void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
669
670# endif /* VIBRATO_STRENGTH_ENABLE */
671
672#endif /* VIBRATO_ENABLE */
673
674// Polyphony functions
675
676void set_polyphony_rate(float rate) { polyphony_rate = rate; }
677
678void enable_polyphony() { polyphony_rate = 5; }
679
680void disable_polyphony() { polyphony_rate = 0; }
681
682void increase_polyphony_rate(float change) { polyphony_rate *= change; }
683
684void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
685
686// Timbre function
687
688void set_timbre(float timbre) { note_timbre = timbre; }
689
690// Tempo functions
691
692void set_tempo(uint8_t tempo) { note_tempo = tempo; }
693
694void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
695
696void increase_tempo(uint8_t tempo_change) {
697 if (note_tempo - tempo_change < 10) {
698 note_tempo = 10;
699 } else {
700 note_tempo -= tempo_change;
701 }
702}
diff --git a/quantum/audio/audio_pwm.c b/quantum/audio/audio_pwm.c
deleted file mode 100644
index 545aef6dd..000000000
--- a/quantum/audio/audio_pwm.c
+++ /dev/null
@@ -1,595 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#include <stdio.h>
17#include <string.h>
18//#include <math.h>
19#include <avr/pgmspace.h>
20#include <avr/interrupt.h>
21#include <avr/io.h>
22#include "print.h"
23#include "audio.h"
24#include "keymap.h"
25
26#include "eeconfig.h"
27
28#define PI 3.14159265
29
30#define CPU_PRESCALER 8
31
32// Timer Abstractions
33
34// TIMSK3 - Timer/Counter #3 Interrupt Mask Register
35// Turn on/off 3A interputs, stopping/enabling the ISR calls
36#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
37#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
38
39// TCCR3A: Timer/Counter #3 Control Register
40// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
41#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
42#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
43
44#define NOTE_PERIOD ICR3
45#define NOTE_DUTY_CYCLE OCR3A
46
47#ifdef PWM_AUDIO
48# include "wave.h"
49# define SAMPLE_DIVIDER 39
50# define SAMPLE_RATE (2000000.0 / SAMPLE_DIVIDER / 2048)
51// Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
52
53float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
54uint16_t place_int = 0;
55bool repeat = true;
56#endif
57
58void delay_us(int count) {
59 while (count--) {
60 _delay_us(1);
61 }
62}
63
64int voices = 0;
65int voice_place = 0;
66float frequency = 0;
67int volume = 0;
68long position = 0;
69
70float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
71int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
72bool sliding = false;
73
74float place = 0;
75
76uint8_t* sample;
77uint16_t sample_length = 0;
78// float freq = 0;
79
80bool playing_notes = false;
81bool playing_note = false;
82float note_frequency = 0;
83float note_length = 0;
84uint8_t note_tempo = TEMPO_DEFAULT;
85float note_timbre = TIMBRE_DEFAULT;
86uint16_t note_position = 0;
87float (*notes_pointer)[][2];
88uint16_t notes_count;
89bool notes_repeat;
90float notes_rest;
91bool note_resting = false;
92
93uint16_t current_note = 0;
94uint8_t rest_counter = 0;
95
96#ifdef VIBRATO_ENABLE
97float vibrato_counter = 0;
98float vibrato_strength = .5;
99float vibrato_rate = 0.125;
100#endif
101
102float polyphony_rate = 0;
103
104static bool audio_initialized = false;
105
106audio_config_t audio_config;
107
108uint16_t envelope_index = 0;
109
110void audio_init() {
111 // Check EEPROM
112 if (!eeconfig_is_enabled()) {
113 eeconfig_init();
114 }
115 audio_config.raw = eeconfig_read_audio();
116
117#ifdef PWM_AUDIO
118
119 PLLFRQ = _BV(PDIV2);
120 PLLCSR = _BV(PLLE);
121 while (!(PLLCSR & _BV(PLOCK)))
122 ;
123 PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
124
125 /* Init a fast PWM on Timer4 */
126 TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
127 TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
128 OCR4A = 0;
129
130 /* Enable the OC4A output */
131 DDRC |= _BV(PORTC6);
132
133 DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs
134
135 TCCR3A = 0x0; // Options not needed
136 TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
137 OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
138
139#else
140
141 // Set port PC6 (OC3A and /OC4A) as output
142 DDRC |= _BV(PORTC6);
143
144 DISABLE_AUDIO_COUNTER_3_ISR;
145
146 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
147 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
148 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
149 // Clock Select (CS3n) = 0b010 = Clock / 8
150 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
151 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
152
153#endif
154
155 audio_initialized = true;
156}
157
158void stop_all_notes() {
159 if (!audio_initialized) {
160 audio_init();
161 }
162 voices = 0;
163#ifdef PWM_AUDIO
164 DISABLE_AUDIO_COUNTER_3_ISR;
165#else
166 DISABLE_AUDIO_COUNTER_3_ISR;
167 DISABLE_AUDIO_COUNTER_3_OUTPUT;
168#endif
169
170 playing_notes = false;
171 playing_note = false;
172 frequency = 0;
173 volume = 0;
174
175 for (uint8_t i = 0; i < 8; i++) {
176 frequencies[i] = 0;
177 volumes[i] = 0;
178 }
179}
180
181void stop_note(float freq) {
182 if (playing_note) {
183 if (!audio_initialized) {
184 audio_init();
185 }
186#ifdef PWM_AUDIO
187 freq = freq / SAMPLE_RATE;
188#endif
189 for (int i = 7; i >= 0; i--) {
190 if (frequencies[i] == freq) {
191 frequencies[i] = 0;
192 volumes[i] = 0;
193 for (int j = i; (j < 7); j++) {
194 frequencies[j] = frequencies[j + 1];
195 frequencies[j + 1] = 0;
196 volumes[j] = volumes[j + 1];
197 volumes[j + 1] = 0;
198 }
199 break;
200 }
201 }
202 voices--;
203 if (voices < 0) voices = 0;
204 if (voice_place >= voices) {
205 voice_place = 0;
206 }
207 if (voices == 0) {
208#ifdef PWM_AUDIO
209 DISABLE_AUDIO_COUNTER_3_ISR;
210#else
211 DISABLE_AUDIO_COUNTER_3_ISR;
212 DISABLE_AUDIO_COUNTER_3_OUTPUT;
213#endif
214 frequency = 0;
215 volume = 0;
216 playing_note = false;
217 }
218 }
219}
220
221#ifdef VIBRATO_ENABLE
222
223float mod(float a, int b) {
224 float r = fmod(a, b);
225 return r < 0 ? r + b : r;
226}
227
228float vibrato(float average_freq) {
229# ifdef VIBRATO_STRENGTH_ENABLE
230 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
231# else
232 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
233# endif
234 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH);
235 return vibrated_freq;
236}
237
238#endif
239
240ISR(TIMER3_COMPA_vect) {
241 if (playing_note) {
242#ifdef PWM_AUDIO
243 if (voices == 1) {
244 // SINE
245 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
246
247 // SQUARE
248 // if (((int)place) >= 1024){
249 // OCR4A = 0xFF >> 2;
250 // } else {
251 // OCR4A = 0x00;
252 // }
253
254 // SAWTOOTH
255 // OCR4A = (int)place / 4;
256
257 // TRIANGLE
258 // if (((int)place) >= 1024) {
259 // OCR4A = (int)place / 2;
260 // } else {
261 // OCR4A = 2048 - (int)place / 2;
262 // }
263
264 place += frequency;
265
266 if (place >= SINE_LENGTH) place -= SINE_LENGTH;
267
268 } else {
269 int sum = 0;
270 for (int i = 0; i < voices; i++) {
271 // SINE
272 sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
273
274 // SQUARE
275 // if (((int)places[i]) >= 1024){
276 // sum += 0xFF >> 2;
277 // } else {
278 // sum += 0x00;
279 // }
280
281 places[i] += frequencies[i];
282
283 if (places[i] >= SINE_LENGTH) places[i] -= SINE_LENGTH;
284 }
285 OCR4A = sum;
286 }
287#else
288 if (voices > 0) {
289 float freq;
290 if (polyphony_rate > 0) {
291 if (voices > 1) {
292 voice_place %= voices;
293 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
294 voice_place = (voice_place + 1) % voices;
295 place = 0.0;
296 }
297 }
298# ifdef VIBRATO_ENABLE
299 if (vibrato_strength > 0) {
300 freq = vibrato(frequencies[voice_place]);
301 } else {
302# else
303 {
304# endif
305 freq = frequencies[voice_place];
306 }
307 } else {
308 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) {
309 frequency = frequency * pow(2, 440 / frequency / 12 / 2);
310 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) {
311 frequency = frequency * pow(2, -440 / frequency / 12 / 2);
312 } else {
313 frequency = frequencies[voices - 1];
314 }
315
316# ifdef VIBRATO_ENABLE
317 if (vibrato_strength > 0) {
318 freq = vibrato(frequency);
319 } else {
320# else
321 {
322# endif
323 freq = frequency;
324 }
325 }
326
327 if (envelope_index < 65535) {
328 envelope_index++;
329 }
330 freq = voice_envelope(freq);
331
332 if (freq < 30.517578125) freq = 30.52;
333 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
334 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
335 }
336#endif
337 }
338
339 // SAMPLE
340 // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
341
342 // place_int++;
343
344 // if (place_int >= sample_length)
345 // if (repeat)
346 // place_int -= sample_length;
347 // else
348 // DISABLE_AUDIO_COUNTER_3_ISR;
349
350 if (playing_notes) {
351#ifdef PWM_AUDIO
352 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
353
354 place += note_frequency;
355 if (place >= SINE_LENGTH) place -= SINE_LENGTH;
356#else
357 if (note_frequency > 0) {
358 float freq;
359
360# ifdef VIBRATO_ENABLE
361 if (vibrato_strength > 0) {
362 freq = vibrato(note_frequency);
363 } else {
364# else
365 {
366# endif
367 freq = note_frequency;
368 }
369
370 if (envelope_index < 65535) {
371 envelope_index++;
372 }
373 freq = voice_envelope(freq);
374
375 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
376 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
377 } else {
378 NOTE_PERIOD = 0;
379 NOTE_DUTY_CYCLE = 0;
380 }
381#endif
382
383 note_position++;
384 bool end_of_note = false;
385 if (NOTE_PERIOD > 0)
386 end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF));
387 else
388 end_of_note = (note_position >= (note_length * 0x7FF));
389 if (end_of_note) {
390 current_note++;
391 if (current_note >= notes_count) {
392 if (notes_repeat) {
393 current_note = 0;
394 } else {
395#ifdef PWM_AUDIO
396 DISABLE_AUDIO_COUNTER_3_ISR;
397#else
398 DISABLE_AUDIO_COUNTER_3_ISR;
399 DISABLE_AUDIO_COUNTER_3_OUTPUT;
400#endif
401 playing_notes = false;
402 return;
403 }
404 }
405 if (!note_resting && (notes_rest > 0)) {
406 note_resting = true;
407 note_frequency = 0;
408 note_length = notes_rest;
409 current_note--;
410 } else {
411 note_resting = false;
412#ifdef PWM_AUDIO
413 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
414 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
415#else
416 envelope_index = 0;
417 note_frequency = (*notes_pointer)[current_note][0];
418 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
419#endif
420 }
421 note_position = 0;
422 }
423 }
424
425 if (!audio_config.enable) {
426 playing_notes = false;
427 playing_note = false;
428 }
429}
430
431void play_note(float freq, int vol) {
432 if (!audio_initialized) {
433 audio_init();
434 }
435
436 if (audio_config.enable && voices < 8) {
437 DISABLE_AUDIO_COUNTER_3_ISR;
438
439 // Cancel notes if notes are playing
440 if (playing_notes) stop_all_notes();
441
442 playing_note = true;
443
444 envelope_index = 0;
445
446#ifdef PWM_AUDIO
447 freq = freq / SAMPLE_RATE;
448#endif
449 if (freq > 0) {
450 frequencies[voices] = freq;
451 volumes[voices] = vol;
452 voices++;
453 }
454
455#ifdef PWM_AUDIO
456 ENABLE_AUDIO_COUNTER_3_ISR;
457#else
458 ENABLE_AUDIO_COUNTER_3_ISR;
459 ENABLE_AUDIO_COUNTER_3_OUTPUT;
460#endif
461 }
462}
463
464void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) {
465 if (!audio_initialized) {
466 audio_init();
467 }
468
469 if (audio_config.enable) {
470 DISABLE_AUDIO_COUNTER_3_ISR;
471
472 // Cancel note if a note is playing
473 if (playing_note) stop_all_notes();
474
475 playing_notes = true;
476
477 notes_pointer = np;
478 notes_count = n_count;
479 notes_repeat = n_repeat;
480 notes_rest = n_rest;
481
482 place = 0;
483 current_note = 0;
484
485#ifdef PWM_AUDIO
486 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
487 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
488#else
489 note_frequency = (*notes_pointer)[current_note][0];
490 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
491#endif
492 note_position = 0;
493
494#ifdef PWM_AUDIO
495 ENABLE_AUDIO_COUNTER_3_ISR;
496#else
497 ENABLE_AUDIO_COUNTER_3_ISR;
498 ENABLE_AUDIO_COUNTER_3_OUTPUT;
499#endif
500 }
501}
502
503#ifdef PWM_AUDIO
504void play_sample(uint8_t* s, uint16_t l, bool r) {
505 if (!audio_initialized) {
506 audio_init();
507 }
508
509 if (audio_config.enable) {
510 DISABLE_AUDIO_COUNTER_3_ISR;
511 stop_all_notes();
512 place_int = 0;
513 sample = s;
514 sample_length = l;
515 repeat = r;
516
517 ENABLE_AUDIO_COUNTER_3_ISR;
518 }
519}
520#endif
521
522void audio_toggle(void) {
523 audio_config.enable ^= 1;
524 eeconfig_update_audio(audio_config.raw);
525}
526
527void audio_on(void) {
528 audio_config.enable = 1;
529 eeconfig_update_audio(audio_config.raw);
530}
531
532void audio_off(void) {
533 audio_config.enable = 0;
534 eeconfig_update_audio(audio_config.raw);
535}
536
537#ifdef VIBRATO_ENABLE
538
539// Vibrato rate functions
540
541void set_vibrato_rate(float rate) { vibrato_rate = rate; }
542
543void increase_vibrato_rate(float change) { vibrato_rate *= change; }
544
545void decrease_vibrato_rate(float change) { vibrato_rate /= change; }
546
547# ifdef VIBRATO_STRENGTH_ENABLE
548
549void set_vibrato_strength(float strength) { vibrato_strength = strength; }
550
551void increase_vibrato_strength(float change) { vibrato_strength *= change; }
552
553void decrease_vibrato_strength(float change) { vibrato_strength /= change; }
554
555# endif /* VIBRATO_STRENGTH_ENABLE */
556
557#endif /* VIBRATO_ENABLE */
558
559// Polyphony functions
560
561void set_polyphony_rate(float rate) { polyphony_rate = rate; }
562
563void enable_polyphony() { polyphony_rate = 5; }
564
565void disable_polyphony() { polyphony_rate = 0; }
566
567void increase_polyphony_rate(float change) { polyphony_rate *= change; }
568
569void decrease_polyphony_rate(float change) { polyphony_rate /= change; }
570
571// Timbre function
572
573void set_timbre(float timbre) { note_timbre = timbre; }
574
575// Tempo functions
576
577void set_tempo(uint8_t tempo) { note_tempo = tempo; }
578
579void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; }
580
581void increase_tempo(uint8_t tempo_change) {
582 if (note_tempo - tempo_change < 10) {
583 note_tempo = 10;
584 } else {
585 note_tempo -= tempo_change;
586 }
587}
588
589//------------------------------------------------------------------------------
590// Override these functions in your keymap file to play different tunes on
591// startup and bootloader jump
592__attribute__((weak)) void play_startup_tone() {}
593
594__attribute__((weak)) void play_goodbye_tone() {}
595//------------------------------------------------------------------------------
diff --git a/quantum/audio/driver_avr_pwm.h b/quantum/audio/driver_avr_pwm.h
new file mode 100644
index 000000000..d6eb3571d
--- /dev/null
+++ b/quantum/audio/driver_avr_pwm.h
@@ -0,0 +1,17 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
diff --git a/quantum/audio/driver_avr_pwm_hardware.c b/quantum/audio/driver_avr_pwm_hardware.c
new file mode 100644
index 000000000..492b9bfb0
--- /dev/null
+++ b/quantum/audio/driver_avr_pwm_hardware.c
@@ -0,0 +1,322 @@
1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#if defined(__AVR__)
19# include <avr/pgmspace.h>
20# include <avr/interrupt.h>
21# include <avr/io.h>
22#endif
23
24#include "audio.h"
25
26extern bool playing_note;
27extern bool playing_melody;
28extern uint8_t note_timbre;
29
30#define CPU_PRESCALER 8
31
32/*
33 Audio Driver: PWM
34
35 drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4.
36
37 the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3
38 and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1
39
40 alternatively, the PWM pins on PORTB can be used as only/primary speaker
41*/
42
43#if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7)
44# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options."
45#endif
46
47#if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6)
48# define AUDIO1_PIN_SET
49# define AUDIO1_TIMSKx TIMSK3
50# define AUDIO1_TCCRxA TCCR3A
51# define AUDIO1_TCCRxB TCCR3B
52# define AUDIO1_ICRx ICR3
53# define AUDIO1_WGMx0 WGM30
54# define AUDIO1_WGMx1 WGM31
55# define AUDIO1_WGMx2 WGM32
56# define AUDIO1_WGMx3 WGM33
57# define AUDIO1_CSx0 CS30
58# define AUDIO1_CSx1 CS31
59# define AUDIO1_CSx2 CS32
60
61# if (AUDIO_PIN == C6)
62# define AUDIO1_COMxy0 COM3A0
63# define AUDIO1_COMxy1 COM3A1
64# define AUDIO1_OCIExy OCIE3A
65# define AUDIO1_OCRxy OCR3A
66# define AUDIO1_PIN C6
67# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect
68# elif (AUDIO_PIN == C5)
69# define AUDIO1_COMxy0 COM3B0
70# define AUDIO1_COMxy1 COM3B1
71# define AUDIO1_OCIExy OCIE3B
72# define AUDIO1_OCRxy OCR3B
73# define AUDIO1_PIN C5
74# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect
75# elif (AUDIO_PIN == C4)
76# define AUDIO1_COMxy0 COM3C0
77# define AUDIO1_COMxy1 COM3C1
78# define AUDIO1_OCIExy OCIE3C
79# define AUDIO1_OCRxy OCR3C
80# define AUDIO1_PIN C4
81# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect
82# endif
83#endif
84
85#if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT)
86# error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense."
87#endif
88
89#if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6)))
90# error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported."
91#endif
92
93#if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
94# error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported."
95#endif
96
97#if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7)
98# define AUDIO2_PIN_SET
99# define AUDIO2_TIMSKx TIMSK1
100# define AUDIO2_TCCRxA TCCR1A
101# define AUDIO2_TCCRxB TCCR1B
102# define AUDIO2_ICRx ICR1
103# define AUDIO2_WGMx0 WGM10
104# define AUDIO2_WGMx1 WGM11
105# define AUDIO2_WGMx2 WGM12
106# define AUDIO2_WGMx3 WGM13
107# define AUDIO2_CSx0 CS10
108# define AUDIO2_CSx1 CS11
109# define AUDIO2_CSx2 CS12
110
111# if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5)
112# define AUDIO2_COMxy0 COM1A0
113# define AUDIO2_COMxy1 COM1A1
114# define AUDIO2_OCIExy OCIE1A
115# define AUDIO2_OCRxy OCR1A
116# define AUDIO2_PIN B5
117# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
118# elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6)
119# define AUDIO2_COMxy0 COM1B0
120# define AUDIO2_COMxy1 COM1B1
121# define AUDIO2_OCIExy OCIE1B
122# define AUDIO2_OCRxy OCR1B
123# define AUDIO2_PIN B6
124# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect
125# elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7)
126# define AUDIO2_COMxy0 COM1C0
127# define AUDIO2_COMxy1 COM1C1
128# define AUDIO2_OCIExy OCIE1C
129# define AUDIO2_OCRxy OCR1C
130# define AUDIO2_PIN B7
131# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect
132# endif
133#endif
134
135// C6 seems to be the assumed default by many existing keyboard - but sill warn the user
136#if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET)
137# pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)"
138// TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define
139#endif
140// -----------------------------------------------------------------------------
141
142#ifdef AUDIO1_PIN_SET
143static float channel_1_frequency = 0.0f;
144void channel_1_set_frequency(float freq) {
145 if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0
146 {
147 // disable the output, but keep the pwm-ISR going (with the previous
148 // frequency) so the audio-state keeps getting updated
149 // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet
150 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
151 return;
152 } else {
153 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode
154 }
155
156 channel_1_frequency = freq;
157
158 // set pwm period
159 AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
160 // and duty cycle
161 AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
162}
163
164void channel_1_start(void) {
165 // enable timer-counter ISR
166 AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy);
167 // enable timer-counter output
168 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1);
169}
170
171void channel_1_stop(void) {
172 // disable timer-counter ISR
173 AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy);
174 // disable timer-counter output
175 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
176}
177#endif
178
179#ifdef AUDIO2_PIN_SET
180static float channel_2_frequency = 0.0f;
181void channel_2_set_frequency(float freq) {
182 if (freq == 0.0f) {
183 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
184 return;
185 } else {
186 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
187 }
188
189 channel_2_frequency = freq;
190
191 AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
192 AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
193}
194
195float channel_2_get_frequency(void) { return channel_2_frequency; }
196
197void channel_2_start(void) {
198 AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);
199 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
200}
201
202void channel_2_stop(void) {
203 AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy);
204 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
205}
206#endif
207
208void audio_driver_initialize() {
209#ifdef AUDIO1_PIN_SET
210 channel_1_stop();
211 setPinOutput(AUDIO1_PIN);
212#endif
213
214#ifdef AUDIO2_PIN_SET
215 channel_2_stop();
216 setPinOutput(AUDIO2_PIN);
217#endif
218
219 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
220 // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
221 // OC3A -- PC6
222 // OC3B -- PC5
223 // OC3C -- PC4
224 // OC1A -- PB5
225 // OC1B -- PB6
226 // OC1C -- PB7
227
228 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
229 // OCR3A - PC6
230 // OCR3B - PC5
231 // OCR3C - PC4
232 // OCR1A - PB5
233 // OCR1B - PB6
234 // OCR1C - PB7
235
236 // Clock Select (CS3n) = 0b010 = Clock / 8
237#ifdef AUDIO1_PIN_SET
238 // initialize timer-counter
239 AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0);
240 AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0);
241#endif
242
243#ifdef AUDIO2_PIN_SET
244 AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0);
245 AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0);
246#endif
247}
248
249void audio_driver_stop() {
250#ifdef AUDIO1_PIN_SET
251 channel_1_stop();
252#endif
253
254#ifdef AUDIO2_PIN_SET
255 channel_2_stop();
256#endif
257}
258
259void audio_driver_start(void) {
260#ifdef AUDIO1_PIN_SET
261 channel_1_start();
262 if (playing_note) {
263 channel_1_set_frequency(audio_get_processed_frequency(0));
264 }
265#endif
266
267#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
268 channel_2_start();
269 if (playing_note) {
270 channel_2_set_frequency(audio_get_processed_frequency(0));
271 }
272#endif
273}
274
275static volatile uint32_t isr_counter = 0;
276#ifdef AUDIO1_PIN_SET
277ISR(AUDIO1_TIMERx_COMPy_vect) {
278 isr_counter++;
279 if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return;
280
281 isr_counter = 0;
282 bool state_changed = audio_update_state();
283
284 if (!playing_note && !playing_melody) {
285 channel_1_stop();
286# ifdef AUDIO2_PIN_SET
287 channel_2_stop();
288# endif
289 return;
290 }
291
292 if (state_changed) {
293 channel_1_set_frequency(audio_get_processed_frequency(0));
294# ifdef AUDIO2_PIN_SET
295 if (audio_get_number_of_active_tones() > 1) {
296 channel_2_set_frequency(audio_get_processed_frequency(1));
297 } else {
298 channel_2_stop();
299 }
300# endif
301 }
302}
303#endif
304
305#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
306ISR(AUDIO2_TIMERx_COMPy_vect) {
307 isr_counter++;
308 if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return;
309
310 isr_counter = 0;
311 bool state_changed = audio_update_state();
312
313 if (!playing_note && !playing_melody) {
314 channel_2_stop();
315 return;
316 }
317
318 if (state_changed) {
319 channel_2_set_frequency(audio_get_processed_frequency(0));
320 }
321}
322#endif
diff --git a/quantum/audio/driver_chibios_dac.h b/quantum/audio/driver_chibios_dac.h
new file mode 100644
index 000000000..07cd622ea
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac.h
@@ -0,0 +1,126 @@
1/* Copyright 2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#ifndef A4
20# define A4 PAL_LINE(GPIOA, 4)
21#endif
22#ifndef A5
23# define A5 PAL_LINE(GPIOA, 5)
24#endif
25
26/**
27 * Size of the dac_buffer arrays. All must be the same size.
28 */
29#define AUDIO_DAC_BUFFER_SIZE 256U
30
31/**
32 * Highest value allowed sample value.
33
34 * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U;
35 * lower values adjust the peak-voltage aka volume down.
36 * adjusting this value has only an effect on a sample-buffer whose values are
37 * are NOT pregenerated - see square-wave
38 */
39#ifndef AUDIO_DAC_SAMPLE_MAX
40# define AUDIO_DAC_SAMPLE_MAX 4095U
41#endif
42
43#if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH)
44# define AUDIO_DAC_QUALITY_SANE_MINIMUM
45#endif
46
47/**
48 * These presets allow you to quickly switch between quality settings for
49 * the DAC. The sample rate and maximum number of simultaneous tones roughly
50 * has an inverse relationship - slightly higher sample rates may be possible.
51 *
52 * NOTE: a high sample-rate results in a higher cpu-load, which might lead to
53 * (audible) discontinuities and/or starve other processes of cpu-time
54 * (like RGB-led back-lighting, ...)
55 */
56#ifdef AUDIO_DAC_QUALITY_VERY_LOW
57# define AUDIO_DAC_SAMPLE_RATE 11025U
58# define AUDIO_MAX_SIMULTANEOUS_TONES 8
59#endif
60
61#ifdef AUDIO_DAC_QUALITY_LOW
62# define AUDIO_DAC_SAMPLE_RATE 22050U
63# define AUDIO_MAX_SIMULTANEOUS_TONES 4
64#endif
65
66#ifdef AUDIO_DAC_QUALITY_HIGH
67# define AUDIO_DAC_SAMPLE_RATE 44100U
68# define AUDIO_MAX_SIMULTANEOUS_TONES 2
69#endif
70
71#ifdef AUDIO_DAC_QUALITY_VERY_HIGH
72# define AUDIO_DAC_SAMPLE_RATE 88200U
73# define AUDIO_MAX_SIMULTANEOUS_TONES 1
74#endif
75
76#ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM
77/* a sane-minimum config: with a trade-off between cpu-load and tone-range
78 *
79 * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now
80 * aim for an even even multiple of the buffer-size, we end up with:
81 * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE)
82 * 7902/256 = 30.867 * 2 * 256 ~= 16384
83 * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P)
84 */
85# define AUDIO_DAC_SAMPLE_RATE 16384U
86# define AUDIO_MAX_SIMULTANEOUS_TONES 8
87#endif
88
89/**
90 * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any
91 * lower will sacrifice perceptible audio quality. Any higher will limit the
92 * number of simultaneous tones. In most situations, a tenth (1/10) of the
93 * sample rate is where notes become unbearable.
94 */
95#ifndef AUDIO_DAC_SAMPLE_RATE
96# define AUDIO_DAC_SAMPLE_RATE 44100U
97#endif
98
99/**
100 * The number of tones that can be played simultaneously. If too high a value
101 * is used here, the keyboard will freeze and glitch-out when that many tones
102 * are being played.
103 */
104#ifndef AUDIO_MAX_SIMULTANEOUS_TONES
105# define AUDIO_MAX_SIMULTANEOUS_TONES 2
106#endif
107
108/**
109 * The default value of the DAC when not playing anything. Certain hardware
110 * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here.
111 * Since multiple added sine waves tend to oscillate around the midpoint,
112 * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a
113 * reasonable default value.
114 */
115#ifndef AUDIO_DAC_OFF_VALUE
116# define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2
117#endif
118
119#if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX
120# error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX"
121#endif
122
123/**
124 *user overridable sample generation/processing
125 */
126uint16_t dac_value_generate(void);
diff --git a/quantum/audio/driver_chibios_dac_additive.c b/quantum/audio/driver_chibios_dac_additive.c
new file mode 100644
index 000000000..db304adb8
--- /dev/null
+++ b/quantum/audio/driver_chibios_dac_additive.c
@@ -0,0 +1,335 @@
1/* Copyright 2016-2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "audio.h"
19#include <ch.h>
20#include <hal.h>
21
22/*
23 Audio Driver: DAC
24
25 which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA
26
27 it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate'
28
29 this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis
30*/
31
32#if !defined(AUDIO_PIN)
33# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options."
34#endif
35#if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE)
36# pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though."
37#endif
38
39#if !defined(AUDIO_PIN_ALT)
40// no ALT pin defined is valid, but the c-ifs below need some value set
41# define AUDIO_PIN_ALT PAL_NOLINE
42#endif
43
44#if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
45# define AUDIO_DAC_SAMPLE_WAVEFORM_SINE
46#endif
47
48#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE
49/* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0
50 */
51static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = {
52 // 256 values, max 4095
53 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe,
54 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1};
55#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE
56#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
57static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = {
58 // 256 values, max 4095
59 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf,
60 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
61#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
62#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
63static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = {
64 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and
65 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half
66};
67#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
68/*
69// four steps: 0, 1/3, 2/3 and 1
70static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = {
71 [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0,
72 [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3,
73 [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3,
74 [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX,
75}
76*/
77#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
78static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
79 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
80#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
81
82static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE};
83
84/* keep track of the sample position for for each frequency */
85static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0};
86
87static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0};
88static uint8_t active_tones_snapshot_length = 0;
89
90typedef enum {
91 OUTPUT_SHOULD_START,
92 OUTPUT_RUN_NORMALLY,
93 // path 1: wait for zero, then change/update active tones
94 OUTPUT_TONES_CHANGED,
95 OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE,
96 // path 2: hardware should stop, wait for zero then turn output off = stop the timer
97 OUTPUT_SHOULD_STOP,
98 OUTPUT_REACHED_ZERO_BEFORE_OFF,
99 OUTPUT_OFF,
100 OUTPUT_OFF_1,
101 OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level
102 number_of_output_states
103} output_states_t;
104output_states_t state = OUTPUT_OFF_2;
105
106/**
107 * Generation of the waveform being passed to the callback. Declared weak so users
108 * can override it with their own wave-forms/noises.
109 */
110__attribute__((weak)) uint16_t dac_value_generate(void) {
111 // DAC is running/asking for values but snapshot length is zero -> must be playing a pause
112 if (active_tones_snapshot_length == 0) {
113 return AUDIO_DAC_OFF_VALUE;
114 }
115
116 /* doing additive wave synthesis over all currently playing tones = adding up
117 * sine-wave-samples for each frequency, scaled by the number of active tones
118 */
119 uint16_t value = 0;
120 float frequency = 0.0f;
121
122 for (uint8_t i = 0; i < active_tones_snapshot_length; i++) {
123 /* Note: a user implementation does not have to rely on the active_tones_snapshot, but
124 * could directly query the active frequencies through audio_get_processed_frequency */
125 frequency = active_tones_snapshot[i];
126
127 dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3;
128 /*Note: the 2/3 are necessary to get the correct frequencies on the
129 * DAC output (as measured with an oscilloscope), since the gpt
130 * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback
131 * is called twice per conversion.*/
132
133 dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE);
134
135 // Wavetable generation/lookup
136 uint16_t dac_i = (uint16_t)dac_if[i];
137
138#if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE)
139 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length;
140#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE)
141 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length;
142#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
143 value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length;
144#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE)
145 value += dac_buffer_square[dac_i] / active_tones_snapshot_length;
146#endif
147 /*
148 // SINE
149 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3;
150 // TRIANGLE
151 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3;
152 // SQUARE
153 value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3;
154 //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P
155 */
156
157 // STAIRS (mostly usefully as test-pattern)
158 // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length;
159 }
160
161 return value;
162}
163
164/**
165 * DAC streaming callback. Does all of the main computing for playing songs.
166 *
167 * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'.
168 */
169static void dac_end(DACDriver *dacp) {
170 dacsample_t *sample_p = (dacp)->samples;
171
172 // work on the other half of the buffer
173 if (dacIsBufferComplete(dacp)) {
174 sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index'
175 }
176
177 for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) {
178 if (OUTPUT_OFF <= state) {
179 sample_p[s] = AUDIO_DAC_OFF_VALUE;
180 continue;
181 } else {
182 sample_p[s] = dac_value_generate();
183 }
184
185 /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX)
186 * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX
187 * * *
188 * * *
189 * ---------------------------------------------------------
190 * * * } AUDIO_DAC_SAMPLE_MAX/100
191 * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE
192 * * * } AUDIO_DAC_SAMPLE_MAX/100
193 * ---------------------------------------------------------
194 * *
195 * * *
196 * * *
197 * =====*=*================================================= 0x0
198 */
199 if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below
200 (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above
201 ) {
202 if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) {
203 state = OUTPUT_RUN_NORMALLY;
204 } else if (OUTPUT_TONES_CHANGED == state) {
205 state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE;
206 } else if (OUTPUT_SHOULD_STOP == state) {
207 state = OUTPUT_REACHED_ZERO_BEFORE_OFF;
208 }
209 }
210
211 // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover
212 if (OUTPUT_SHOULD_START == state) {
213 sample_p[s] = AUDIO_DAC_OFF_VALUE;
214 }
215
216 if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) {
217 uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones());
218 active_tones_snapshot_length = 0;
219 // update the snapshot - once, and only on occasion that something changed;
220 // -> saves cpu cycles (?)
221 for (uint8_t i = 0; i < active_tones; i++) {
222 float freq = audio_get_processed_frequency(i);
223 if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step
224 active_tones_snapshot[active_tones_snapshot_length++] = freq;
225 }
226 }
227
228 if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) {
229 state = OUTPUT_OFF;
230 }
231 if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) {
232 state = OUTPUT_RUN_NORMALLY;
233 }
234 }
235 }
236
237 // update audio internal state (note position, current_note, ...)
238 if (audio_update_state()) {
239 if (OUTPUT_SHOULD_STOP != state) {
240 state = OUTPUT_TONES_CHANGED;
241 }
242 }
243
244 if (OUTPUT_OFF <= state) {
245 if (OUTPUT_OFF_2 == state) {
246 // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE
247 gptStopTimer(&GPTD6);
248 } else {
249 state++;
250 }
251 }
252}
253
254static void dac_error(DACDriver *dacp, dacerror_t err) {
255 (void)dacp;
256 (void)err;
257
258 chSysHalt("DAC failure. halp");
259}
260
261static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3,
262 .callback = NULL,
263 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
264 .dier = 0U};
265
266static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
267
268/**
269 * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
270 * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
271 * to be a third of what we expect.
272 *
273 * Here are all the values for DAC_TRG (TSEL in the ref manual)
274 * TIM15_TRGO 0b011
275 * TIM2_TRGO 0b100
276 * TIM3_TRGO 0b001
277 * TIM6_TRGO 0b000
278 * TIM7_TRGO 0b010
279 * EXTI9 0b110
280 * SWTRIG 0b111
281 */
282static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};
283
284void audio_driver_initialize() {
285 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
286 palSetLineMode(A4, PAL_MODE_INPUT_ANALOG);
287 dacStart(&DACD1, &dac_conf);
288 }
289 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
290 palSetLineMode(A5, PAL_MODE_INPUT_ANALOG);
291 dacStart(&DACD2, &dac_conf);
292 }
293
294 /* enable the output buffer, to directly drive external loads with no additional circuitry
295 *
296 * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
297 * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
298 * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
299 *
300 * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
301 * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
302 */
303 DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
304 DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
305
306 if (AUDIO_PIN == A4) {
307 dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
308 } else if (AUDIO_PIN == A5) {
309 dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
310 }
311
312 // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE
313#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
314 if (AUDIO_PIN_ALT == A4) {
315 dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
316 } else if (AUDIO_PIN_ALT == A5) {
317 dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
318 }
319#endif
320
321 gptStart(&GPTD6, &gpt6cfg1);
322}
323
324void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; }
325
326void audio_driver_start(void) {
327 gptStartContinuous(&GPTD6, 2U);
328
329 for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) {
330 dac_if[i] = 0.0f;
331 active_tones_snapshot[i] = 0.0f;
332 }
333 active_tones_snapshot_length = 0;
334 state = OUTPUT_SHOULD_START;
335}
diff --git a/quantum/audio/driver_chibios_dac_basic.c b/quantum/audio/driver_chibios_dac_basic.c
new file mode 100644
index 000000000..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 8ac6aafd3..ddd7d374f 100644
--- a/quantum/audio/musical_notes.h
+++ b/quantum/audio/musical_notes.h
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
@@ -13,11 +14,12 @@
13 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 16 */
16
17#pragma once 17#pragma once
18 18
19// Tempo Placeholder 19#ifndef TEMPO_DEFAULT
20#define TEMPO_DEFAULT 100 20# define TEMPO_DEFAULT 120
21// in beats-per-minute
22#endif
21 23
22#define SONG(notes...) \ 24#define SONG(notes...) \
23 { notes } 25 { notes }
@@ -25,12 +27,14 @@
25// Note Types 27// Note Types
26#define MUSICAL_NOTE(note, duration) \ 28#define MUSICAL_NOTE(note, duration) \
27 { (NOTE##note), duration } 29 { (NOTE##note), duration }
30
28#define BREVE_NOTE(note) MUSICAL_NOTE(note, 128) 31#define BREVE_NOTE(note) MUSICAL_NOTE(note, 128)
29#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64) 32#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64)
30#define HALF_NOTE(note) MUSICAL_NOTE(note, 32) 33#define HALF_NOTE(note) MUSICAL_NOTE(note, 32)
31#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16) 34#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16)
32#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8) 35#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8)
33#define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4) 36#define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4)
37#define THIRTYSECOND_NOTE(note) MUSICAL_NOTE(note, 2)
34 38
35#define BREVE_DOT_NOTE(note) MUSICAL_NOTE(note, 128 + 64) 39#define BREVE_DOT_NOTE(note) MUSICAL_NOTE(note, 128 + 64)
36#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64 + 32) 40#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64 + 32)
@@ -38,6 +42,9 @@
38#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16 + 8) 42#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16 + 8)
39#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8 + 4) 43#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8 + 4)
40#define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4 + 2) 44#define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4 + 2)
45#define THIRTYSECOND_DOT_NOTE(note) MUSICAL_NOTE(note, 2 + 1)
46// duration of 64 units == one beat == one whole note
47// with a tempo of 60bpm this comes to a length of one second
41 48
42// Note Type Shortcuts 49// Note Type Shortcuts
43#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration) 50#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration)
@@ -47,55 +54,52 @@
47#define Q__NOTE(n) QUARTER_NOTE(n) 54#define Q__NOTE(n) QUARTER_NOTE(n)
48#define E__NOTE(n) EIGHTH_NOTE(n) 55#define E__NOTE(n) EIGHTH_NOTE(n)
49#define S__NOTE(n) SIXTEENTH_NOTE(n) 56#define S__NOTE(n) SIXTEENTH_NOTE(n)
57#define T__NOTE(n) THIRTYSECOND_NOTE(n)
50#define BD_NOTE(n) BREVE_DOT_NOTE(n) 58#define BD_NOTE(n) BREVE_DOT_NOTE(n)
51#define WD_NOTE(n) WHOLE_DOT_NOTE(n) 59#define WD_NOTE(n) WHOLE_DOT_NOTE(n)
52#define HD_NOTE(n) HALF_DOT_NOTE(n) 60#define HD_NOTE(n) HALF_DOT_NOTE(n)
53#define QD_NOTE(n) QUARTER_DOT_NOTE(n) 61#define QD_NOTE(n) QUARTER_DOT_NOTE(n)
54#define ED_NOTE(n) EIGHTH_DOT_NOTE(n) 62#define ED_NOTE(n) EIGHTH_DOT_NOTE(n)
55#define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n) 63#define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n)
64#define TD_NOTE(n) THIRTYSECOND_DOT_NOTE(n)
56 65
57// Note Timbre 66// Note Timbre
58// Changes how the notes sound 67// Changes how the notes sound
59#define TIMBRE_12 0.125f 68#define TIMBRE_12 12
60#define TIMBRE_25 0.250f 69#define TIMBRE_25 25
61#define TIMBRE_50 0.500f 70#define TIMBRE_50 50
62#define TIMBRE_75 0.750f 71#define TIMBRE_75 75
63#define TIMBRE_DEFAULT TIMBRE_50 72#ifndef TIMBRE_DEFAULT
73# define TIMBRE_DEFAULT TIMBRE_50
74#endif
64 75
65// Notes - # = Octave 76// Notes - # = Octave
66 77
67#ifdef __arm__ 78#define NOTE_REST 0.00f
68# define NOTE_REST 1.00f
69#else
70# define NOTE_REST 0.00f
71#endif
72
73/* These notes are currently bugged
74#define NOTE_C0 16.35f
75#define NOTE_CS0 17.32f
76#define NOTE_D0 18.35f
77#define NOTE_DS0 19.45f
78#define NOTE_E0 20.60f
79#define NOTE_F0 21.83f
80#define NOTE_FS0 23.12f
81#define NOTE_G0 24.50f
82#define NOTE_GS0 25.96f
83#define NOTE_A0 27.50f
84#define NOTE_AS0 29.14f
85#define NOTE_B0 30.87f
86#define NOTE_C1 32.70f
87#define NOTE_CS1 34.65f
88#define NOTE_D1 36.71f
89#define NOTE_DS1 38.89f
90#define NOTE_E1 41.20f
91#define NOTE_F1 43.65f
92#define NOTE_FS1 46.25f
93#define NOTE_G1 49.00f
94#define NOTE_GS1 51.91f
95#define NOTE_A1 55.00f
96#define NOTE_AS1 58.27f
97*/
98 79
80#define NOTE_C0 16.35f
81#define NOTE_CS0 17.32f
82#define NOTE_D0 18.35f
83#define NOTE_DS0 19.45f
84#define NOTE_E0 20.60f
85#define NOTE_F0 21.83f
86#define NOTE_FS0 23.12f
87#define NOTE_G0 24.50f
88#define NOTE_GS0 25.96f
89#define NOTE_A0 27.50f
90#define NOTE_AS0 29.14f
91#define NOTE_B0 30.87f
92#define NOTE_C1 32.70f
93#define NOTE_CS1 34.65f
94#define NOTE_D1 36.71f
95#define NOTE_DS1 38.89f
96#define NOTE_E1 41.20f
97#define NOTE_F1 43.65f
98#define NOTE_FS1 46.25f
99#define NOTE_G1 49.00f
100#define NOTE_GS1 51.91f
101#define NOTE_A1 55.00f
102#define NOTE_AS1 58.27f
99#define NOTE_B1 61.74f 103#define NOTE_B1 61.74f
100#define NOTE_C2 65.41f 104#define NOTE_C2 65.41f
101#define NOTE_CS2 69.30f 105#define NOTE_CS2 69.30f
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c
index 1592618be..8988d827e 100644
--- a/quantum/audio/voices.c
+++ b/quantum/audio/voices.c
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
@@ -17,13 +18,19 @@
17#include "audio.h" 18#include "audio.h"
18#include <stdlib.h> 19#include <stdlib.h>
19 20
20// these are imported from audio.c 21uint8_t note_timbre = TIMBRE_DEFAULT;
21extern uint16_t envelope_index; 22bool glissando = false;
22extern float note_timbre; 23bool vibrato = false;
23extern float polyphony_rate; 24float vibrato_strength = 0.5;
24extern bool glissando; 25float vibrato_rate = 0.125;
25 26
27uint16_t voices_timer = 0;
28
29#ifdef AUDIO_VOICE_DEFAULT
30voice_type voice = AUDIO_VOICE_DEFAULT;
31#else
26voice_type voice = default_voice; 32voice_type voice = default_voice;
33#endif
27 34
28void set_voice(voice_type v) { voice = v; } 35void set_voice(voice_type v) { voice = v; }
29 36
@@ -31,22 +38,54 @@ void voice_iterate() { voice = (voice + 1) % number_of_voices; }
31 38
32void voice_deiterate() { voice = (voice - 1 + number_of_voices) % number_of_voices; } 39void voice_deiterate() { voice = (voice - 1 + number_of_voices) % number_of_voices; }
33 40
41#ifdef AUDIO_VOICES
42float mod(float a, int b) {
43 float r = fmod(a, b);
44 return r < 0 ? r + b : r;
45}
46
47// Effect: 'vibrate' a given target frequency slightly above/below its initial value
48float voice_add_vibrato(float average_freq) {
49 float vibrato_counter = mod(timer_read() / (100 * vibrato_rate), VIBRATO_LUT_LENGTH);
50
51 return average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
52}
53
54// Effect: 'slides' the 'frequency' from the starting-point, to the target frequency
55float voice_add_glissando(float from_freq, float to_freq) {
56 if (to_freq != 0 && from_freq < to_freq && from_freq < to_freq * pow(2, -440 / to_freq / 12 / 2)) {
57 return from_freq * pow(2, 440 / from_freq / 12 / 2);
58 } else if (to_freq != 0 && from_freq > to_freq && from_freq > to_freq * pow(2, 440 / to_freq / 12 / 2)) {
59 return from_freq * pow(2, -440 / from_freq / 12 / 2);
60 } else {
61 return to_freq;
62 }
63}
64#endif
65
34float voice_envelope(float frequency) { 66float voice_envelope(float frequency) {
35 // envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz 67 // envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz
36 __attribute__((unused)) uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency)); 68// __attribute__((unused)) uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency));
69#ifdef AUDIO_VOICES
70 uint16_t envelope_index = timer_elapsed(voices_timer); // TODO: multiply in some factor?
71 uint16_t compensated_index = envelope_index / 100; // TODO: correct factor would be?
72#endif
37 73
38 switch (voice) { 74 switch (voice) {
39 case default_voice: 75 case default_voice:
40 glissando = false; 76 glissando = false;
41 note_timbre = TIMBRE_50; 77 // note_timbre = TIMBRE_50; //Note: leave the user the possibility to adjust the timbre with 'audio_set_timbre'
42 polyphony_rate = 0;
43 break; 78 break;
44 79
45#ifdef AUDIO_VOICES 80#ifdef AUDIO_VOICES
46 81
82 case vibrating:
83 glissando = false;
84 vibrato = true;
85 break;
86
47 case something: 87 case something:
48 glissando = false; 88 glissando = false;
49 polyphony_rate = 0;
50 switch (compensated_index) { 89 switch (compensated_index) {
51 case 0 ... 9: 90 case 0 ... 9:
52 note_timbre = TIMBRE_12; 91 note_timbre = TIMBRE_12;
@@ -57,24 +96,23 @@ float voice_envelope(float frequency) {
57 break; 96 break;
58 97
59 case 20 ... 200: 98 case 20 ... 200:
60 note_timbre = .125 + .125; 99 note_timbre = 12 + 12;
61 break; 100 break;
62 101
63 default: 102 default:
64 note_timbre = .125; 103 note_timbre = 12;
65 break; 104 break;
66 } 105 }
67 break; 106 break;
68 107
69 case drums: 108 case drums:
70 glissando = false; 109 glissando = false;
71 polyphony_rate = 0;
72 // switch (compensated_index) { 110 // switch (compensated_index) {
73 // case 0 ... 10: 111 // case 0 ... 10:
74 // note_timbre = 0.5; 112 // note_timbre = 50;
75 // break; 113 // break;
76 // case 11 ... 20: 114 // case 11 ... 20:
77 // note_timbre = 0.5 * (21 - compensated_index) / 10; 115 // note_timbre = 50 * (21 - compensated_index) / 10;
78 // break; 116 // break;
79 // default: 117 // default:
80 // note_timbre = 0; 118 // note_timbre = 0;
@@ -88,10 +126,10 @@ float voice_envelope(float frequency) {
88 frequency = (rand() % (int)(40)) + 60; 126 frequency = (rand() % (int)(40)) + 60;
89 switch (envelope_index) { 127 switch (envelope_index) {
90 case 0 ... 10: 128 case 0 ... 10:
91 note_timbre = 0.5; 129 note_timbre = 50;
92 break; 130 break;
93 case 11 ... 20: 131 case 11 ... 20:
94 note_timbre = 0.5 * (21 - envelope_index) / 10; 132 note_timbre = 50 * (21 - envelope_index) / 10;
95 break; 133 break;
96 default: 134 default:
97 note_timbre = 0; 135 note_timbre = 0;
@@ -103,10 +141,10 @@ float voice_envelope(float frequency) {
103 frequency = (rand() % (int)(1000)) + 1000; 141 frequency = (rand() % (int)(1000)) + 1000;
104 switch (envelope_index) { 142 switch (envelope_index) {
105 case 0 ... 5: 143 case 0 ... 5:
106 note_timbre = 0.5; 144 note_timbre = 50;
107 break; 145 break;
108 case 6 ... 20: 146 case 6 ... 20:
109 note_timbre = 0.5 * (21 - envelope_index) / 15; 147 note_timbre = 50 * (21 - envelope_index) / 15;
110 break; 148 break;
111 default: 149 default:
112 note_timbre = 0; 150 note_timbre = 0;
@@ -118,10 +156,10 @@ float voice_envelope(float frequency) {
118 frequency = (rand() % (int)(2000)) + 3000; 156 frequency = (rand() % (int)(2000)) + 3000;
119 switch (envelope_index) { 157 switch (envelope_index) {
120 case 0 ... 15: 158 case 0 ... 15:
121 note_timbre = 0.5; 159 note_timbre = 50;
122 break; 160 break;
123 case 16 ... 20: 161 case 16 ... 20:
124 note_timbre = 0.5 * (21 - envelope_index) / 5; 162 note_timbre = 50 * (21 - envelope_index) / 5;
125 break; 163 break;
126 default: 164 default:
127 note_timbre = 0; 165 note_timbre = 0;
@@ -133,10 +171,10 @@ float voice_envelope(float frequency) {
133 frequency = (rand() % (int)(2000)) + 3000; 171 frequency = (rand() % (int)(2000)) + 3000;
134 switch (envelope_index) { 172 switch (envelope_index) {
135 case 0 ... 35: 173 case 0 ... 35:
136 note_timbre = 0.5; 174 note_timbre = 50;
137 break; 175 break;
138 case 36 ... 50: 176 case 36 ... 50:
139 note_timbre = 0.5 * (51 - envelope_index) / 15; 177 note_timbre = 50 * (51 - envelope_index) / 15;
140 break; 178 break;
141 default: 179 default:
142 note_timbre = 0; 180 note_timbre = 0;
@@ -145,8 +183,7 @@ float voice_envelope(float frequency) {
145 } 183 }
146 break; 184 break;
147 case butts_fader: 185 case butts_fader:
148 glissando = true; 186 glissando = true;
149 polyphony_rate = 0;
150 switch (compensated_index) { 187 switch (compensated_index) {
151 case 0 ... 9: 188 case 0 ... 9:
152 frequency = frequency / 4; 189 frequency = frequency / 4;
@@ -159,7 +196,7 @@ float voice_envelope(float frequency) {
159 break; 196 break;
160 197
161 case 20 ... 200: 198 case 20 ... 200:
162 note_timbre = .125 - pow(((float)compensated_index - 20) / (200 - 20), 2) * .125; 199 note_timbre = 12 - (uint8_t)(pow(((float)compensated_index - 20) / (200 - 20), 2) * 12.5);
163 break; 200 break;
164 201
165 default: 202 default:
@@ -169,7 +206,6 @@ float voice_envelope(float frequency) {
169 break; 206 break;
170 207
171 // case octave_crunch: 208 // case octave_crunch:
172 // polyphony_rate = 0;
173 // switch (compensated_index) { 209 // switch (compensated_index) {
174 // case 0 ... 9: 210 // case 0 ... 9:
175 // case 20 ... 24: 211 // case 20 ... 24:
@@ -187,14 +223,13 @@ float voice_envelope(float frequency) {
187 223
188 // default: 224 // default:
189 // note_timbre = TIMBRE_12; 225 // note_timbre = TIMBRE_12;
190 // break; 226 // break;
191 // } 227 // }
192 // break; 228 // break;
193 229
194 case duty_osc: 230 case duty_osc:
195 // This slows the loop down a substantial amount, so higher notes may freeze 231 // This slows the loop down a substantial amount, so higher notes may freeze
196 glissando = true; 232 glissando = true;
197 polyphony_rate = 0;
198 switch (compensated_index) { 233 switch (compensated_index) {
199 default: 234 default:
200# define OCS_SPEED 10 235# define OCS_SPEED 10
@@ -202,38 +237,36 @@ float voice_envelope(float frequency) {
202 // sine wave is slow 237 // sine wave is slow
203 // note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5; 238 // note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5;
204 // triangle wave is a bit faster 239 // triangle wave is a bit faster
205 note_timbre = (float)abs((compensated_index * OCS_SPEED % 3000) - 1500) * (OCS_AMP / 1500) + (1 - OCS_AMP) / 2; 240 note_timbre = (uint8_t)abs((compensated_index * OCS_SPEED % 3000) - 1500) * (OCS_AMP / 1500) + (1 - OCS_AMP) / 2;
206 break; 241 break;
207 } 242 }
208 break; 243 break;
209 244
210 case duty_octave_down: 245 case duty_octave_down:
211 glissando = true; 246 glissando = true;
212 polyphony_rate = 0; 247 note_timbre = (uint8_t)(100 * (envelope_index % 2) * .125 + .375 * 2);
213 note_timbre = (envelope_index % 2) * .125 + .375 * 2; 248 if ((envelope_index % 4) == 0) note_timbre = 50;
214 if ((envelope_index % 4) == 0) note_timbre = 0.5;
215 if ((envelope_index % 8) == 0) note_timbre = 0; 249 if ((envelope_index % 8) == 0) note_timbre = 0;
216 break; 250 break;
217 case delayed_vibrato: 251 case delayed_vibrato:
218 glissando = true; 252 glissando = true;
219 polyphony_rate = 0; 253 note_timbre = TIMBRE_50;
220 note_timbre = TIMBRE_50;
221# define VOICE_VIBRATO_DELAY 150 254# define VOICE_VIBRATO_DELAY 150
222# define VOICE_VIBRATO_SPEED 50 255# define VOICE_VIBRATO_SPEED 50
223 switch (compensated_index) { 256 switch (compensated_index) {
224 case 0 ... VOICE_VIBRATO_DELAY: 257 case 0 ... VOICE_VIBRATO_DELAY:
225 break; 258 break;
226 default: 259 default:
260 // TODO: merge/replace with voice_add_vibrato above
227 frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1)) / 1000 * VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; 261 frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1)) / 1000 * VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)];
228 break; 262 break;
229 } 263 }
230 break; 264 break;
231 // case delayed_vibrato_octave: 265 // case delayed_vibrato_octave:
232 // polyphony_rate = 0;
233 // if ((envelope_index % 2) == 1) { 266 // if ((envelope_index % 2) == 1) {
234 // note_timbre = 0.55; 267 // note_timbre = 55;
235 // } else { 268 // } else {
236 // note_timbre = 0.45; 269 // note_timbre = 45;
237 // } 270 // }
238 // #define VOICE_VIBRATO_DELAY 150 271 // #define VOICE_VIBRATO_DELAY 150
239 // #define VOICE_VIBRATO_SPEED 50 272 // #define VOICE_VIBRATO_SPEED 50
@@ -246,35 +279,64 @@ float voice_envelope(float frequency) {
246 // } 279 // }
247 // break; 280 // break;
248 // case duty_fifth_down: 281 // case duty_fifth_down:
249 // note_timbre = 0.5; 282 // note_timbre = TIMBRE_50;
250 // if ((envelope_index % 3) == 0) 283 // if ((envelope_index % 3) == 0)
251 // note_timbre = 0.75; 284 // note_timbre = TIMBRE_75;
252 // break; 285 // break;
253 // case duty_fourth_down: 286 // case duty_fourth_down:
254 // note_timbre = 0.0; 287 // note_timbre = 0;
255 // if ((envelope_index % 12) == 0) 288 // if ((envelope_index % 12) == 0)
256 // note_timbre = 0.75; 289 // note_timbre = TIMBRE_75;
257 // if (((envelope_index % 12) % 4) != 1) 290 // if (((envelope_index % 12) % 4) != 1)
258 // note_timbre = 0.75; 291 // note_timbre = TIMBRE_75;
259 // break; 292 // break;
260 // case duty_third_down: 293 // case duty_third_down:
261 // note_timbre = 0.5; 294 // note_timbre = TIMBRE_50;
262 // if ((envelope_index % 5) == 0) 295 // if ((envelope_index % 5) == 0)
263 // note_timbre = 0.75; 296 // note_timbre = TIMBRE_75;
264 // break; 297 // break;
265 // case duty_fifth_third_down: 298 // case duty_fifth_third_down:
266 // note_timbre = 0.5; 299 // note_timbre = TIMBRE_50;
267 // if ((envelope_index % 5) == 0) 300 // if ((envelope_index % 5) == 0)
268 // note_timbre = 0.75; 301 // note_timbre = TIMBRE_75;
269 // if ((envelope_index % 3) == 0) 302 // if ((envelope_index % 3) == 0)
270 // note_timbre = 0.25; 303 // note_timbre = TIMBRE_25;
271 // break; 304 // break;
272 305
273#endif 306#endif // AUDIO_VOICES
274 307
275 default: 308 default:
276 break; 309 break;
277 } 310 }
278 311
312#ifdef AUDIO_VOICES
313 if (vibrato && (vibrato_strength > 0)) {
314 frequency = voice_add_vibrato(frequency);
315 }
316
317 if (glissando) {
318 // TODO: where to keep track of the start-frequency?
319 // frequency = voice_add_glissando(??, frequency);
320 }
321#endif // AUDIO_VOICES
322
279 return frequency; 323 return frequency;
280} 324}
325
326// Vibrato functions
327
328void voice_set_vibrato_rate(float rate) { vibrato_rate = rate; }
329void voice_increase_vibrato_rate(float change) { vibrato_rate *= change; }
330void voice_decrease_vibrato_rate(float change) { vibrato_rate /= change; }
331void voice_set_vibrato_strength(float strength) { vibrato_strength = strength; }
332void voice_increase_vibrato_strength(float change) { vibrato_strength *= change; }
333void voice_decrease_vibrato_strength(float change) { vibrato_strength /= change; }
334
335// Timbre functions
336
337void voice_set_timbre(uint8_t timbre) {
338 if ((timbre > 0) && (timbre < 100)) {
339 note_timbre = timbre;
340 }
341}
342uint8_t voice_get_timbre(void) { return note_timbre; }
diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h
index abafa2b40..578350d33 100644
--- a/quantum/audio/voices.h
+++ b/quantum/audio/voices.h
@@ -1,4 +1,5 @@
1/* Copyright 2016 Jack Humbert 1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
@@ -13,7 +14,6 @@
13 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 16 */
16
17#pragma once 17#pragma once
18 18
19#include <stdint.h> 19#include <stdint.h>
@@ -29,6 +29,7 @@ float voice_envelope(float frequency);
29typedef enum { 29typedef enum {
30 default_voice, 30 default_voice,
31#ifdef AUDIO_VOICES 31#ifdef AUDIO_VOICES
32 vibrating,
32 something, 33 something,
33 drums, 34 drums,
34 butts_fader, 35 butts_fader,
@@ -48,3 +49,21 @@ typedef enum {
48void set_voice(voice_type v); 49void set_voice(voice_type v);
49void voice_iterate(void); 50void voice_iterate(void);
50void voice_deiterate(void); 51void voice_deiterate(void);
52
53// Vibrato functions
54void voice_set_vibrato_rate(float rate);
55void voice_increase_vibrato_rate(float change);
56void voice_decrease_vibrato_rate(float change);
57void voice_set_vibrato_strength(float strength);
58void voice_increase_vibrato_strength(float change);
59void voice_decrease_vibrato_strength(float change);
60
61// Timbre functions
62/**
63 * @brief set the global timbre for tones to be played
64 * @note: only applies to pwm implementations - where it adjusts the duty-cycle
65 * @note: using any instrument from voices.[ch] other than 'default' may override the set value
66 * @param[in]: timbre: valid range is (0,100)
67 */
68void voice_set_timbre(uint8_t timbre);
69uint8_t voice_get_timbre(void);
diff --git a/quantum/audio/wave.h b/quantum/audio/wave.h
deleted file mode 100644
index 48210a944..000000000
--- a/quantum/audio/wave.h
+++ /dev/null
@@ -1,36 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <avr/io.h>
18#include <avr/interrupt.h>
19#include <avr/pgmspace.h>
20
21#define SINE_LENGTH 2048
22
23const uint8_t sinewave[] PROGMEM = // 2048 values
24 {0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x93, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xbb,
25 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd5, 0xd5, 0xd5, 0xd5, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8,
26 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
27 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
28 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xed, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4,
29 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9d,
30 0x9d, 0x9d, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x94, 0x94, 0x93, 0x93, 0x93, 0x92, 0x92, 0x91, 0x91, 0x91, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x86, 0x86, 0x85, 0x85, 0x85, 0x84, 0x84, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7c, 0x7c, 0x7b, 0x7b, 0x7a, 0x7a, 0x7a, 0x79, 0x79, 0x78, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x75, 0x75, 0x75, 0x74, 0x74, 0x73, 0x73, 0x73, 0x72, 0x72, 0x71, 0x71, 0x71, 0x70, 0x70, 0x70, 0x6f, 0x6f, 0x6e, 0x6e, 0x6e, 0x6d, 0x6d, 0x6c, 0x6c, 0x6c, 0x6b, 0x6b, 0x6a, 0x6a, 0x6a, 0x69, 0x69, 0x69, 0x68, 0x68, 0x67, 0x67, 0x67, 0x66, 0x66, 0x65, 0x65, 0x65, 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x62, 0x61, 0x61, 0x61, 0x60,
31 0x60, 0x5f, 0x5f, 0x5f, 0x5e, 0x5e, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5b, 0x5b, 0x5a, 0x5a, 0x5a, 0x59, 0x59, 0x59, 0x58, 0x58, 0x58, 0x57, 0x57, 0x56, 0x56, 0x56, 0x55, 0x55, 0x55, 0x54, 0x54, 0x53, 0x53, 0x53, 0x52, 0x52, 0x52, 0x51, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 0x4f, 0x4e, 0x4e, 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 0x4b, 0x4a, 0x4a, 0x4a, 0x49, 0x49, 0x49, 0x48, 0x48, 0x48, 0x47, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2e, 0x2e, 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2c, 0x2c, 0x2b, 0x2b, 0x2b, 0x2a, 0x2a,
32 0x2a, 0x2a, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26, 0x26, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, 0x10, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xe, 0xe, 0xe, 0xe, 0xe, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8,
33 0x8, 0x8, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
34 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xe, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17,
35 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46,
36 0x46, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f};