diff options
Diffstat (limited to 'quantum/audio/audio.h')
-rw-r--r-- | quantum/audio/audio.h | 281 |
1 files changed, 230 insertions, 51 deletions
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h index dccf03d5f..56b9158a1 100644 --- a/quantum/audio/audio.h +++ b/quantum/audio/audio.h | |||
@@ -1,4 +1,5 @@ | |||
1 | /* Copyright 2016 Jack Humbert | 1 | /* Copyright 2016-2020 Jack Humbert |
2 | * Copyright 2020 JohSchneider | ||
2 | * | 3 | * |
3 | * This program is free software: you can redistribute it and/or modify | 4 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -13,28 +14,30 @@ | |||
13 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | */ | 16 | */ |
16 | |||
17 | #pragma once | 17 | #pragma once |
18 | 18 | ||
19 | #include <stdint.h> | 19 | #include <stdint.h> |
20 | #include <stdbool.h> | 20 | #include <stdbool.h> |
21 | #if defined(__AVR__) | ||
22 | # include <avr/io.h> | ||
23 | #endif | ||
24 | #include "wait.h" | ||
25 | #include "musical_notes.h" | 21 | #include "musical_notes.h" |
26 | #include "song_list.h" | 22 | #include "song_list.h" |
27 | #include "voices.h" | 23 | #include "voices.h" |
28 | #include "quantum.h" | 24 | #include "quantum.h" |
29 | #include <math.h> | 25 | #include <math.h> |
30 | 26 | ||
31 | // Largely untested PWM audio mode (doesn't sound as good) | 27 | #if defined(__AVR__) |
32 | // #define PWM_AUDIO | 28 | # include <avr/io.h> |
33 | 29 | # if defined(AUDIO_DRIVER_PWM) | |
34 | // #define VIBRATO_ENABLE | 30 | # include "driver_avr_pwm.h" |
31 | # endif | ||
32 | #endif | ||
35 | 33 | ||
36 | // Enable vibrato strength/amplitude - slows down ISR too much | 34 | #if defined(PROTOCOL_CHIBIOS) |
37 | // #define VIBRATO_STRENGTH_ENABLE | 35 | # if defined(AUDIO_DRIVER_PWM) |
36 | # include "driver_chibios_pwm.h" | ||
37 | # elif defined(AUDIO_DRIVER_DAC) | ||
38 | # include "driver_chibios_dac.h" | ||
39 | # endif | ||
40 | #endif | ||
38 | 41 | ||
39 | typedef union { | 42 | typedef union { |
40 | uint8_t raw; | 43 | uint8_t raw; |
@@ -45,62 +48,238 @@ typedef union { | |||
45 | }; | 48 | }; |
46 | } audio_config_t; | 49 | } audio_config_t; |
47 | 50 | ||
48 | bool 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 | */ | ||
61 | typedef 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 | */ | ||
77 | void audio_init(void); | ||
78 | void audio_startup(void); | ||
79 | |||
80 | /** | ||
81 | * @brief en-/disable audio output, save this choice to the eeprom | ||
82 | */ | ||
49 | void audio_toggle(void); | 83 | void audio_toggle(void); |
84 | /** | ||
85 | * @brief enable audio output, save this choice to the eeprom | ||
86 | */ | ||
50 | void audio_on(void); | 87 | void audio_on(void); |
88 | /** | ||
89 | * @brief disable audio output, save this choice to the eeprom | ||
90 | */ | ||
51 | void audio_off(void); | 91 | void audio_off(void); |
92 | /** | ||
93 | * @brief query the if audio output is enabled | ||
94 | */ | ||
95 | bool audio_is_on(void); | ||
52 | 96 | ||
53 | // Vibrato rate functions | 97 | /** |
98 | * @brief start playback of a tone with the given frequency and duration | ||
99 | * | ||
100 | * @details starts the playback of a given note, which is automatically stopped | ||
101 | * at the the end of its duration = fire&forget | ||
102 | * | ||
103 | * @param[in] pitch frequency of the tone be played | ||
104 | * @param[in] duration in milliseconds, use 'audio_duration_to_ms' to convert | ||
105 | * from the musical_notes.h unit to ms | ||
106 | */ | ||
107 | void audio_play_note(float pitch, uint16_t duration); | ||
108 | // TODO: audio_play_note(float pitch, uint16_t duration, float intensity, float timbre); | ||
109 | // audio_play_note_with_instrument ifdef AUDIO_ENABLE_VOICES | ||
54 | 110 | ||
55 | #ifdef VIBRATO_ENABLE | 111 | /** |
112 | * @brief start playback of a tone with the given frequency | ||
113 | * | ||
114 | * @details the 'frequency' is put on-top the internal stack of active tones, | ||
115 | * as a new tone with indefinite duration. this tone is played by | ||
116 | * the hardware until a call to 'audio_stop_tone'. | ||
117 | * should a tone with that frequency already be active, its entry | ||
118 | * is put on the top of said internal stack - so no duplicate | ||
119 | * entries are kept. | ||
120 | * 'hardware_start' is called upon the first note. | ||
121 | * | ||
122 | * @param[in] pitch frequency of the tone be played | ||
123 | */ | ||
124 | void audio_play_tone(float pitch); | ||
56 | 125 | ||
57 | void set_vibrato_rate(float rate); | 126 | /** |
58 | void increase_vibrato_rate(float change); | 127 | * @brief stop a given tone/frequency |
59 | void decrease_vibrato_rate(float change); | 128 | * |
129 | * @details removes a tone matching the given frequency from the internal | ||
130 | * playback stack | ||
131 | * the hardware is stopped in case this was the last/only frequency | ||
132 | * being played. | ||
133 | * | ||
134 | * @param[in] pitch tone/frequency to be stopped | ||
135 | */ | ||
136 | void audio_stop_tone(float pitch); | ||
60 | 137 | ||
61 | # ifdef VIBRATO_STRENGTH_ENABLE | 138 | /** |
139 | * @brief play a melody | ||
140 | * | ||
141 | * @details starts playback of a melody passed in from a SONG definition - an | ||
142 | * array of {pitch, duration} float-tuples | ||
143 | * | ||
144 | * @param[in] np note-pointer to the SONG array | ||
145 | * @param[in] n_count number of MUSICAL_NOTES of the SONG | ||
146 | * @param[in] n_repeat false for onetime, true for looped playback | ||
147 | */ | ||
148 | void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat); | ||
62 | 149 | ||
63 | void set_vibrato_strength(float strength); | 150 | /** |
64 | void increase_vibrato_strength(float change); | 151 | * @brief play a short tone of a specific frequency to emulate a 'click' |
65 | void decrease_vibrato_strength(float change); | 152 | * |
153 | * @details constructs a two-note melody (one pause plus a note) and plays it through | ||
154 | * audio_play_melody. very short durations might not quite work due to | ||
155 | * hardware limitations (DAC: added pulses from zero-crossing feature;...) | ||
156 | * | ||
157 | * @param[in] delay in milliseconds, length for the pause before the pulses, can be zero | ||
158 | * @param[in] pitch | ||
159 | * @param[in] duration in milliseconds, length of the 'click' | ||
160 | */ | ||
161 | void audio_play_click(uint16_t delay, float pitch, uint16_t duration); | ||
66 | 162 | ||
67 | # endif | 163 | /** |
164 | * @brief stops all playback | ||
165 | * | ||
166 | * @details stops playback of both a melody as well as single tones, resetting | ||
167 | * the internal state | ||
168 | */ | ||
169 | void audio_stop_all(void); | ||
68 | 170 | ||
69 | #endif | 171 | /** |
172 | * @brief query if one/multiple tones are playing | ||
173 | */ | ||
174 | bool audio_is_playing_note(void); | ||
70 | 175 | ||
71 | // Polyphony functions | 176 | /** |
177 | * @brief query if a melody/SONG is playing | ||
178 | */ | ||
179 | bool audio_is_playing_melody(void); | ||
72 | 180 | ||
73 | void set_polyphony_rate(float rate); | 181 | // These macros are used to allow audio_play_melody to play an array of indeterminate |
74 | void enable_polyphony(void); | 182 | // length. This works around the limitation of C's sizeof operation on pointers. |
75 | void disable_polyphony(void); | 183 | // The global float array for the song must be used here. |
76 | void increase_polyphony_rate(float change); | 184 | #define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) |
77 | void decrease_polyphony_rate(float change); | ||
78 | 185 | ||
79 | void set_timbre(float timbre); | 186 | /** |
80 | void set_tempo(uint8_t tempo); | 187 | * @brief convenience macro, to play a melody/SONG once |
188 | */ | ||
189 | #define PLAY_SONG(note_array) audio_play_melody(¬e_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(¬e_array, NOTE_ARRAY_SIZE((note_array)), true) | ||
81 | 195 | ||
82 | void increase_tempo(uint8_t tempo_change); | 196 | // Tone-Multiplexing functions |
83 | void decrease_tempo(uint8_t tempo_change); | 197 | // this feature only makes sense for hardware setups which can't do proper |
198 | // audio-wave synthesis = have no DAC and need to use PWM for tone generation | ||
199 | #ifdef AUDIO_ENABLE_TONE_MULTIPLEXING | ||
200 | # ifndef AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT | ||
201 | # define AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 0 | ||
202 | // 0=off, good starting value is 4; the lower the value the higher the cpu-load | ||
203 | # endif | ||
204 | void audio_set_tone_multiplexing_rate(uint16_t rate); | ||
205 | void audio_enable_tone_multiplexing(void); | ||
206 | void audio_disable_tone_multiplexing(void); | ||
207 | void audio_increase_tone_multiplexing_rate(uint16_t change); | ||
208 | void audio_decrease_tone_multiplexing_rate(uint16_t change); | ||
209 | #endif | ||
210 | |||
211 | // Tempo functions | ||
212 | |||
213 | void audio_set_tempo(uint8_t tempo); | ||
214 | void audio_increase_tempo(uint8_t tempo_change); | ||
215 | void audio_decrease_tempo(uint8_t tempo_change); | ||
216 | |||
217 | // conversion macros, from 64parts-to-a-beat to milliseconds and back | ||
218 | uint16_t audio_duration_to_ms(uint16_t duration_bpm); | ||
219 | uint16_t audio_ms_to_duration(uint16_t duration_ms); | ||
84 | 220 | ||
85 | void audio_init(void); | ||
86 | void audio_startup(void); | 221 | void audio_startup(void); |
87 | 222 | ||
88 | #ifdef PWM_AUDIO | 223 | // hardware interface |
89 | void play_sample(uint8_t* s, uint16_t l, bool r); | ||
90 | #endif | ||
91 | void play_note(float freq, int vol); | ||
92 | void stop_note(float freq); | ||
93 | void stop_all_notes(void); | ||
94 | void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat); | ||
95 | 224 | ||
96 | #define SCALE \ | 225 | // implementation in the driver_avr/arm_* respective parts |
97 | (int8_t[]) { 0 + (12 * 0), 2 + (12 * 0), 4 + (12 * 0), 5 + (12 * 0), 7 + (12 * 0), 9 + (12 * 0), 11 + (12 * 0), 0 + (12 * 1), 2 + (12 * 1), 4 + (12 * 1), 5 + (12 * 1), 7 + (12 * 1), 9 + (12 * 1), 11 + (12 * 1), 0 + (12 * 2), 2 + (12 * 2), 4 + (12 * 2), 5 + (12 * 2), 7 + (12 * 2), 9 + (12 * 2), 11 + (12 * 2), 0 + (12 * 3), 2 + (12 * 3), 4 + (12 * 3), 5 + (12 * 3), 7 + (12 * 3), 9 + (12 * 3), 11 + (12 * 3), 0 + (12 * 4), 2 + (12 * 4), 4 + (12 * 4), 5 + (12 * 4), 7 + (12 * 4), 9 + (12 * 4), 11 + (12 * 4), } | 226 | void audio_driver_initialize(void); |
227 | void audio_driver_start(void); | ||
228 | void audio_driver_stop(void); | ||
98 | 229 | ||
99 | // These macros are used to allow play_notes to play an array of indeterminate | 230 | /** |
100 | // length. This works around the limitation of C's sizeof operation on pointers. | 231 | * @brief get the number of currently active tones |
101 | // The global float array for the song must be used here. | 232 | * @return number, 0=none active |
102 | #define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) | 233 | */ |
103 | #define PLAY_SONG(note_array) play_notes(¬e_array, NOTE_ARRAY_SIZE((note_array)), false) | 234 | uint8_t audio_get_number_of_active_tones(void); |
104 | #define PLAY_LOOP(note_array) play_notes(¬e_array, NOTE_ARRAY_SIZE((note_array)), true) | 235 | |
236 | /** | ||
237 | * @brief access to the raw/unprocessed frequency for a specific tone | ||
238 | * @details each active tone has a frequency associated with it, which | ||
239 | * the internal state keeps track of, and is usually influenced | ||
240 | * by various effects | ||
241 | * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the | ||
242 | * first being the most recent and each increment yielding the next | ||
243 | * older one | ||
244 | * @return a positive frequency, in Hz; or zero if the tone is a pause | ||
245 | */ | ||
246 | float 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 | */ | ||
258 | float 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 | */ | ||
270 | bool audio_update_state(void); | ||
271 | |||
272 | // legacy and back-warts compatibility stuff | ||
273 | |||
274 | #define is_audio_on() audio_is_on() | ||
275 | #define is_playing_notes() audio_is_playing_melody() | ||
276 | #define is_playing_note() audio_is_playing_note() | ||
277 | #define stop_all_notes() audio_stop_all() | ||
278 | #define stop_note(f) audio_stop_tone(f) | ||
279 | #define play_note(f, v) audio_play_tone(f) | ||
105 | 280 | ||
106 | bool 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 | ||