From 996a19ee7ba3308e17fd347afde0b135852835cc Mon Sep 17 00:00:00 2001 From: Drashna Jael're Date: Tue, 29 Jun 2021 15:36:35 -0700 Subject: Revert "Audio system overhaul (#11820)" due to freezing issues This reverts commit c80e5f9f8868ccaa8cb990be6f4da3f1011c2b78. --- quantum/audio/audio.h | 281 +++++++++----------------------------------------- 1 file changed, 51 insertions(+), 230 deletions(-) (limited to 'quantum/audio/audio.h') 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 . */ + #pragma once #include #include +#if defined(__AVR__) +# include +#endif +#include "wait.h" #include "musical_notes.h" #include "song_list.h" #include "voices.h" #include "quantum.h" #include -#if defined(__AVR__) -# include -# 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(¬e_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(¬e_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(¬e_array, NOTE_ARRAY_SIZE((note_array)), false) +#define PLAY_LOOP(note_array) play_notes(¬e_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); -- cgit v1.2.3