audio.h 10 KB

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