X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=quantum%2Faudio%2Faudio.c;h=c948a60d6cfced46b2369372416b025beb32361d;hb=b29799f8874a86d22b6eca4ce1352f394b276b7a;hp=5b85630932eadb0c1b4915acae3b58bd17872c17;hpb=6a3c66776cb10888b24400526241b46deeb051a8;p=qmk_firmware.git diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c index 5b8563093..c948a60d6 100644 --- a/quantum/audio/audio.c +++ b/quantum/audio/audio.c @@ -17,12 +17,15 @@ #include #include //#include -#include -#include -#include +#if defined(__AVR__) + #include + #include + #include +#endif #include "print.h" #include "audio.h" #include "keymap.h" +#include "wait.h" #include "eeconfig.h" @@ -32,44 +35,81 @@ // Timer Abstractions // ----------------------------------------------------------------------------- -// TIMSK3 - Timer/Counter #3 Interrupt Mask Register -// Turn on/off 3A interputs, stopping/enabling the ISR calls -#ifdef C6_AUDIO +//Currently we support timers 1 and 3 used at the sime time, channels A-C, +//pins PB5, PB6, PB7, PC4, PC5, and PC6 +#if defined(C6_AUDIO) + #define CPIN_AUDIO + #define CPIN_SET_DIRECTION DDRC |= _BV(PORTC6); + #define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) -#endif - -#ifdef B5_AUDIO - #define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1A) - #define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1A) -#endif - -// TCCR3A: Timer/Counter #3 Control Register -// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 - -#ifdef C6_AUDIO #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); + #define TIMER_3_PERIOD ICR3 + #define TIMER_3_DUTY_CYCLE OCR3A + #define TIMER3_AUDIO_vect TIMER3_COMPA_vect #endif - -#ifdef B5_AUDIO - #define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1A1); - #define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0)); +#if defined(C5_AUDIO) + #define CPIN_AUDIO + #define CPIN_SET_DIRECTION DDRC |= _BV(PORTC5); + #define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3B1) | (0 << COM3B0) | (1 << WGM31) | (0 << WGM30); + #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3B) + #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3B) + #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3B1); + #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3B1) | _BV(COM3B0)); + #define TIMER_3_PERIOD ICR3 + #define TIMER_3_DUTY_CYCLE OCR3B + #define TIMER3_AUDIO_vect TIMER3_COMPB_vect #endif - -// Fast PWM Mode Controls - -#ifdef C6_AUDIO +#if defined(C4_AUDIO) + #define CPIN_AUDIO + #define CPIN_SET_DIRECTION DDRC |= _BV(PORTC4); + #define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3C1) | (0 << COM3C0) | (1 << WGM31) | (0 << WGM30); + #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3C) + #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3C) + #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3C1); + #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3C1) | _BV(COM3C0)); #define TIMER_3_PERIOD ICR3 - #define TIMER_3_DUTY_CYCLE OCR3A + #define TIMER_3_DUTY_CYCLE OCR3C + #define TIMER3_AUDIO_vect TIMER3_COMPC_vect #endif -#ifdef B5_AUDIO +#if defined(B5_AUDIO) + #define BPIN_AUDIO + #define BPIN_SET_DIRECTION DDRB |= _BV(PORTB5); + #define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << WGM11) | (0 << WGM10); + #define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1A) + #define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1A) + #define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1A1); + #define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0)); #define TIMER_1_PERIOD ICR1 #define TIMER_1_DUTY_CYCLE OCR1A + #define TIMER1_AUDIO_vect TIMER1_COMPA_vect +#endif +#if defined(B6_AUDIO) + #define BPIN_AUDIO + #define BPIN_SET_DIRECTION DDRB |= _BV(PORTB6); + #define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1B1) | (0 << COM1B0) | (1 << WGM11) | (0 << WGM10); + #define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1B) + #define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1B) + #define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1B1); + #define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1B1) | _BV(COM1B0)); + #define TIMER_1_PERIOD ICR1 + #define TIMER_1_DUTY_CYCLE OCR1B + #define TIMER1_AUDIO_vect TIMER1_COMPB_vect +#endif +#if defined(B7_AUDIO) + #define BPIN_AUDIO + #define BPIN_SET_DIRECTION DDRB |= _BV(PORTB7); + #define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1C1) | (0 << COM1C0) | (1 << WGM11) | (0 << WGM10); + #define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1C) + #define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1C) + #define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1C1); + #define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1C1) | _BV(COM1C0)); + #define TIMER_1_PERIOD ICR1 + #define TIMER_1_DUTY_CYCLE OCR1C + #define TIMER1_AUDIO_vect TIMER1_COMPC_vect #endif - - // ----------------------------------------------------------------------------- @@ -99,7 +139,6 @@ uint16_t note_position = 0; float (* notes_pointer)[][2]; uint16_t notes_count; bool notes_repeat; -float notes_rest; bool note_resting = false; uint8_t current_note = 0; @@ -123,14 +162,19 @@ bool glissando = true; #ifndef STARTUP_SONG #define STARTUP_SONG SONG(STARTUP_SOUND) #endif +#ifndef AUDIO_ON_SONG + #define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND) +#endif +#ifndef AUDIO_OFF_SONG + #define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND) +#endif float startup_song[][2] = STARTUP_SONG; +float audio_on_song[][2] = AUDIO_ON_SONG; +float audio_off_song[][2] = AUDIO_OFF_SONG; void audio_init() { - if (audio_initialized) - return; - // Check EEPROM if (!eeconfig_is_enabled()) { @@ -138,51 +182,56 @@ void audio_init() } audio_config.raw = eeconfig_read_audio(); - // Set port PC6 (OC3A and /OC4A) as output - - #ifdef C6_AUDIO - DDRC |= _BV(PORTC6); - #else - DDRC |= _BV(PORTC6); - PORTC &= ~_BV(PORTC6); - #endif - - #ifdef B5_AUDIO - DDRB |= _BV(PORTB5); - #else - DDRB |= _BV(PORTB5); - PORTB &= ~_BV(PORTB5); - #endif - - #ifdef C6_AUDIO - DISABLE_AUDIO_COUNTER_3_ISR; - #endif - - #ifdef B5_AUDIO - DISABLE_AUDIO_COUNTER_1_ISR; - #endif - - // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers - // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 - // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) - // Clock Select (CS3n) = 0b010 = Clock / 8 - - #ifdef C6_AUDIO - TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); - TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); - #endif + if (!audio_initialized) { - #ifdef B5_AUDIO - TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << WGM11) | (0 << WGM10); - TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); - #endif + // Set audio ports as output + #ifdef CPIN_AUDIO + CPIN_SET_DIRECTION + DISABLE_AUDIO_COUNTER_3_ISR; + #endif + #ifdef BPIN_AUDIO + BPIN_SET_DIRECTION + DISABLE_AUDIO_COUNTER_1_ISR; + #endif - audio_initialized = true; + // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B + // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation + // OC3A -- PC6 + // OC3B -- PC5 + // OC3C -- PC4 + // OC1A -- PB5 + // OC1B -- PB6 + // OC1C -- PB7 + + // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A) + // OCR3A - PC6 + // OCR3B - PC5 + // OCR3C - PC4 + // OCR1A - PB5 + // OCR1B - PB6 + // OCR1C - PB7 + + // Clock Select (CS3n) = 0b010 = Clock / 8 + #ifdef CPIN_AUDIO + INIT_AUDIO_COUNTER_3 + TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); + TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER)); + TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre); + #endif + #ifdef BPIN_AUDIO + INIT_AUDIO_COUNTER_1 + TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); + TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER)); + TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre); + #endif + + audio_initialized = true; + } if (audio_config.enable) { - PLAY_NOTE_ARRAY(startup_song, false, LEGATO); + PLAY_SONG(startup_song); } - + } void stop_all_notes() @@ -194,13 +243,12 @@ void stop_all_notes() } voices = 0; - - #ifdef C6_AUDIO + #ifdef CPIN_AUDIO DISABLE_AUDIO_COUNTER_3_ISR; DISABLE_AUDIO_COUNTER_3_OUTPUT; #endif - #ifdef B5_AUDIO + #ifdef BPIN_AUDIO DISABLE_AUDIO_COUNTER_1_ISR; DISABLE_AUDIO_COUNTER_1_OUTPUT; #endif @@ -246,11 +294,11 @@ void stop_note(float freq) voice_place = 0; } if (voices == 0) { - #ifdef C6_AUDIO + #ifdef CPIN_AUDIO DISABLE_AUDIO_COUNTER_3_ISR; DISABLE_AUDIO_COUNTER_3_OUTPUT; #endif - #ifdef B5_AUDIO + #ifdef BPIN_AUDIO DISABLE_AUDIO_COUNTER_1_ISR; DISABLE_AUDIO_COUNTER_1_OUTPUT; #endif @@ -282,15 +330,15 @@ float vibrato(float average_freq) { #endif -#ifdef C6_AUDIO -ISR(TIMER3_COMPA_vect) +#ifdef CPIN_AUDIO +ISR(TIMER3_AUDIO_vect) { float freq; if (playing_note) { if (voices > 0) { - #ifdef B5_AUDIO + #ifdef BPIN_AUDIO float freq_alt = 0; if (voices > 1) { if (polyphony_rate == 0) { @@ -416,9 +464,12 @@ ISR(TIMER3_COMPA_vect) note_position++; bool end_of_note = false; if (TIMER_3_PERIOD > 0) { - end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); + if (!note_resting) + end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF - 1)); + else + end_of_note = (note_position >= (note_length)); } else { - end_of_note = (note_position >= (note_length * 0x7FF)); + end_of_note = (note_position >= (note_length)); } if (end_of_note) { @@ -433,11 +484,16 @@ ISR(TIMER3_COMPA_vect) return; } } - if (!note_resting && (notes_rest > 0)) { + if (!note_resting) { note_resting = true; - note_frequency = 0; - note_length = notes_rest; current_note--; + if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) { + note_frequency = 0; + note_length = 1; + } else { + note_frequency = (*notes_pointer)[current_note][0]; + note_length = 1; + } } else { note_resting = false; envelope_index = 0; @@ -456,10 +512,10 @@ ISR(TIMER3_COMPA_vect) } #endif -#ifdef B5_AUDIO -ISR(TIMER1_COMPA_vect) +#ifdef BPIN_AUDIO +ISR(TIMER1_AUDIO_vect) { - #if defined(B5_AUDIO) && !defined(C6_AUDIO) + #if defined(BPIN_AUDIO) && !defined(CPIN_AUDIO) float freq = 0; if (playing_note) { @@ -548,9 +604,12 @@ ISR(TIMER1_COMPA_vect) note_position++; bool end_of_note = false; if (TIMER_1_PERIOD > 0) { - end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF)); + if (!note_resting) + end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF - 1)); + else + end_of_note = (note_position >= (note_length)); } else { - end_of_note = (note_position >= (note_length * 0x7FF)); + end_of_note = (note_position >= (note_length)); } if (end_of_note) { @@ -565,11 +624,16 @@ ISR(TIMER1_COMPA_vect) return; } } - if (!note_resting && (notes_rest > 0)) { + if (!note_resting) { note_resting = true; - note_frequency = 0; - note_length = notes_rest; current_note--; + if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) { + note_frequency = 0; + note_length = 1; + } else { + note_frequency = (*notes_pointer)[current_note][0]; + note_length = 1; + } } else { note_resting = false; envelope_index = 0; @@ -598,10 +662,10 @@ void play_note(float freq, int vol) { } if (audio_config.enable && voices < 8) { - #ifdef C6_AUDIO + #ifdef CPIN_AUDIO DISABLE_AUDIO_COUNTER_3_ISR; #endif - #ifdef B5_AUDIO + #ifdef BPIN_AUDIO DISABLE_AUDIO_COUNTER_1_ISR; #endif @@ -619,12 +683,12 @@ void play_note(float freq, int vol) { voices++; } - #ifdef C6_AUDIO + #ifdef CPIN_AUDIO ENABLE_AUDIO_COUNTER_3_ISR; ENABLE_AUDIO_COUNTER_3_OUTPUT; #endif - #ifdef B5_AUDIO - #ifdef C6_AUDIO + #ifdef BPIN_AUDIO + #ifdef CPIN_AUDIO if (voices > 1) { ENABLE_AUDIO_COUNTER_1_ISR; ENABLE_AUDIO_COUNTER_1_OUTPUT; @@ -638,7 +702,7 @@ void play_note(float freq, int vol) { } -void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) +void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) { if (!audio_initialized) { @@ -647,10 +711,10 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) if (audio_config.enable) { - #ifdef C6_AUDIO + #ifdef CPIN_AUDIO DISABLE_AUDIO_COUNTER_3_ISR; #endif - #ifdef B5_AUDIO + #ifdef BPIN_AUDIO DISABLE_AUDIO_COUNTER_1_ISR; #endif @@ -663,7 +727,6 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) notes_pointer = np; notes_count = n_count; notes_repeat = n_repeat; - notes_rest = n_rest; place = 0; current_note = 0; @@ -673,12 +736,12 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) note_position = 0; - #ifdef C6_AUDIO + #ifdef CPIN_AUDIO ENABLE_AUDIO_COUNTER_3_ISR; ENABLE_AUDIO_COUNTER_3_OUTPUT; #endif - #ifdef B5_AUDIO - #ifndef C6_AUDIO + #ifdef BPIN_AUDIO + #ifndef CPIN_AUDIO ENABLE_AUDIO_COUNTER_1_ISR; ENABLE_AUDIO_COUNTER_1_OUTPUT; #endif @@ -706,9 +769,13 @@ void audio_on(void) { audio_config.enable = 1; eeconfig_update_audio(audio_config.raw); audio_on_user(); + PLAY_SONG(audio_on_song); } void audio_off(void) { + PLAY_SONG(audio_off_song); + wait_ms(100); + stop_all_notes(); audio_config.enable = 0; eeconfig_update_audio(audio_config.raw); }