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