summaryrefslogtreecommitdiff
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, 51 insertions, 230 deletions
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
index 56b9158a1a..dccf03d5f6 100644
--- a/quantum/audio/audio.h
+++ b/quantum/audio/audio.h
@@ -1,5 +1,4 @@
-/* Copyright 2016-2020 Jack Humbert
- * Copyright 2020 JohSchneider
+/* Copyright 2016 Jack Humbert
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,30 +13,28 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
#pragma once
#include <stdint.h>
#include <stdbool.h>
+#if defined(__AVR__)
+# include <avr/io.h>
+#endif
+#include "wait.h"
#include "musical_notes.h"
#include "song_list.h"
#include "voices.h"
#include "quantum.h"
#include <math.h>
-#if defined(__AVR__)
-# include <avr/io.h>
-# if defined(AUDIO_DRIVER_PWM)
-# include "driver_avr_pwm.h"
-# endif
-#endif
+// Largely untested PWM audio mode (doesn't sound as good)
+// #define PWM_AUDIO
-#if defined(PROTOCOL_CHIBIOS)
-# if defined(AUDIO_DRIVER_PWM)
-# include "driver_chibios_pwm.h"
-# elif defined(AUDIO_DRIVER_DAC)
-# include "driver_chibios_dac.h"
-# endif
-#endif
+// #define VIBRATO_ENABLE
+
+// Enable vibrato strength/amplitude - slows down ISR too much
+// #define VIBRATO_STRENGTH_ENABLE
typedef union {
uint8_t raw;
@@ -48,238 +45,62 @@ typedef union {
};
} audio_config_t;
-// AVR/LUFA has a MIN, arm/chibios does not
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-/*
- * a 'musical note' is represented by pitch and duration; a 'musical tone' adds intensity and timbre
- * https://en.wikipedia.org/wiki/Musical_tone
- * "A musical tone is characterized by its duration, pitch, intensity (or loudness), and timbre (or quality)"
- */
-typedef struct {
- 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
- float pitch; // aka frequency, in Hz
- 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
- // float intensity; // aka volume [0,1] TODO: not used at the moment; pwm drivers can't handle it
- // uint8_t timbre; // range: [0,100] TODO: this currently kept track of globally, should we do this per tone instead?
-} musical_tone_t;
-
-// public interface
-
-/**
- * @brief one-time initialization called by quantum/quantum.c
- * @details usually done lazy, when some tones are to be played
- *
- * @post audio system (and hardware) initialized and ready to play tones
- */
-void audio_init(void);
-void audio_startup(void);
-
-/**
- * @brief en-/disable audio output, save this choice to the eeprom
- */
+bool is_audio_on(void);
void audio_toggle(void);
-/**
- * @brief enable audio output, save this choice to the eeprom
- */
void audio_on(void);
-/**
- * @brief disable audio output, save this choice to the eeprom
- */
void audio_off(void);
-/**
- * @brief query the if audio output is enabled
- */
-bool audio_is_on(void);
-/**
- * @brief start playback of a tone with the given frequency and duration
- *
- * @details starts the playback of a given note, which is automatically stopped
- * at the the end of its duration = fire&forget
- *
- * @param[in] pitch frequency of the tone be played
- * @param[in] duration in milliseconds, use 'audio_duration_to_ms' to convert
- * from the musical_notes.h unit to ms
- */
-void audio_play_note(float pitch, uint16_t duration);
-// TODO: audio_play_note(float pitch, uint16_t duration, float intensity, float timbre);
-// audio_play_note_with_instrument ifdef AUDIO_ENABLE_VOICES
+// Vibrato rate functions
-/**
- * @brief start playback of a tone with the given frequency
- *
- * @details the 'frequency' is put on-top the internal stack of active tones,
- * as a new tone with indefinite duration. this tone is played by
- * the hardware until a call to 'audio_stop_tone'.
- * should a tone with that frequency already be active, its entry
- * is put on the top of said internal stack - so no duplicate
- * entries are kept.
- * 'hardware_start' is called upon the first note.
- *
- * @param[in] pitch frequency of the tone be played
- */
-void audio_play_tone(float pitch);
+#ifdef VIBRATO_ENABLE
-/**
- * @brief stop a given tone/frequency
- *
- * @details removes a tone matching the given frequency from the internal
- * playback stack
- * the hardware is stopped in case this was the last/only frequency
- * being played.
- *
- * @param[in] pitch tone/frequency to be stopped
- */
-void audio_stop_tone(float pitch);
+void set_vibrato_rate(float rate);
+void increase_vibrato_rate(float change);
+void decrease_vibrato_rate(float change);
-/**
- * @brief play a melody
- *
- * @details starts playback of a melody passed in from a SONG definition - an
- * array of {pitch, duration} float-tuples
- *
- * @param[in] np note-pointer to the SONG array
- * @param[in] n_count number of MUSICAL_NOTES of the SONG
- * @param[in] n_repeat false for onetime, true for looped playback
- */
-void audio_play_melody(float (*np)[][2], uint16_t n_count, bool n_repeat);
-
-/**
- * @brief play a short tone of a specific frequency to emulate a 'click'
- *
- * @details constructs a two-note melody (one pause plus a note) and plays it through
- * audio_play_melody. very short durations might not quite work due to
- * hardware limitations (DAC: added pulses from zero-crossing feature;...)
- *
- * @param[in] delay in milliseconds, length for the pause before the pulses, can be zero
- * @param[in] pitch
- * @param[in] duration in milliseconds, length of the 'click'
- */
-void audio_play_click(uint16_t delay, float pitch, uint16_t duration);
-
-/**
- * @brief stops all playback
- *
- * @details stops playback of both a melody as well as single tones, resetting
- * the internal state
- */
-void audio_stop_all(void);
-
-/**
- * @brief query if one/multiple tones are playing
- */
-bool audio_is_playing_note(void);
-
-/**
- * @brief query if a melody/SONG is playing
- */
-bool audio_is_playing_melody(void);
+# ifdef VIBRATO_STRENGTH_ENABLE
-// These macros are used to allow audio_play_melody to play an array of indeterminate
-// length. This works around the limitation of C's sizeof operation on pointers.
-// The global float array for the song must be used here.
-#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
-
-/**
- * @brief convenience macro, to play a melody/SONG once
- */
-#define PLAY_SONG(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), false)
-// TODO: a 'song' is a melody plus singing/vocals -> PLAY_MELODY
-/**
- * @brief convenience macro, to play a melody/SONG in a loop, until stopped by 'audio_stop_all'
- */
-#define PLAY_LOOP(note_array) audio_play_melody(&note_array, NOTE_ARRAY_SIZE((note_array)), true)
+void set_vibrato_strength(float strength);
+void increase_vibrato_strength(float change);
+void decrease_vibrato_strength(float change);
-// Tone-Multiplexing functions
-// this feature only makes sense for hardware setups which can't do proper
-// audio-wave synthesis = have no DAC and need to use PWM for tone generation
-#ifdef AUDIO_ENABLE_TONE_MULTIPLEXING
-# ifndef AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT
-# define AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 0
-// 0=off, good starting value is 4; the lower the value the higher the cpu-load
# endif
-void audio_set_tone_multiplexing_rate(uint16_t rate);
-void audio_enable_tone_multiplexing(void);
-void audio_disable_tone_multiplexing(void);
-void audio_increase_tone_multiplexing_rate(uint16_t change);
-void audio_decrease_tone_multiplexing_rate(uint16_t change);
-#endif
-
-// Tempo functions
-
-void audio_set_tempo(uint8_t tempo);
-void audio_increase_tempo(uint8_t tempo_change);
-void audio_decrease_tempo(uint8_t tempo_change);
-// conversion macros, from 64parts-to-a-beat to milliseconds and back
-uint16_t audio_duration_to_ms(uint16_t duration_bpm);
-uint16_t audio_ms_to_duration(uint16_t duration_ms);
-
-void audio_startup(void);
+#endif
-// hardware interface
+// Polyphony functions
-// implementation in the driver_avr/arm_* respective parts
-void audio_driver_initialize(void);
-void audio_driver_start(void);
-void audio_driver_stop(void);
+void set_polyphony_rate(float rate);
+void enable_polyphony(void);
+void disable_polyphony(void);
+void increase_polyphony_rate(float change);
+void decrease_polyphony_rate(float change);
-/**
- * @brief get the number of currently active tones
- * @return number, 0=none active
- */
-uint8_t audio_get_number_of_active_tones(void);
+void set_timbre(float timbre);
+void set_tempo(uint8_t tempo);
-/**
- * @brief access to the raw/unprocessed frequency for a specific tone
- * @details each active tone has a frequency associated with it, which
- * the internal state keeps track of, and is usually influenced
- * by various effects
- * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
- * first being the most recent and each increment yielding the next
- * older one
- * @return a positive frequency, in Hz; or zero if the tone is a pause
- */
-float audio_get_frequency(uint8_t tone_index);
+void increase_tempo(uint8_t tempo_change);
+void decrease_tempo(uint8_t tempo_change);
-/**
- * @brief calculate and return the frequency for the requested tone
- * @details effects like glissando, vibrato, ... are post-processed onto the
- * each active tones 'base'-frequency; this function returns the
- * post-processed result.
- * @param[in] tone_index, ranging from 0 to number_of_active_tones-1, with the
- * first being the most recent and each increment yielding the next
- * older one
- * @return a positive frequency, in Hz; or zero if the tone is a pause
- */
-float audio_get_processed_frequency(uint8_t tone_index);
+void audio_init(void);
+void audio_startup(void);
-/**
- * @brief update audio internal state: currently playing and active tones,...
- * @details This function is intended to be called by the audio-hardware
- * specific implementation on a somewhat regular basis while a SONG
- * or notes (pitch+duration) are playing to 'advance' the internal
- * state (current playing notes, position in the melody, ...)
- *
- * @return true if something changed in the currently active tones, which the
- * hardware might need to react to
- */
-bool audio_update_state(void);
+#ifdef PWM_AUDIO
+void play_sample(uint8_t* s, uint16_t l, bool r);
+#endif
+void play_note(float freq, int vol);
+void stop_note(float freq);
+void stop_all_notes(void);
+void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat);
-// legacy and back-warts compatibility stuff
+#define SCALE \
+ (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), }
-#define is_audio_on() audio_is_on()
-#define is_playing_notes() audio_is_playing_melody()
-#define is_playing_note() audio_is_playing_note()
-#define stop_all_notes() audio_stop_all()
-#define stop_note(f) audio_stop_tone(f)
-#define play_note(f, v) audio_play_tone(f)
+// These macros are used to allow play_notes to play an array of indeterminate
+// length. This works around the limitation of C's sizeof operation on pointers.
+// The global float array for the song must be used here.
+#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
+#define PLAY_SONG(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), false)
+#define PLAY_LOOP(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), true)
-#define set_timbre(t) voice_set_timbre(t)
-#define set_tempo(t) audio_set_tempo(t)
-#define increase_tempo(t) audio_increase_tempo(t)
-#define decrease_tempo(t) audio_decrease_tempo(t)
-// vibrato functions are not used in any keyboards
+bool is_playing_notes(void);