audio.h (10430B)
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 #pragma once 18 19 #include <stdint.h> 20 #include <stdbool.h> 21 22 #include "compiler_support.h" 23 #include "musical_notes.h" 24 #include "song_list.h" 25 #include "voices.h" 26 27 #if defined(AUDIO_DRIVER_PWM) 28 # include "audio_pwm.h" 29 #elif defined(AUDIO_DRIVER_DAC) 30 # include "audio_dac.h" 31 #endif 32 33 typedef union audio_config_t { 34 uint8_t raw; 35 struct { 36 bool enable : 1; 37 bool clicky_enable : 1; 38 bool valid : 1; 39 uint8_t reserved : 5; 40 }; 41 } audio_config_t; 42 43 STATIC_ASSERT(sizeof(audio_config_t) == sizeof(uint8_t), "Audio EECONFIG out of spec."); 44 45 /* 46 * a 'musical note' is represented by pitch and duration; a 'musical tone' adds intensity and timbre 47 * https://en.wikipedia.org/wiki/Musical_tone 48 * "A musical tone is characterized by its duration, pitch, intensity (or loudness), and timbre (or quality)" 49 */ 50 typedef struct { 51 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 52 float pitch; // aka frequency, in Hz 53 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 54 // float intensity; // aka volume [0,1] TODO: not used at the moment; pwm drivers can't handle it 55 // uint8_t timbre; // range: [0,100] TODO: this currently kept track of globally, should we do this per tone instead? 56 } musical_tone_t; 57 58 // public interface 59 60 /** 61 * @brief Save the current choices to the eeprom 62 */ 63 void eeconfig_update_audio_current(void); 64 65 /** 66 * @brief one-time initialization called by quantum/quantum.c 67 * @details usually done lazy, when some tones are to be played 68 * 69 * @post audio system (and hardware) initialized and ready to play tones 70 */ 71 void audio_init(void); 72 73 /** 74 * \brief Handle various subsystem background tasks. 75 */ 76 void audio_task(void); 77 78 /** 79 * @brief en-/disable audio output, save this choice to the eeprom 80 */ 81 void audio_toggle(void); 82 /** 83 * @brief enable audio output, save this choice to the eeprom 84 */ 85 void audio_on(void); 86 /** 87 * @brief disable audio output, save this choice to the eeprom 88 */ 89 void audio_off(void); 90 /** 91 * @brief query the if audio output is enabled 92 */ 93 bool audio_is_on(void); 94 95 /** 96 * @brief start playback of a tone with the given frequency and duration 97 * 98 * @details starts the playback of a given note, which is automatically stopped 99 * at the the end of its duration = fire&forget 100 * 101 * @param[in] pitch frequency of the tone be played 102 * @param[in] duration in milliseconds, use 'audio_duration_to_ms' to convert 103 * from the musical_notes.h unit to ms 104 */ 105 void audio_play_note(float pitch, uint16_t duration); 106 // TODO: audio_play_note(float pitch, uint16_t duration, float intensity, float timbre); 107 // audio_play_note_with_instrument ifdef AUDIO_ENABLE_VOICES 108 109 /** 110 * @brief start playback of a tone with the given frequency 111 * 112 * @details the 'frequency' is put on-top the internal stack of active tones, 113 * as a new tone with indefinite duration. this tone is played by 114 * the hardware until a call to 'audio_stop_tone'. 115 * should a tone with that frequency already be active, its entry 116 * is put on the top of said internal stack - so no duplicate 117 * entries are kept. 118 * 'hardware_start' is called upon the first note. 119 * 120 * @param[in] pitch frequency of the tone be played 121 */ 122 void audio_play_tone(float pitch); 123 124 /** 125 * @brief stop a given tone/frequency 126 * 127 * @details removes a tone matching the given frequency from the internal 128 * playback stack 129 * the hardware is stopped in case this was the last/only frequency 130 * being played. 131 * 132 * @param[in] pitch tone/frequency to be stopped 133 */ 134 void audio_stop_tone(float pitch); 135 136 /** 137 * @brief play a melody 138 * 139 * @details starts playback of a melody passed in from a SONG definition - an 140 * array of {pitch, duration} float-tuples 141 * 142 * @param[in] np note-pointer to the SONG array 143 * @param[in] n_count number of MUSICAL_NOTES of the SONG 144 * @param[in] n_repeat false for onetime, true for looped playback 145 */ 146 void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat); 147 148 /** 149 * @brief play a short tone of a specific frequency to emulate a 'click' 150 * 151 * @details constructs a two-note melody (one pause plus a note) and plays it through 152 * audio_play_melody. very short durations might not quite work due to 153 * hardware limitations (DAC: added pulses from zero-crossing feature;...) 154 * 155 * @param[in] delay in milliseconds, length for the pause before the pulses, can be zero 156 * @param[in] pitch 157 * @param[in] duration in milliseconds, length of the 'click' 158 */ 159 void audio_play_click(uint16_t delay, float pitch, uint16_t duration); 160 161 /** 162 * @brief stops all playback 163 * 164 * @details stops playback of both a melody as well as single tones, resetting 165 * the internal state 166 */ 167 void audio_stop_all(void); 168 169 /** 170 * @brief query if one/multiple tones are playing 171 */ 172 bool audio_is_playing_note(void); 173 174 /** 175 * @brief query if a melody/SONG is playing 176 */ 177 bool audio_is_playing_melody(void); 178 179 // These macros are used to allow audio_play_melody to play an array of indeterminate 180 // length. This works around the limitation of C's sizeof operation on pointers. 181 // The global float array for the song must be used here. 182 #define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) 183 184 /** 185 * @brief convenience macro, to play a melody/SONG once 186 */ 187 #define PLAY_SONG(note_array) audio_play_melody(¬e_array, NOTE_ARRAY_SIZE((note_array)), false) 188 // TODO: a 'song' is a melody plus singing/vocals -> PLAY_MELODY 189 /** 190 * @brief convenience macro, to play a melody/SONG in a loop, until stopped by 'audio_stop_all' 191 */ 192 #define PLAY_LOOP(note_array) audio_play_melody(¬e_array, NOTE_ARRAY_SIZE((note_array)), true) 193 194 // Tone-Multiplexing functions 195 // this feature only makes sense for hardware setups which can't do proper 196 // audio-wave synthesis = have no DAC and need to use PWM for tone generation 197 #ifdef AUDIO_ENABLE_TONE_MULTIPLEXING 198 # ifndef AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 199 # define AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 0 200 // 0=off, good starting value is 4; the lower the value the higher the cpu-load 201 # endif 202 void audio_set_tone_multiplexing_rate(uint16_t rate); 203 void audio_enable_tone_multiplexing(void); 204 void audio_disable_tone_multiplexing(void); 205 void audio_increase_tone_multiplexing_rate(uint16_t change); 206 void audio_decrease_tone_multiplexing_rate(uint16_t change); 207 #endif 208 209 // Tempo functions 210 211 void audio_set_tempo(uint8_t tempo); 212 void audio_increase_tempo(uint8_t tempo_change); 213 void audio_decrease_tempo(uint8_t tempo_change); 214 215 // conversion macros, from 64parts-to-a-beat to milliseconds and back 216 uint16_t audio_duration_to_ms(uint16_t duration_bpm); 217 uint16_t audio_ms_to_duration(uint16_t duration_ms); 218 219 void audio_startup(void); 220 221 // hardware interface 222 223 // implementation in the driver_avr/arm_* respective parts 224 void audio_driver_initialize_impl(void); 225 void audio_driver_start_impl(void); 226 void audio_driver_stop_impl(void); 227 228 /** 229 * @brief get the number of currently active tones 230 * @return number, 0=none active 231 */ 232 uint8_t audio_get_number_of_active_tones(void); 233 234 /** 235 * @brief access to the raw/unprocessed frequency for a specific tone 236 * @details each active tone has a frequency associated with it, which 237 * the internal state keeps track of, and is usually influenced 238 * by various effects 239 * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the 240 * first being the most recent and each increment yielding the next 241 * older one 242 * @return a positive frequency, in Hz; or zero if the tone is a pause 243 */ 244 float audio_get_frequency(uint8_t tone_index); 245 246 /** 247 * @brief calculate and return the frequency for the requested tone 248 * @details effects like glissando, vibrato, ... are post-processed onto the 249 * each active tones 'base'-frequency; this function returns the 250 * post-processed result. 251 * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the 252 * first being the most recent and each increment yielding the next 253 * older one 254 * @return a positive frequency, in Hz; or zero if the tone is a pause 255 */ 256 float audio_get_processed_frequency(uint8_t tone_index); 257 258 /** 259 * @brief update audio internal state: currently playing and active tones,... 260 * @details This function is intended to be called by the audio-hardware 261 * specific implementation on a somewhat regular basis while a SONG 262 * or notes (pitch+duration) are playing to 'advance' the internal 263 * state (current playing notes, position in the melody, ...) 264 * 265 * @return true if something changed in the currently active tones, which the 266 * hardware might need to react to 267 */ 268 bool audio_update_state(void); 269 270 // legacy and back-warts compatibility stuff 271 272 #define is_audio_on() audio_is_on() 273 #define is_playing_notes() audio_is_playing_melody() 274 #define is_playing_note() audio_is_playing_note() 275 #define stop_all_notes() audio_stop_all() 276 #define stop_note(f) audio_stop_tone(f) 277 #define play_note(f, v) audio_play_tone(f) 278 279 #define set_timbre(t) voice_set_timbre(t) 280 #define set_tempo(t) audio_set_tempo(t) 281 #define increase_tempo(t) audio_increase_tempo(t) 282 #define decrease_tempo(t) audio_decrease_tempo(t) 283 // vibrato functions are not used in any keyboards 284 285 void audio_on_user(void); 286 void audio_off_user(void);