diff options
Diffstat (limited to 'quantum')
-rw-r--r-- | quantum/audio/audio_avr.c | 812 | ||||
-rw-r--r-- | quantum/audio/audio_chibios.c | 726 | ||||
-rw-r--r-- | quantum/audio/voices.c | 3 | ||||
-rw-r--r-- | quantum/audio/voices.h | 1 | ||||
-rw-r--r-- | quantum/dynamic_keymap.c | 17 | ||||
-rw-r--r-- | quantum/keymap_extras/keymap_contributions.h | 372 | ||||
-rw-r--r-- | quantum/keymap_extras/keymap_norwegian.h | 197 | ||||
-rw-r--r-- | quantum/keymap_extras/keymap_spanish_dvorak.h | 4 | ||||
-rw-r--r-- | quantum/keymap_extras/sendstring_dvorak.h | 36 | ||||
-rw-r--r-- | quantum/oryx.c | 249 | ||||
-rw-r--r-- | quantum/oryx.h | 82 | ||||
-rw-r--r-- | quantum/process_keycode/process_auto_shift.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | quantum/process_keycode/process_grave_esc.h | 0 | ||||
-rw-r--r-- | quantum/quantum.c | 22 | ||||
-rw-r--r-- | quantum/quantum.h | 17 | ||||
-rw-r--r-- | quantum/quantum_keycodes.h | 2 | ||||
-rw-r--r-- | quantum/template/base/keymaps/default/keymap.c | 3 |
17 files changed, 2434 insertions, 111 deletions
diff --git a/quantum/audio/audio_avr.c b/quantum/audio/audio_avr.c new file mode 100644 index 0000000000..1bac43bb43 --- /dev/null +++ b/quantum/audio/audio_avr.c @@ -0,0 +1,812 @@ +/* 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 + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <string.h> +//#include <math.h> +#if defined(__AVR__) +# include <avr/pgmspace.h> +# include <avr/interrupt.h> +# include <avr/io.h> +#endif +#include "print.h" +#include "audio.h" +#include "keymap.h" +#include "wait.h" + +#include "eeconfig.h" + +#define CPU_PRESCALER 8 + +// ----------------------------------------------------------------------------- +// Timer Abstractions +// ----------------------------------------------------------------------------- + +// 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) +# 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 +#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 +#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 OCR3C +# define TIMER3_AUDIO_vect TIMER3_COMPC_vect +#endif + +#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 + +#if !defined(BPIN_AUDIO) && !defined(CPIN_AUDIO) +# error "Audio feature enabled, but no suitable pin selected - see docs/feature_audio.md under the AVR settings for available options." +#endif + +// ----------------------------------------------------------------------------- + +int voices = 0; +int voice_place = 0; +float frequency = 0; +float frequency_alt = 0; +int volume = 0; +long position = 0; + +float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +bool sliding = false; + +float place = 0; + +uint8_t* sample; +uint16_t sample_length = 0; + +bool playing_notes = false; +bool playing_note = false; +float note_frequency = 0; +float note_length = 0; +uint8_t note_tempo = TEMPO_DEFAULT; +float note_timbre = TIMBRE_DEFAULT; +uint16_t note_position = 0; +float (*notes_pointer)[][2]; +uint16_t notes_count; +bool notes_repeat; +bool note_resting = false; + +uint16_t current_note = 0; +uint8_t rest_counter = 0; + +#ifdef VIBRATO_ENABLE +float vibrato_counter = 0; +float vibrato_strength = .5; +float vibrato_rate = 0.125; +#endif + +float polyphony_rate = 0; + +static bool audio_initialized = false; + +audio_config_t audio_config; + +uint16_t envelope_index = 0; +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() { + // Check EEPROM + if (!eeconfig_is_enabled()) { + eeconfig_init(); + } + audio_config.raw = eeconfig_read_audio(); + + if (!audio_initialized) { +// 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 + +// 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; + } +} + +void audio_startup() { + if (audio_config.enable) { + PLAY_SONG(startup_song); + } +} + +void stop_all_notes() { + dprintf("audio stop all notes"); + + if (!audio_initialized) { + audio_init(); + } + voices = 0; + +#ifdef CPIN_AUDIO + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; +#endif + +#ifdef BPIN_AUDIO + DISABLE_AUDIO_COUNTER_1_ISR; + DISABLE_AUDIO_COUNTER_1_OUTPUT; +#endif + + playing_notes = false; + playing_note = false; + frequency = 0; + frequency_alt = 0; + volume = 0; + + for (uint8_t i = 0; i < 8; i++) { + frequencies[i] = 0; + volumes[i] = 0; + } +} + +void stop_note(float freq) { + dprintf("audio stop note freq=%d", (int)freq); + + if (playing_note) { + if (!audio_initialized) { + audio_init(); + } + for (int i = 7; i >= 0; i--) { + if (frequencies[i] == freq) { + frequencies[i] = 0; + volumes[i] = 0; + for (int j = i; (j < 7); j++) { + frequencies[j] = frequencies[j + 1]; + frequencies[j + 1] = 0; + volumes[j] = volumes[j + 1]; + volumes[j + 1] = 0; + } + break; + } + } + voices--; + if (voices < 0) voices = 0; + if (voice_place >= voices) { + voice_place = 0; + } + if (voices == 0) { +#ifdef CPIN_AUDIO + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; +#endif +#ifdef BPIN_AUDIO + DISABLE_AUDIO_COUNTER_1_ISR; + DISABLE_AUDIO_COUNTER_1_OUTPUT; +#endif + frequency = 0; + frequency_alt = 0; + volume = 0; + playing_note = false; + } + } +} + +#ifdef VIBRATO_ENABLE + +float mod(float a, int b) { + float r = fmod(a, b); + return r < 0 ? r + b : r; +} + +float vibrato(float average_freq) { +# ifdef VIBRATO_STRENGTH_ENABLE + float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); +# else + float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; +# endif + vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH); + return vibrated_freq; +} + +#endif + +#ifdef CPIN_AUDIO +ISR(TIMER3_AUDIO_vect) { + float freq; + + if (playing_note) { + if (voices > 0) { +# ifdef BPIN_AUDIO + float freq_alt = 0; + if (voices > 1) { + if (polyphony_rate == 0) { + if (glissando) { + if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) { + frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2); + } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) { + frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2); + } else { + frequency_alt = frequencies[voices - 2]; + } + } else { + frequency_alt = frequencies[voices - 2]; + } + +# ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq_alt = vibrato(frequency_alt); + } else { + freq_alt = frequency_alt; + } +# else + freq_alt = frequency_alt; +# endif + } + + if (envelope_index < 65535) { + envelope_index++; + } + + freq_alt = voice_envelope(freq_alt); + + if (freq_alt < 30.517578125) { + freq_alt = 30.52; + } + + TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq_alt * CPU_PRESCALER)); + TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq_alt * CPU_PRESCALER)) * note_timbre); + } +# endif + + if (polyphony_rate > 0) { + if (voices > 1) { + voice_place %= voices; + if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { + voice_place = (voice_place + 1) % voices; + place = 0.0; + } + } + +# ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequencies[voice_place]); + } else { + freq = frequencies[voice_place]; + } +# else + freq = frequencies[voice_place]; +# endif + } else { + if (glissando) { + if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) { + frequency = frequency * pow(2, 440 / frequency / 12 / 2); + } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) { + frequency = frequency * pow(2, -440 / frequency / 12 / 2); + } else { + frequency = frequencies[voices - 1]; + } + } else { + frequency = frequencies[voices - 1]; + } + +# ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequency); + } else { + freq = frequency; + } +# else + freq = frequency; +# endif + } + + if (envelope_index < 65535) { + envelope_index++; + } + + freq = voice_envelope(freq); + + if (freq < 30.517578125) { + freq = 30.52; + } + + TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); + TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); + } + } + + if (playing_notes) { + if (note_frequency > 0) { +# ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(note_frequency); + } else { + freq = note_frequency; + } +# else + freq = note_frequency; +# endif + + if (envelope_index < 65535) { + envelope_index++; + } + freq = voice_envelope(freq); + + TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); + TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); + } else { + TIMER_3_PERIOD = 0; + TIMER_3_DUTY_CYCLE = 0; + } + + note_position++; + bool end_of_note = false; + if (TIMER_3_PERIOD > 0) { + 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)); + } + + if (end_of_note) { + current_note++; + if (current_note >= notes_count) { + if (notes_repeat) { + current_note = 0; + } else { + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; + playing_notes = false; + return; + } + } + if (!note_resting) { + note_resting = true; + 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; + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + } + + note_position = 0; + } + } + + if (!audio_config.enable) { + playing_notes = false; + playing_note = false; + } +} +#endif + +#ifdef BPIN_AUDIO +ISR(TIMER1_AUDIO_vect) { +# if defined(BPIN_AUDIO) && !defined(CPIN_AUDIO) + float freq = 0; + + if (playing_note) { + if (voices > 0) { + if (polyphony_rate > 0) { + if (voices > 1) { + voice_place %= voices; + if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { + voice_place = (voice_place + 1) % voices; + place = 0.0; + } + } + +# ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequencies[voice_place]); + } else { + freq = frequencies[voice_place]; + } +# else + freq = frequencies[voice_place]; +# endif + } else { + if (glissando) { + if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) { + frequency = frequency * pow(2, 440 / frequency / 12 / 2); + } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) { + frequency = frequency * pow(2, -440 / frequency / 12 / 2); + } else { + frequency = frequencies[voices - 1]; + } + } else { + frequency = frequencies[voices - 1]; + } + +# ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequency); + } else { + freq = frequency; + } +# else + freq = frequency; +# endif + } + + if (envelope_index < 65535) { + envelope_index++; + } + + freq = voice_envelope(freq); + + if (freq < 30.517578125) { + freq = 30.52; + } + + TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); + TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); + } + } + + if (playing_notes) { + if (note_frequency > 0) { +# ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(note_frequency); + } else { + freq = note_frequency; + } +# else + freq = note_frequency; +# endif + + if (envelope_index < 65535) { + envelope_index++; + } + freq = voice_envelope(freq); + + TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); + TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); + } else { + TIMER_1_PERIOD = 0; + TIMER_1_DUTY_CYCLE = 0; + } + + note_position++; + bool end_of_note = false; + if (TIMER_1_PERIOD > 0) { + 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)); + } + + if (end_of_note) { + current_note++; + if (current_note >= notes_count) { + if (notes_repeat) { + current_note = 0; + } else { + DISABLE_AUDIO_COUNTER_1_ISR; + DISABLE_AUDIO_COUNTER_1_OUTPUT; + playing_notes = false; + return; + } + } + if (!note_resting) { + note_resting = true; + 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; + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + } + + note_position = 0; + } + } + + if (!audio_config.enable) { + playing_notes = false; + playing_note = false; + } +# endif +} +#endif + +void play_note(float freq, int vol) { + dprintf("audio play note freq=%d vol=%d", (int)freq, vol); + + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable && voices < 8) { +#ifdef CPIN_AUDIO + DISABLE_AUDIO_COUNTER_3_ISR; +#endif +#ifdef BPIN_AUDIO + DISABLE_AUDIO_COUNTER_1_ISR; +#endif + + // Cancel notes if notes are playing + if (playing_notes) stop_all_notes(); + + playing_note = true; + + envelope_index = 0; + + if (freq > 0) { + frequencies[voices] = freq; + volumes[voices] = vol; + voices++; + } + +#ifdef CPIN_AUDIO + ENABLE_AUDIO_COUNTER_3_ISR; + ENABLE_AUDIO_COUNTER_3_OUTPUT; +#endif +#ifdef BPIN_AUDIO +# ifdef CPIN_AUDIO + if (voices > 1) { + ENABLE_AUDIO_COUNTER_1_ISR; + ENABLE_AUDIO_COUNTER_1_OUTPUT; + } +# else + ENABLE_AUDIO_COUNTER_1_ISR; + ENABLE_AUDIO_COUNTER_1_OUTPUT; +# endif +#endif + } +} + +void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) { + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable) { +#ifdef CPIN_AUDIO + DISABLE_AUDIO_COUNTER_3_ISR; +#endif +#ifdef BPIN_AUDIO + DISABLE_AUDIO_COUNTER_1_ISR; +#endif + + // Cancel note if a note is playing + if (playing_note) stop_all_notes(); + + playing_notes = true; + + notes_pointer = np; + notes_count = n_count; + notes_repeat = n_repeat; + + place = 0; + current_note = 0; + + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + note_position = 0; + +#ifdef CPIN_AUDIO + ENABLE_AUDIO_COUNTER_3_ISR; + ENABLE_AUDIO_COUNTER_3_OUTPUT; +#endif +#ifdef BPIN_AUDIO +# ifndef CPIN_AUDIO + ENABLE_AUDIO_COUNTER_1_ISR; + ENABLE_AUDIO_COUNTER_1_OUTPUT; +# endif +#endif + } +} + +bool is_playing_notes(void) { return playing_notes; } + +bool is_audio_on(void) { return (audio_config.enable != 0); } + +void audio_toggle(void) { + audio_config.enable ^= 1; + eeconfig_update_audio(audio_config.raw); + if (audio_config.enable) audio_on_user(); +} + +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); +} + +#ifdef VIBRATO_ENABLE + +// Vibrato rate functions + +void set_vibrato_rate(float rate) { vibrato_rate = rate; } + +void increase_vibrato_rate(float change) { vibrato_rate *= change; } + +void decrease_vibrato_rate(float change) { vibrato_rate /= change; } + +# ifdef VIBRATO_STRENGTH_ENABLE + +void set_vibrato_strength(float strength) { vibrato_strength = strength; } + +void increase_vibrato_strength(float change) { vibrato_strength *= change; } + +void decrease_vibrato_strength(float change) { vibrato_strength /= change; } + +# endif /* VIBRATO_STRENGTH_ENABLE */ + +#endif /* VIBRATO_ENABLE */ + +// Polyphony functions + +void set_polyphony_rate(float rate) { polyphony_rate = rate; } + +void enable_polyphony() { polyphony_rate = 5; } + +void disable_polyphony() { polyphony_rate = 0; } + +void increase_polyphony_rate(float change) { polyphony_rate *= change; } + +void decrease_polyphony_rate(float change) { polyphony_rate /= change; } + +// Timbre function + +void set_timbre(float timbre) { note_timbre = timbre; } + +// Tempo functions + +void set_tempo(uint8_t tempo) { note_tempo = tempo; } + +void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; } + +void increase_tempo(uint8_t tempo_change) { + if (note_tempo - tempo_change < 10) { + note_tempo = 10; + } else { + note_tempo -= tempo_change; + } +} diff --git a/quantum/audio/audio_chibios.c b/quantum/audio/audio_chibios.c new file mode 100644 index 0000000000..377f93de5d --- /dev/null +++ b/quantum/audio/audio_chibios.c @@ -0,0 +1,726 @@ +/* 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 + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "audio.h" +#include <ch.h> +#include <hal.h> + +#include <string.h> +#include "print.h" +#include "keymap.h" + +#include "eeconfig.h" + +// ----------------------------------------------------------------------------- + +int voices = 0; +int voice_place = 0; +float frequency = 0; +float frequency_alt = 0; +int volume = 0; +long position = 0; + +float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +bool sliding = false; + +float place = 0; + +uint8_t *sample; +uint16_t sample_length = 0; + +bool playing_notes = false; +bool playing_note = false; +float note_frequency = 0; +float note_length = 0; +uint8_t note_tempo = TEMPO_DEFAULT; +float note_timbre = TIMBRE_DEFAULT; +uint16_t note_position = 0; +float (*notes_pointer)[][2]; +uint16_t notes_count; +bool notes_repeat; +bool note_resting = false; + +uint16_t current_note = 0; +uint8_t rest_counter = 0; + +#ifdef VIBRATO_ENABLE +float vibrato_counter = 0; +float vibrato_strength = .5; +float vibrato_rate = 0.125; +#endif + +float polyphony_rate = 0; + +static bool audio_initialized = false; + +audio_config_t audio_config; + +uint16_t envelope_index = 0; +bool glissando = true; + +#ifndef STARTUP_SONG +# define STARTUP_SONG SONG(STARTUP_SOUND) +#endif +float startup_song[][2] = STARTUP_SONG; + +static void gpt_cb8(GPTDriver *gptp); + +#define DAC_BUFFER_SIZE 100 +#ifndef DAC_SAMPLE_MAX +# define DAC_SAMPLE_MAX 65535U +#endif + +#define START_CHANNEL_1() \ + gptStart(&GPTD6, &gpt6cfg1); \ + gptStartContinuous(&GPTD6, 2U); \ + palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG) + +#define START_CHANNEL_2() \ + gptStart(&GPTD7, &gpt7cfg1); \ + gptStartContinuous(&GPTD7, 2U); \ + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG) + +#define STOP_CHANNEL_1() \ + gptStopTimer(&GPTD6); \ + palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL); \ + palSetPad(GPIOA, 4) + +#define STOP_CHANNEL_2() \ + gptStopTimer(&GPTD7); \ + palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); \ + palSetPad(GPIOA, 5) + + +#define RESTART_CHANNEL_1() \ + STOP_CHANNEL_1(); \ + START_CHANNEL_1() +#define RESTART_CHANNEL_2() \ + STOP_CHANNEL_2(); \ + START_CHANNEL_2() +#define UPDATE_CHANNEL_1_FREQ(freq) \ + gpt6cfg1.frequency = freq * DAC_BUFFER_SIZE; \ + RESTART_CHANNEL_1() +#define UPDATE_CHANNEL_2_FREQ(freq) \ + gpt7cfg1.frequency = freq * DAC_BUFFER_SIZE; \ + RESTART_CHANNEL_2() +#define GET_CHANNEL_1_FREQ (uint16_t)(gpt6cfg1.frequency * DAC_BUFFER_SIZE) +#define GET_CHANNEL_2_FREQ (uint16_t)(gpt7cfg1.frequency * DAC_BUFFER_SIZE) + +/* + * GPT6 configuration. + */ +// static const GPTConfig gpt6cfg1 = { +// .frequency = 1000000U, +// .callback = NULL, +// .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ +// .dier = 0U +// }; + +GPTConfig gpt6cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE, + .callback = NULL, + .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ + .dier = 0U}; + +GPTConfig gpt7cfg1 = {.frequency = 440U * DAC_BUFFER_SIZE, + .callback = NULL, + .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ + .dier = 0U}; + +GPTConfig gpt8cfg1 = {.frequency = 10, + .callback = gpt_cb8, + .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ + .dier = 0U}; + +/* + * DAC test buffer (sine wave). + */ +// static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = { +// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437, +// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846, +// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221, +// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544, +// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801, +// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982, +// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078, +// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086, +// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004, +// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837, +// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591, +// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278, +// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912, +// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507, +// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082, +// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657, +// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248, +// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873, +// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550, +// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293, +// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112, +// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16, +// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8, +// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90, +// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257, +// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503, +// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816, +// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182, +// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587, +// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012 +// }; + +// static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = { +// 12, 8, 5, 3, 2, 1, 0, 1, 2, 3, 5, 8, +// 12, 16, 20, 26, 32, 38, 45, 53, 61, 70, 80, 90, +// 101, 112, 124, 136, 150, 163, 177, 192, 208, 224, 240, 257, +// 275, 293, 312, 331, 350, 371, 391, 413, 434, 457, 479, 503, +// 526, 550, 575, 600, 626, 651, 678, 705, 732, 759, 787, 816, +// 844, 873, 903, 933, 963, 993, 1024, 1055, 1086, 1118, 1150, 1182, +// 1215, 1248, 1281, 1314, 1347, 1381, 1415, 1449, 1483, 1518, 1552, 1587, +// 1622, 1657, 1692, 1727, 1763, 1798, 1834, 1869, 1905, 1940, 1976, 2012, +// 2047, 2082, 2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437, +// 2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 2813, 2846, +// 2879, 2912, 2944, 2976, 3008, 3039, 3070, 3101, 3131, 3161, 3191, 3221, +// 3250, 3278, 3307, 3335, 3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544, +// 3568, 3591, 3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801, +// 3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 3970, 3982, +// 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4062, 4068, 4074, 4078, +// 4082, 4086, 4089, 4091, 4092, 4093, 4094, 4093, 4092, 4091, 4089, 4086, +// 4082, 4078, 4074, 4068, 4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004, +// 3993, 3982, 3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837, +// 3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 3615, 3591, +// 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 3362, 3335, 3307, 3278, +// 3250, 3221, 3191, 3161, 3131, 3101, 3070, 3039, 3008, 2976, 2944, 2912, +// 2879, 2846, 2813, 2780, 2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507, +// 2472, 2437, 2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082, +// 2047, 2012, 1976, 1940, 1905, 1869, 1834, 1798, 1763, 1727, 1692, 1657, +// 1622, 1587, 1552, 1518, 1483, 1449, 1415, 1381, 1347, 1314, 1281, 1248, +// 1215, 1182, 1150, 1118, 1086, 1055, 1024, 993, 963, 933, 903, 873, +// 844, 816, 787, 759, 732, 705, 678, 651, 626, 600, 575, 550, +// 526, 503, 479, 457, 434, 413, 391, 371, 350, 331, 312, 293, +// 275, 257, 240, 224, 208, 192, 177, 163, 150, 136, 124, 112, +// 101, 90, 80, 70, 61, 53, 45, 38, 32, 26, 20, 16 +// }; + +// squarewave +static const dacsample_t dac_buffer[DAC_BUFFER_SIZE] = { + // First half is max, second half is 0 + [0 ... DAC_BUFFER_SIZE / 2 - 1] = DAC_SAMPLE_MAX, + [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = 0, +}; + +// squarewave +static const dacsample_t dac_buffer_2[DAC_BUFFER_SIZE] = { + // opposite of dac_buffer above + [0 ... DAC_BUFFER_SIZE / 2 - 1] = 0, + [DAC_BUFFER_SIZE / 2 ... DAC_BUFFER_SIZE - 1] = DAC_SAMPLE_MAX, +}; + +/* + * DAC streaming callback. + */ +size_t nz = 0; +static void end_cb1(DACDriver *dacp) { + (void)dacp; + + nz++; + if ((nz % 1000) == 0) { + // palTogglePad(GPIOD, GPIOD_LED3); + } +} + +/* + * DAC error callback. + */ +static void error_cb1(DACDriver *dacp, dacerror_t err) { + (void)dacp; + (void)err; + + chSysHalt("DAC failure"); +} + +static const DACConfig dac1cfg1 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT}; + +static const DACConversionGroup dacgrpcfg1 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)}; + +static const DACConfig dac1cfg2 = {.init = DAC_SAMPLE_MAX, .datamode = DAC_DHRM_12BIT_RIGHT}; + +static const DACConversionGroup dacgrpcfg2 = {.num_channels = 1U, .end_cb = end_cb1, .error_cb = error_cb1, .trigger = DAC_TRG(0)}; + +void audio_init() { + if (audio_initialized) { + return; + } + +// Check EEPROM +#ifdef EEPROM_ENABLE + if (!eeconfig_is_enabled()) { + eeconfig_init(); + } + audio_config.raw = eeconfig_read_audio(); +#else // ARM EEPROM + audio_config.enable = true; +# ifdef AUDIO_CLICKY_ON + audio_config.clicky_enable = true; +# endif +#endif // ARM EEPROM + + /* + * Starting DAC1 driver, setting up the output pin as analog as suggested + * by the Reference Manual. + */ + palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); + dacStart(&DACD1, &dac1cfg1); + dacStart(&DACD2, &dac1cfg2); + + /* + * Start the note timer + */ + gptStart(&GPTD8, &gpt8cfg1); + gptStartContinuous(&GPTD8, 2U); + + /* + * Starting GPT6/7 driver, it is used for triggering the DAC. + */ + START_CHANNEL_1(); + START_CHANNEL_2(); + + /* + * Starting a continuous conversion. + */ + dacStartConversion(&DACD1, &dacgrpcfg1, (dacsample_t *)dac_buffer, DAC_BUFFER_SIZE); + dacStartConversion(&DACD2, &dacgrpcfg2, (dacsample_t *)dac_buffer_2, DAC_BUFFER_SIZE); + + audio_initialized = true; + + stop_all_notes(); +} + +void audio_startup() { + if (audio_config.enable) { + PLAY_SONG(startup_song); + } +} + +void stop_all_notes() { + dprintf("audio stop all notes"); + + if (!audio_initialized) { + audio_init(); + } + voices = 0; + + gptStopTimer(&GPTD6); + gptStopTimer(&GPTD7); + gptStopTimer(&GPTD8); + + playing_notes = false; + playing_note = false; + frequency = 0; + frequency_alt = 0; + volume = 0; + + for (uint8_t i = 0; i < 8; i++) { + frequencies[i] = 0; + volumes[i] = 0; + } +} + +void stop_note(float freq) { + dprintf("audio stop note freq=%d", (int)freq); + + if (playing_note) { + if (!audio_initialized) { + audio_init(); + } + for (int i = 7; i >= 0; i--) { + if (frequencies[i] == freq) { + frequencies[i] = 0; + volumes[i] = 0; + for (int j = i; (j < 7); j++) { + frequencies[j] = frequencies[j + 1]; + frequencies[j + 1] = 0; + volumes[j] = volumes[j + 1]; + volumes[j + 1] = 0; + } + break; + } + } + voices--; + if (voices < 0) { + voices = 0; + } + if (voice_place >= voices) { + voice_place = 0; + } + if (voices == 0) { + STOP_CHANNEL_1(); + STOP_CHANNEL_2(); + gptStopTimer(&GPTD8); + frequency = 0; + frequency_alt = 0; + volume = 0; + playing_note = false; + } + } +} + +#ifdef VIBRATO_ENABLE + +float mod(float a, int b) { + float r = fmod(a, b); + return r < 0 ? r + b : r; +} + +float vibrato(float average_freq) { +# ifdef VIBRATO_STRENGTH_ENABLE + float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); +# else + float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; +# endif + vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH); + return vibrated_freq; +} + +#endif + +static void gpt_cb8(GPTDriver *gptp) { + float freq; + + if (playing_note) { + if (voices > 0) { + float freq_alt = 0; + if (voices > 1) { + if (polyphony_rate == 0) { + if (glissando) { + if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) { + frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2); + } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) { + frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2); + } else { + frequency_alt = frequencies[voices - 2]; + } + } else { + frequency_alt = frequencies[voices - 2]; + } + +#ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq_alt = vibrato(frequency_alt); + } else { + freq_alt = frequency_alt; + } +#else + freq_alt = frequency_alt; +#endif + } + + if (envelope_index < 65535) { + envelope_index++; + } + + freq_alt = voice_envelope(freq_alt); + + if (freq_alt < 30.517578125) { + freq_alt = 30.52; + } + + if (GET_CHANNEL_2_FREQ != (uint16_t)freq_alt) { + UPDATE_CHANNEL_2_FREQ(freq_alt); + } else { + RESTART_CHANNEL_2(); + } + // note_timbre; + } + + if (polyphony_rate > 0) { + if (voices > 1) { + voice_place %= voices; + if (place++ > (frequencies[voice_place] / polyphony_rate)) { + voice_place = (voice_place + 1) % voices; + place = 0.0; + } + } + +#ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequencies[voice_place]); + } else { + freq = frequencies[voice_place]; + } +#else + freq = frequencies[voice_place]; +#endif + } else { + if (glissando) { + if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) { + frequency = frequency * pow(2, 440 / frequency / 12 / 2); + } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) { + frequency = frequency * pow(2, -440 / frequency / 12 / 2); + } else { + frequency = frequencies[voices - 1]; + } + } else { + frequency = frequencies[voices - 1]; + } + +#ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequency); + } else { + freq = frequency; + } +#else + freq = frequency; +#endif + } + + if (envelope_index < 65535) { + envelope_index++; + } + + freq = voice_envelope(freq); + + if (freq < 30.517578125) { + freq = 30.52; + } + + if (GET_CHANNEL_1_FREQ != (uint16_t)freq) { + UPDATE_CHANNEL_1_FREQ(freq); + } else { + RESTART_CHANNEL_1(); + } + // note_timbre; + } + } + + if (playing_notes) { + if (note_frequency > 0) { +#ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(note_frequency); + } else { + freq = note_frequency; + } +#else + freq = note_frequency; +#endif + + if (envelope_index < 65535) { + envelope_index++; + } + freq = voice_envelope(freq); + + if (GET_CHANNEL_1_FREQ != (uint16_t)freq) { + UPDATE_CHANNEL_1_FREQ(freq); + UPDATE_CHANNEL_2_FREQ(freq); + } + // note_timbre; + } else { + // gptStopTimer(&GPTD6); + // gptStopTimer(&GPTD7); + } + + note_position++; + bool end_of_note = false; + if (GET_CHANNEL_1_FREQ > 0) { + if (!note_resting) + end_of_note = (note_position >= (note_length * 8 - 1)); + else + end_of_note = (note_position >= (note_length * 8)); + } else { + end_of_note = (note_position >= (note_length * 8)); + } + + if (end_of_note) { + current_note++; + if (current_note >= notes_count) { + if (notes_repeat) { + current_note = 0; + } else { + STOP_CHANNEL_1(); + STOP_CHANNEL_2(); + // gptStopTimer(&GPTD8); + playing_notes = false; + return; + } + } + if (!note_resting) { + note_resting = true; + 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; + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + } + + note_position = 0; + } + } + + if (!audio_config.enable) { + playing_notes = false; + playing_note = false; + } +} + +void play_note(float freq, int vol) { + dprintf("audio play note freq=%d vol=%d", (int)freq, vol); + + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable && voices < 8) { + // Cancel notes if notes are playing + if (playing_notes) { + stop_all_notes(); + } + + playing_note = true; + + envelope_index = 0; + + if (freq > 0) { + frequencies[voices] = freq; + volumes[voices] = vol; + voices++; + } + + gptStart(&GPTD8, &gpt8cfg1); + gptStartContinuous(&GPTD8, 2U); + RESTART_CHANNEL_1(); + RESTART_CHANNEL_2(); + } +} + +void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) { + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable) { + // Cancel note if a note is playing + if (playing_note) { + stop_all_notes(); + } + + playing_notes = true; + + notes_pointer = np; + notes_count = n_count; + notes_repeat = n_repeat; + + place = 0; + current_note = 0; + + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + note_position = 0; + + gptStart(&GPTD8, &gpt8cfg1); + gptStartContinuous(&GPTD8, 2U); + RESTART_CHANNEL_1(); + RESTART_CHANNEL_2(); + } +} + +bool is_playing_notes(void) { return playing_notes; } + +bool is_audio_on(void) { return (audio_config.enable != 0); } + +void audio_toggle(void) { + if (audio_config.enable) { + stop_all_notes(); + } + audio_config.enable ^= 1; + eeconfig_update_audio(audio_config.raw); + if (audio_config.enable) { + audio_on_user(); + } +} + +void audio_on(void) { + audio_config.enable = 1; + eeconfig_update_audio(audio_config.raw); + audio_on_user(); +} + +void audio_off(void) { + stop_all_notes(); + audio_config.enable = 0; + eeconfig_update_audio(audio_config.raw); +} + +#ifdef VIBRATO_ENABLE + +// Vibrato rate functions + +void set_vibrato_rate(float rate) { vibrato_rate = rate; } + +void increase_vibrato_rate(float change) { vibrato_rate *= change; } + +void decrease_vibrato_rate(float change) { vibrato_rate /= change; } + +# ifdef VIBRATO_STRENGTH_ENABLE + +void set_vibrato_strength(float strength) { vibrato_strength = strength; } + +void increase_vibrato_strength(float change) { vibrato_strength *= change; } + +void decrease_vibrato_strength(float change) { vibrato_strength /= change; } + +# endif /* VIBRATO_STRENGTH_ENABLE */ + +#endif /* VIBRATO_ENABLE */ + +// Polyphony functions + +void set_polyphony_rate(float rate) { polyphony_rate = rate; } + +void enable_polyphony() { polyphony_rate = 5; } + +void disable_polyphony() { polyphony_rate = 0; } + +void increase_polyphony_rate(float change) { polyphony_rate *= change; } + +void decrease_polyphony_rate(float change) { polyphony_rate /= change; } + +// Timbre function + +void set_timbre(float timbre) { note_timbre = timbre; } + +// Tempo functions + +void set_tempo(uint8_t tempo) { note_tempo = tempo; } + +void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; } + +void increase_tempo(uint8_t tempo_change) { + if (note_tempo - tempo_change < 10) { + note_tempo = 10; + } else { + note_tempo -= tempo_change; + } +} diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c index 8988d827e9..d43fb8d169 100644 --- a/quantum/audio/voices.c +++ b/quantum/audio/voices.c @@ -35,7 +35,6 @@ voice_type voice = default_voice; void set_voice(voice_type v) { voice = v; } void voice_iterate() { voice = (voice + 1) % number_of_voices; } - void voice_deiterate() { voice = (voice - 1 + number_of_voices) % number_of_voices; } #ifdef AUDIO_VOICES @@ -257,7 +256,7 @@ float voice_envelope(float frequency) { case 0 ... VOICE_VIBRATO_DELAY: break; default: - // TODO: merge/replace with voice_add_vibrato above + frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1)) / 1000 * VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; break; } diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h index 578350d337..7bd26b461f 100644 --- a/quantum/audio/voices.h +++ b/quantum/audio/voices.h @@ -14,6 +14,7 @@ * 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> diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index b7a9f2662c..f76f37f997 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c @@ -14,13 +14,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "keymap.h" // to get keymaps[][][] + #include "tmk_core/common/eeprom.h" -#include "progmem.h" // to read default from flash #include "quantum.h" // for send_string() -#include "dynamic_keymap.h" -#include "via.h" // for default VIA_EEPROM_ADDR_END +#include "eeconfig.h" #ifndef DYNAMIC_KEYMAP_LAYER_COUNT # define DYNAMIC_KEYMAP_LAYER_COUNT 4 @@ -54,10 +51,14 @@ // If DYNAMIC_KEYMAP_EEPROM_ADDR not explicitly defined in config.h, // default it start after VIA_EEPROM_CUSTOM_ADDR+VIA_EEPROM_CUSTOM_SIZE #ifndef DYNAMIC_KEYMAP_EEPROM_ADDR -# ifdef VIA_EEPROM_CUSTOM_CONFIG_ADDR -# define DYNAMIC_KEYMAP_EEPROM_ADDR (VIA_EEPROM_CUSTOM_CONFIG_ADDR + VIA_EEPROM_CUSTOM_CONFIG_SIZE) +# ifdef VIA_ENABLE +# ifdef VIA_EEPROM_CUSTOM_CONFIG_ADDR +# define DYNAMIC_KEYMAP_EEPROM_ADDR (VIA_EEPROM_CUSTOM_CONFIG_ADDR + VIA_EEPROM_CUSTOM_CONFIG_SIZE) +# else +# error DYNAMIC_KEYMAP_EEPROM_ADDR not defined +# endif # else -# error DYNAMIC_KEYMAP_EEPROM_ADDR not defined +# define DYNAMIC_KEYMAP_EEPROM_ADDR EECONFIG_SIZE # endif #endif diff --git a/quantum/keymap_extras/keymap_contributions.h b/quantum/keymap_extras/keymap_contributions.h new file mode 100644 index 0000000000..2e505eb74d --- /dev/null +++ b/quantum/keymap_extras/keymap_contributions.h @@ -0,0 +1,372 @@ +/* If you’d like to contribute a locale, we've created a google sheet: + * https://docs.google.com/spreadsheets/d/1gSB063BTHLTNLSGalzkhqz82RdBRVQytXKlabhX5Zcg/edit?usp=sharing + * Get in touch with us over email <contact@zsa.io> and we can help you get started! + */ + +//Polish programmer, contributed by Krzysztof Bogacz. +#define PL_01 ALGR(KC_Z) // ż +#define PL_02 ALGR(KC_X) // ź +#define PL_03 ALGR(KC_S) // ś +#define PL_04 ALGR(KC_O) // ó +#define PL_05 ALGR(KC_N) // ń +#define PL_06 ALGR(KC_L) // ł +#define PL_07 ALGR(KC_E) // ę +#define PL_08 ALGR(KC_C) // ć +#define PL_09 ALGR(KC_A) // ą + +//Kazakh, contributed by Zhanibek Adilbekov +#define KK_01 KC_SLASH // № +#define KK_02 KC_DOT // ю +#define KK_03 KC_COMMA // б +#define KK_04 KC_M // ь +#define KK_05 KC_N // т +#define KK_06 KC_B // и +#define KK_07 KC_V // м +#define KK_08 KC_X // ч +#define KK_09 KC_Z // я +#define KK_10 KC_QUOTE // э +#define KK_11 KC_SCOLON // ж +#define KK_12 KC_L // д +#define KK_13 KC_K // л +#define KK_14 KC_J // о +#define KK_15 KC_H // р +#define KK_16 KC_G // п +#define KK_17 KC_F // а +#define KK_18 KC_D // в +#define KK_19 KC_S // ы +#define KK_20 KC_A // ф +#define KK_21 KC_RBRACKET // ъ +#define KK_22 KC_LBRACKET // х +#define KK_23 KC_P // з +#define KK_24 KC_O // щ +#define KK_25 KC_I // ш +#define KK_26 KC_U // г +#define KK_27 KC_Y // н +#define KK_28 KC_T // е +#define KK_29 KC_R // к +#define KK_30 KC_E // у +#define KK_31 KC_W // ц +#define KK_32 KC_Q // й +#define KK_33 KC_EQUAL // һ +#define KK_34 KC_MINUS // ө +#define KK_35 KC_0 // қ +#define KK_36 KC_9 // ұ +#define KK_37 KC_8 // ү +#define KK_38 KC_7 // . +#define KK_39 KC_6 // , +#define KK_40 KC_5 // ғ +#define KK_41 KC_4 // ң +#define KK_42 KC_3 // і +#define KK_43 KC_2 // ә +#define KK_44 KC_1 // " + +//Portuguese OSX, contributed by André Cruz (@edevil) +#define PT_OSX_SECT KC_GRV // § +#define PT_OSX_QUOT KC_MINS // ' +#define PT_OSX_PLUS KC_EQL // + +#define PT_OSX_MORD KC_LBRC // º +#define PT_OSX_ACUT KC_RBRC // ´ (dead) +#define PT_OSX_CCED KC_SCLN // Ç +#define PT_OSX_TILD KC_QUOT // ~ (dead) +#define PT_OSX_BSLS KC_NUHS // (backslash) +#define PT_OSX_LABK KC_NUBS // < +#define PT_OSX_MINS KC_SLSH // - +#define PT_OSX_PLMN S(PT_OSX_SECT) // ± +#define PT_OSX_EXLM S(KC_1) // ! +#define PT_OSX_DQUO S(KC_2) // " +#define PT_OSX_HASH S(KC_3) // # +#define PT_OSX_DLR S(KC_4) // $ +#define PT_OSX_PERC S(KC_5) // % +#define PT_OSX_AMPR S(KC_6) // & +#define PT_OSX_SLSH S(KC_7) // / +#define PT_OSX_LPRN S(KC_8) // ( +#define PT_OSX_RPRN S(KC_9) // ) +#define PT_OSX_EQL S(KC_0) // = +#define PT_OSX_QUES S(PT_OSX_QUOT) // ? +#define PT_OSX_ASTR S(PT_OSX_PLUS) // * +#define PT_OSX_FORD S(PT_OSX_MORD) // ª +#define PT_OSX_GRV S(PT_OSX_ACUT) // ` (dead) +#define PT_OSX_CIRC S(PT_OSX_TILD) // ^ (dead) +#define PT_OSX_PIPE S(PT_OSX_BSLS) // | +#define PT_OSX_RABK S(PT_OSX_LABK) // > +#define PT_OSX_SCLN S(KC_COMM) // ; +#define PT_OSX_COLN S(KC_DOT) // : +#define PT_OSX_UNDS S(PT_OSX_MINS) // _ +#define PT_OSX_APPL A(KC_1) // (Apple logo) +#define PT_OSX_AT A(KC_2) // @ +#define PT_OSX_EURO A(KC_3) // € +#define PT_OSX_PND A(KC_4) // £ +#define PT_OSX_PERM A(KC_5) // ‰ +#define PT_OSX_PILC A(KC_6) // ¶ +#define PT_OSX_DIV A(KC_7) // ÷ +#define PT_OSX_LBRC A(KC_8) // [ +#define PT_OSX_RBRC A(KC_9) // ] +#define PT_OSX_NEQL A(KC_0) // ≠ +#define PT_OSX_OE A(KC_Q) // Œ +#define PT_OSX_NARS A(KC_W) // ∑ +#define PT_OSX_AE A(KC_E) // Æ +#define PT_OSX_REGD A(KC_R) // ® +#define PT_OSX_TM A(KC_T) // ™ +#define PT_OSX_YEN A(KC_Y) // ¥ +#define PT_OSX_DAGG A(KC_U) // † +#define PT_OSX_DLSI A(KC_I) // ı +#define PT_OSX_OSTR A(KC_O) // Ø +#define PT_OSX_PI A(KC_P) // π +#define PT_OSX_DEG A(PT_OSX_MORD) // ° +#define PT_OSX_DIAE A(PT_OSX_ACUT) // ¨ (dead) +#define PT_OSX_ARNG A(KC_A) // å +#define PT_OSX_SS A(KC_S) // ß +#define PT_OSX_PDIF A(KC_D) // ∂ +#define PT_OSX_FHK A(KC_F) // ƒ +#define PT_OSX_DOTA A(KC_G) // ˙ +#define PT_OSX_CARN A(KC_H) // ˇ +#define PT_OSX_MACR A(KC_J) // ¯ +#define PT_OSX_DLQU A(KC_K) // „ +#define PT_OSX_LSQU A(KC_L) // ‘ +#define PT_OSX_CEDL A(PT_OSX_CCED) // ¸ +#define PT_OSX_STIL A(PT_OSX_TILD) // ˜ (dead) +#define PT_OSX_LSAQ A(PT_OSX_BSLS) // ‹ +#define PT_OSX_LTEQ A(PT_OSX_LABK) // ≤ +#define PT_OSX_OMEG A(KC_Z) // Ω +#define PT_OSX_LDAQ A(KC_X) // « +#define PT_OSX_COPY A(KC_C) // © +#define PT_OSX_SQRT A(KC_V) // √ +#define PT_OSX_INTG A(KC_B) // ∫ +#define PT_OSX_NOT A(KC_N) // ¬ +#define PT_OSX_MICR A(KC_M) // µ +#define PT_OSX_LDQU A(KC_COMM) // “ +#define PT_OSX_ELLP A(KC_DOT) // … +#define PT_OSX_MDSH A(PT_OSX_MINS) // — +#define PT_OSX_IEXL S(A(KC_1)) // ¡ +#define PT_OSX_FI S(A(KC_2)) // fi +#define PT_OSX_FL S(A(KC_3)) // fl +#define PT_OSX_CENT S(A(KC_4)) // ¢ +#define PT_OSX_INFN S(A(KC_5)) // ∞ +#define PT_OSX_BULT S(A(KC_6)) // • +#define PT_OSX_FRSL S(A(KC_7)) // ⁄ +#define PT_OSX_LCBR S(A(KC_8)) // { +#define PT_OSX_RCBR S(A(KC_9)) // } +#define PT_OSX_AEQL S(A(KC_0)) // ≈ +#define PT_OSX_IQUE S(A(PT_OSX_QUOT)) // ¿ +#define PT_OSX_LOZN S(A(PT_OSX_PLUS)) // ◊ +#define PT_OSX_DDAG S(A(KC_U)) // ‡ +#define PT_OSX_RNGA S(A(KC_I)) // ˚ +#define PT_OSX_NARP S(A(KC_P)) // ∏ +#define PT_OSX_DACU S(A(PT_OSX_ACUT)) // ˝ +#define PT_OSX_INCR S(A(KC_D)) // ∆ +#define PT_OSX_SLQU S(A(KC_K)) // ‚ +#define PT_OSX_RSQU S(A(KC_L)) // ’ +#define PT_OSX_OGON S(A(PT_OSX_CCED)) // ˛ +#define PT_OSX_DCIR S(A(PT_OSX_TILD)) // ˆ (dead) +#define PT_OSX_RSAQ S(A(PT_OSX_BSLS)) // › +#define PT_OSX_GTEQ S(A(PT_OSX_LABK)) // ≥ +#define PT_OSX_RDAQ S(A(KC_X)) // » +#define PT_OSX_RDQU S(A(KC_COMM)) // ” +#define PT_OSX_MDDT S(A(KC_DOT)) // · +#define PT_OSX_NDSH S(A(PT_OSX_MINS)) // – + +// Swiss French aliases to avoid collisions with Swiss german ones +#define FRCH_Y KC_Z +#define FRCH_Z KC_Y +#define FRCH_SECT KC_GRV +#define FRCH_QUOT KC_MINS +#define FRCH_CIRC KC_EQL +#define FRCH_EGRV KC_LBRC +#define FRCH_DIAE KC_RBRC +#define FRCH_EACU KC_SCLN +#define FRCH_AGRV KC_QUOT +#define FRCH_DLR KC_NUHS +#define FRCH_LABK KC_NUBS +#define FRCH_MINS KC_SLSH +#define FRCH_DEG S(FRCH_SECT) +#define FRCH_PLUS S(KC_1) +#define FRCH_DQUO S(KC_2) +#define FRCH_ASTR S(KC_3) +#define FRCH_CCED S(KC_4) +#define FRCH_PERC S(KC_5) +#define FRCH_AMPR S(KC_6) +#define FRCH_SLSH S(KC_7) +#define FRCH_LPRN S(KC_8) +#define FRCH_RPRN S(KC_9) +#define FRCH_EQL S(KC_0) +#define FRCH_QUES S(FRCH_QUOT) +#define FRCH_GRV S(FRCH_CIRC) +#define FRCH_UDIA S(FRCH_EGRV) +#define FRCH_EXLM S(FRCH_DIAE) +#define FRCH_ODIA S(FRCH_EACU) +#define FRCH_ADIA S(FRCH_AGRV) +#define FRCH_PND S(FRCH_DLR) +#define FRCH_RABK S(FRCH_LABK) +#define FRCH_SCLN S(KC_COMM) +#define FRCH_COLN S(KC_DOT) +#define FRCH_UNDS S(KC_MINS) +#define FRCH_BRKP ALGR(CH_1) +#define FRCH_AT ALGR(KC_2) +#define FRCH_HASH ALGR(KC_3) +#define FRCH_NOT ALGR(KC_6) +#define FRCH_PIPE ALGR(KC_7) +#define FRCH_CENT ALGR(KC_8) +#define FRCH_ACUT ALGR(FRCH_QUOT) +#define FRCH_TILD ALGR(FRCH_CIRC) +#define FRCH_EURO ALGR(KC_E) +#define FRCH_LBRC ALGR(FRCH_EGRV) +#define FRCH_RBRC ALGR(FRCH_DIAE) +#define FRCH_LCBR ALGR(FRCH_AGRV) +#define FRCH_RCBR ALGR(FRCH_DLR) +#define FRCH_BSLS ALGR(FRCH_LABK) + +// Ukrainian +#define UA_01 S(A(KC_EQUAL)) +#define UA_02 A(KC_EQUAL) +#define UA_03 S(KC_7) +#define UA_04 S(KC_6) +#define UA_05 S(KC_4) +#define UA_06 S(KC_3) +#define UA_07 S(KC_2) +#define UA_08 A(S(KC_GRAVE)) +#define UA_09 A(KC_GRAVE) +#define UA_10 KC_GRAVE +#define UA_11 KC_SLASH +#define UA_12 KC_DOT +#define UA_13 KC_COMMA +#define UA_14 KC_M +#define UA_15 KC_N +#define UA_16 KC_B +#define UA_17 KC_V +#define UA_18 KC_C +#define UA_19 KC_X +#define UA_20 KC_Z +#define UA_21 KC_QUOTE +#define UA_22 KC_SCOLON +#define UA_23 KC_J +#define UA_24 KC_K +#define UA_25 KC_J +#define UA_26 KC_H +#define UA_27 KC_G +#define UA_28 KC_F +#define UA_29 KC_D +#define UA_30 KC_S +#define UA_31 KC_A +#define UA_32 KC_RBRACKET +#define UA_33 KC_LBRACKET +#define UA_34 KC_P +#define UA_35 KC_O +#define UA_36 KC_I +#define UA_37 A(KC_U) +#define UA_38 KC_U +#define UA_39 KC_Y +#define UA_40 KC_T +#define UA_41 KC_R +#define UA_42 KC_E +#define UA_43 KC_W +#define UA_44 KC_W + +// French Canadian +#define FRCA_01 ALGR(KC_COMMA) +#define FRCA_02 ALGR(KC_M) +#define FRCA_03 ALGR(KC_RBRACKET) +#define FRCA_04 ALGR(KC_LBRACKET) +#define FRCA_05 ALGR(KC_QUOTE) +#define FRCA_06 ALGR(KC_BSLASH) +#define FRCA_07 KC_GRAVE +#define FRCA_08 A(KC_GRAVE) +#define FRCA_09 S(KC_GRAVE) +#define FRCA_10 S(KC_BSLASH) +#define FRCA_11 KC_BSLASH +#define FRCA_12 KC_RBRACKET +#define FRCA_13 KC_QUOTE +#define FRCA_14 S(KC_RBRACKET) +#define FRCA_15 KC_LBRACKET +#define FRCA_16 KC_SLASH +#define FRCA_17 ALGR(KC_SCOLON) +#define FRCA_18 ALGR(KC_P) +#define FRCA_19 ALGR(KC_O) +#define FRCA_20 ALGR(KC_MINUS) +#define FRCA_21 ALGR(KC_0) +#define FRCA_22 ALGR(KC_9) +#define FRCA_23 ALGR(KC_8) +#define FRCA_24 ALGR(KC_7) +#define FRCA_25 ALGR(KC_6) +#define FRCA_26 ALGR(KC_5) +#define FRCA_27 ALGR(KC_4) +#define FRCA_28 ALGR(KC_3) +#define FRCA_29 ALGR(KC_2) +#define FRCA_30 ALGR(KC_1) +#define FRCA_31 S(KC_6) +#define FRCA_32 S(KC_3) +#define FRCA_33 S(KC_2) + +// Icelandic +#define IS_01 S(KC_DOT) //: +#define IS_02 S(KC_COMMA) //; +#define IS_03 ALGR(KC_NONUS_BSLASH) //| +#define IS_04 S(KC_NONUS_BSLASH) //> +#define IS_05 KC_NONUS_BSLASH //< +#define IS_06 S(KC_BSLASH)// * +#define IS_07 S(KC_QUOTE) //´ +#define IS_08 S(KC_RBRACKET) //? +#define IS_09 S(KC_EQUAL) //_ +#define IS_10 S(KC_GRAVE) //¨ +#define IS_11 S(KC_0) //= +#define IS_12 S(KC_8) //( +#define IS_13 S(KC_7) //° +#define IS_14 S(KC_6) //& +#define IS_15 KC_BSLASH //+ +#define IS_16 KC_QUOTE //´ +#define IS_17 KC_RBRACKET //' +#define IS_18 KC_EQUAL //- +#define IS_19 KC_GRAVE //° +#define IS_20 KC_MINUS //ö +#define IS_21 KC_SCOLON //æ +#define IS_22 KC_LBRACKET //ð +#define IS_23 S(KC_9) //) +#define IS_24 S(KC_2) //" +#define IS_25 S(KC_MINUS) //Ö +#define IS_26 S(KC_SLASH) //Þ +#define IS_27 S(KC_SCOLON) //Æ +#define IS_28 S(KC_LBRACKET) //Ð + +// Spanish LATAM +#define ES_LA_01 ALGR(KC_MINUS) +#define ES_LA_02 ALGR(KC_GRAVE) //¬ +#define ES_LA_03 ALGR(KC_Q) //@ +#define ES_LA_04 ALGR(KC_BSLASH) //` +#define ES_LA_05 ALGR(KC_QUOTE) //^ +#define ES_LA_06 ALGR(KC_RBRACKET) //~ +#define ES_LA_07 S(KC_SCOLON) //Ñ +#define ES_LA_08 KC_SCOLON //ñ +#define ES_LA_09 S(KC_SLASH) //_ +#define ES_LA_10 KC_SLASH //- +#define ES_LA_11 S(KC_DOT) //: +#define ES_LA_12 KC_DOT //. +#define ES_LA_13 S(KC_COMMA) //; +#define ES_LA_14 KC_COMMA //, +#define ES_LA_15 S(KC_NONUS_BSLASH) //> +#define ES_LA_16 KC_NONUS_BSLASH //< +#define ES_LA_17 S(KC_BSLASH) //] +#define ES_LA_18 KC_BSLASH //} +#define ES_LA_19 S(KC_QUOTE) //[ +#define ES_LA_20 KC_QUOTE //{ +#define ES_LA_21 S(KC_RBRACKET) //* +#define ES_LA_22 KC_RBRACKET //+ +#define ES_LA_23 S(KC_LBRACKET) //¨ +#define ES_LA_24 KC_LBRACKET //´ +#define ES_LA_25 S(KC_EQUAL) //¡ +#define ES_LA_26 KC_EQUAL //¿ +#define ES_LA_27 S(KC_MINUS) //? +#define ES_LA_28 KC_MINUS //' +#define ES_LA_29 S(KC_0) //= +#define ES_LA_30 S(KC_9) //( +#define ES_LA_31 S(KC_8) //( +#define ES_LA_32 S(KC_7) /// +#define ES_LA_33 S(KC_6) //& +#define ES_LA_34 S(KC_5) //% +#define ES_LA_35 S(KC_4) //$ +#define ES_LA_36 S(KC_3) //# +#define ES_LA_37 S(KC_2) //" +#define ES_LA_38 S(KC_1) //! +#define ES_LA_39 S(KC_GRAVE) //° +#define ES_LA_40 KC_GRAVE //| + +// Extra CMS codes +#define CSA_MOMEG RCTL(RSFT(KC_Q)) //Ω diff --git a/quantum/keymap_extras/keymap_norwegian.h b/quantum/keymap_extras/keymap_norwegian.h index 6eab4163b6..8b6497f00f 100644 --- a/quantum/keymap_extras/keymap_norwegian.h +++ b/quantum/keymap_extras/keymap_norwegian.h @@ -34,57 +34,57 @@ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘ */ // Row 1 -#define NO_PIPE KC_GRV // | -#define NO_1 KC_1 // 1 -#define NO_2 KC_2 // 2 -#define NO_3 KC_3 // 3 -#define NO_4 KC_4 // 4 -#define NO_5 KC_5 // 5 -#define NO_6 KC_6 // 6 -#define NO_7 KC_7 // 7 -#define NO_8 KC_8 // 8 -#define NO_9 KC_9 // 9 -#define NO_0 KC_0 // 0 -#define NO_PLUS KC_MINS // + -#define NO_BSLS KC_EQL // (backslash) +#define NWG_PIPE KC_GRV // | +#define NWG_1 KC_1 // 1 +#define NWG_2 KC_2 // 2 +#define NWG_3 KC_3 // 3 +#define NWG_4 KC_4 // 4 +#define NWG_5 KC_5 // 5 +#define NWG_6 KC_6 // 6 +#define NWG_7 KC_7 // 7 +#define NWG_8 KC_8 // 8 +#define NWG_9 KC_9 // 9 +#define NWG_0 KC_0 // 0 +#define NWG_PLUS KC_MINS // + +#define NWG_BSLS KC_EQL // (backslash) // Row 2 -#define NO_Q KC_Q // Q -#define NO_W KC_W // W -#define NO_E KC_E // E -#define NO_R KC_R // R -#define NO_T KC_T // T -#define NO_Y KC_Y // Y -#define NO_U KC_U // U -#define NO_I KC_I // I -#define NO_O KC_O // O -#define NO_P KC_P // P -#define NO_ARNG KC_LBRC // Å -#define NO_DIAE KC_RBRC // ¨ (dead) +#define NWG_Q KC_Q // Q +#define NWG_W KC_W // W +#define NWG_E KC_E // E +#define NWG_R KC_R // R +#define NWG_T KC_T // T +#define NWG_Y KC_Y // Y +#define NWG_U KC_U // U +#define NWG_I KC_I // I +#define NWG_O KC_O // O +#define NWG_P KC_P // P +#define NWG_ARNG KC_LBRC // Å +#define NWG_DIAE KC_RBRC // ¨ (dead) // Row 3 -#define NO_A KC_A // A -#define NO_S KC_S // S -#define NO_D KC_D // D -#define NO_F KC_F // F -#define NO_G KC_G // G -#define NO_H KC_H // H -#define NO_J KC_J // J -#define NO_K KC_K // K -#define NO_L KC_L // L -#define NO_OSTR KC_SCLN // Ø -#define NO_AE KC_QUOT // Æ -#define NO_QUOT KC_NUHS // ' +#define NWG_A KC_A // A +#define NWG_S KC_S // S +#define NWG_D KC_D // D +#define NWG_F KC_F // F +#define NWG_G KC_G // G +#define NWG_H KC_H // H +#define NWG_J KC_J // J +#define NWG_K KC_K // K +#define NWG_L KC_L // L +#define NWG_OSTR KC_SCLN // Ø +#define NWG_AE KC_QUOT // Æ +#define NWG_QUOT KC_NUHS // ' // Row 4 -#define NO_LABK KC_NUBS // < -#define NO_Z KC_Z // Z -#define NO_X KC_X // X -#define NO_C KC_C // C -#define NO_V KC_V // V -#define NO_B KC_B // B -#define NO_N KC_N // N -#define NO_M KC_M // M -#define NO_COMM KC_COMM // , -#define NO_DOT KC_DOT // . -#define NO_MINS KC_SLSH // - +#define NWG_LABK KC_NUBS // < +#define NWG_Z KC_Z // Z +#define NWG_X KC_X // X +#define NWG_C KC_C // C +#define NWG_V KC_V // V +#define NWG_B KC_B // B +#define NWG_N KC_N // N +#define NWG_M KC_M // M +#define NWG_COMM KC_COMM // , +#define NWG_DOT KC_DOT // . +#define NWG_MINS KC_SLSH // - /* Shifted symbols * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ @@ -100,28 +100,28 @@ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘ */ // Row 1 -#define NO_SECT S(NO_PIPE) // § -#define NO_EXLM S(NO_1) // ! -#define NO_DQUO S(NO_2) // " -#define NO_HASH S(NO_3) // # -#define NO_CURR S(NO_4) // ¤ -#define NO_PERC S(NO_5) // % -#define NO_AMPR S(NO_6) // & -#define NO_SLSH S(NO_7) // / -#define NO_LPRN S(NO_8) // ( -#define NO_RPRN S(NO_9) // ) -#define NO_EQL S(NO_0) // = -#define NO_QUES S(NO_PLUS) // ? -#define NO_GRV S(NO_BSLS) // ` (dead) +#define NWG_SECT S(NWG_PIPE) // § +#define NWG_EXLM S(NWG_1) // ! +#define NWG_DQUO S(NWG_2) // " +#define NWG_HASH S(NWG_3) // # +#define NWG_CURR S(NWG_4) // ¤ +#define NWG_PERC S(NWG_5) // % +#define NWG_AMPR S(NWG_6) // & +#define NWG_SLSH S(NWG_7) // / +#define NWG_LPRN S(NWG_8) // ( +#define NWG_RPRN S(NWG_9) // ) +#define NWG_EQL S(NWG_0) // = +#define NWG_QUES S(NWG_PLUS) // ? +#define NWG_GRV S(NWG_BSLS) // ` (dead) // Row 2 -#define NO_CIRC S(NO_DIAE) // ^ (dead) +#define NWG_CIRC S(NWG_DIAE) // ^ (dead) // Row 3 -#define NO_ASTR S(NO_QUOT) // * +#define NWG_ASTR S(NWG_QUOT) // * // Row 4 -#define NO_RABK S(NO_LABK) // > -#define NO_SCLN S(NO_COMM) // ; -#define NO_COLN S(NO_DOT) // : -#define NO_UNDS S(NO_MINS) // _ +#define NWG_RABK S(NWG_LABK) // > +#define NWG_SCLN S(NWG_COMM) // ; +#define NWG_COLN S(NWG_DOT) // : +#define NWG_UNDS S(NWG_MINS) // _ /* AltGr symbols * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ @@ -137,39 +137,40 @@ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘ */ // Row 1 -#define NO_AT ALGR(NO_2) // @ -#define NO_PND ALGR(NO_3) // £ -#define NO_DLR ALGR(NO_4) // $ -#define NO_EURO ALGR(NO_5) // € -#define NO_LCBR ALGR(NO_7) // { -#define NO_LBRC ALGR(NO_8) // [ -#define NO_RBRC ALGR(NO_9) // ] -#define NO_RCBR ALGR(NO_0) // } -#define NO_ACUT ALGR(NO_BSLS) // ´ (dead) + +#define NWG_AT ALGR(NWG_2) // @ +#define NWG_PND ALGR(NWG_3) // £ +#define NWG_DLR ALGR(NWG_4) // $ +#define NWG_EURO ALGR(NWG_5) // € +#define NWG_LCBR ALGR(NWG_7) // { +#define NWG_LBRC ALGR(NWG_8) // [ +#define NWG_RBRC ALGR(NWG_9) // ] +#define NWG_RCBR ALGR(NWG_0) // } +#define NWG_ACUT ALGR(NWG_BSLS) // ´ (dead) // Row 2 -#define NO_TILD ALGR(NO_DIAE) // ~ (dead) +#define NWG_TILD ALGR(NWG_DIAE) // ~ (dead) // Row 4 -#define NO_MICR ALGR(NO_M) // µ +#define NWG_MICR ALGR(NWG_M) // µ // DEPRECATED -#define NO_AM NO_ARNG -#define NO_AA NO_ARNG -#define NO_OSLH NO_OSTR -#define NO_APOS NO_QUOT -#define NO_LESS NO_LABK -#define NO_QUO2 NO_DQUO -#define NO_BULT NO_CURR -#define NO_GRTR NO_RABK -#define NO_MU NO_MICR +#define NWG_AM NWG_ARNG +#define NWG_AA NWG_ARNG +#define NWG_OSLH NWG_OSTR +#define NWG_APOS NWG_QUOT +#define NWG_LESS NWG_LABK +#define NWG_QUO2 NWG_DQUO +#define NWG_BULT NWG_CURR +#define NWG_GRTR NWG_RABK +#define NWG_MU NWG_MICR // Norwegian macOS symbols -#define NO_ACUT_MAC NO_BSLS // ´ -#define NO_APOS_MAC NO_LABK // ' -#define NO_AT_MAC NO_QUOT // @ -#define NO_BSLS_MAC S(ALGR(NO_7)) // (backslash) -#define NO_DLR_MAC S(NO_4) // $ -#define NO_GRV_MAC ALGR(NO_BSLS) // ` -#define NO_GRTR_MAC S(NO_PIPE) // > -#define NO_LCBR_MAC S(ALGR(NO_8)) // { -#define NO_LESS_MAC NO_PIPE // < -#define NO_PIPE_MAC ALGR(NO_7) // | -#define NO_RCBR_MAC S(ALGR(NO_9)) // } +#define NWG_ACUT_MAC NWG_BSLS // ´ +#define NWG_APOS_MAC NWG_LABK // ' +#define NWG_AT_MAC NWG_QUOT // @ +#define NWG_BSLS_MAC S(ALGR(NWG_7)) // (backslash) +#define NWG_DLR_MAC S(NWG_4) // $ +#define NWG_GRV_MAC ALGR(NWG_BSLS) // ` +#define NWG_GRTR_MAC S(NWG_PIPE) // > +#define NWG_LCBR_MAC S(ALGR(NWG_8)) // { +#define NWG_LESS_MAC NWG_PIPE // < +#define NWG_PIPE_MAC ALGR(NWG_7) // | +#define NWG_RCBR_MAC S(ALGR(NWG_9)) // } diff --git a/quantum/keymap_extras/keymap_spanish_dvorak.h b/quantum/keymap_extras/keymap_spanish_dvorak.h index 38f579ae10..8fd6214728 100644 --- a/quantum/keymap_extras/keymap_spanish_dvorak.h +++ b/quantum/keymap_extras/keymap_spanish_dvorak.h @@ -119,7 +119,11 @@ #define DV_CIRC S(DV_GRV) // ^ (dead) #define DV_ASTR S(DV_PLUS) // * // Row 3 +<<<<<<< HEAD +#define DV_DIAE S(DV_GRV) // ¨ (dead) +======= #define DV_DIAE S(DV_ACUT) // ¨ (dead) +>>>>>>> 0.12.52~1 // Row 4 #define DV_RABK S(DV_LABK) // > #define DV_UNDS S(DV_MINS) // _ diff --git a/quantum/keymap_extras/sendstring_dvorak.h b/quantum/keymap_extras/sendstring_dvorak.h index 25e1d31423..9bad0dc13a 100644 --- a/quantum/keymap_extras/sendstring_dvorak.h +++ b/quantum/keymap_extras/sendstring_dvorak.h @@ -20,12 +20,47 @@ #include "keymap_dvorak.h" +<<<<<<< HEAD +======= // clang-format off +>>>>>>> 0.12.52~1 const uint8_t ascii_to_keycode_lut[128] PROGMEM = { // NUL SOH STX ETX EOT ENQ ACK BEL XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, // BS TAB LF VT FF CR SO SI +<<<<<<< HEAD + KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // DLE DC1 DC2 DC3 DC4 NAK SYN ETB + XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // CAN EM SUB ESC FS GS RS US + XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + + // ! " # $ % & ' + KC_SPC, DV_1, DV_QUOT, DV_3, DV_4, DV_5, DV_7, DV_QUOT, + // ( ) * + , - . / + DV_9, DV_0, DV_8, DV_EQL, DV_COMM, DV_MINS, DV_DOT, DV_SLSH, + // 0 1 2 3 4 5 6 7 + DV_0, DV_1, DV_2, DV_3, DV_4, DV_5, DV_6, DV_7, + // 8 9 : ; < = > ? + DV_8, DV_9, DV_SCLN, DV_SCLN, DV_COMM, DV_EQL, DV_DOT, DV_SLSH, + // @ A B C D E F G + DV_2, DV_A, DV_B, DV_C, DV_D, DV_E, DV_F, DV_G, + // H I J K L M N O + DV_H, DV_I, DV_J, DV_K, DV_L, DV_M, DV_N, DV_O, + // P Q R S T U V W + DV_P, DV_Q, DV_R, DV_S, DV_T, DV_U, DV_V, DV_W, + // X Y Z [ \ ] ^ _ + DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_6, DV_MINS, + // ` a b c d e f g + DV_GRV, DV_A, DV_B, DV_C, DV_D, DV_E, DV_F, DV_G, + // h i j k l m n o + DV_H, DV_I, DV_J, DV_K, DV_L, DV_M, DV_N, DV_O, + // p q r s t u v w + DV_P, DV_Q, DV_R, DV_S, DV_T, DV_U, DV_V, DV_W, + // x y z { | } ~ DEL + DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_GRV, KC_DEL}; +======= KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, // DLE DC1 DC2 DC3 DC4 NAK SYN ETB XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, @@ -57,3 +92,4 @@ const uint8_t ascii_to_keycode_lut[128] PROGMEM = { // x y z { | } ~ DEL DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_GRV, KC_DEL }; +>>>>>>> 0.12.52~1 diff --git a/quantum/oryx.c b/quantum/oryx.c new file mode 100644 index 0000000000..55176a7e4c --- /dev/null +++ b/quantum/oryx.c @@ -0,0 +1,249 @@ +#include "oryx.h" +#include "eeprom.h" +#include <string.h> + +bool oryx_state_live_training_enabled; + +bool webusb_receive_oryx(uint8_t *data, uint8_t length) { + uint8_t command = data[0]; + uint8_t *param = &(data[1]); + + switch (command) { + case ORYX_GET_LAYER: + oryx_layer_event(); + return true; + case ORYX_CMD_LIVE_TRAINING: { + uint8_t event[4]; + switch (param[0]) { // 0 for querying, 1 for off, 2 for on + case 0: + break; + case 1: + oryx_state_live_training_enabled = false; + break; + case 2: + oryx_state_live_training_enabled = true; + break; + default: + webusb_error(WEBUSB_STATUS_UNKNOWN_COMMAND); + return true; + } + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_TRAINING; + event[2] = oryx_state_live_training_enabled; + event[3] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } +#ifdef DYNAMIC_KEYMAP_ENABLE + case ORYX_CMD_LIVE_UPDATE_GET_KEYCODE: { + uint8_t event[5]; + // layer, row, col + uint16_t keycode = dynamic_keymap_get_keycode(param[0], param[1], param[2]); + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_GET_KEYCODE; + event[2] = keycode >> 8; + event[3] = keycode & 0xFF; + event[4] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_SET_KEYCODE: { + uint8_t event[5]; + dynamic_keymap_set_keycode(param[0], param[1], param[2], (param[3] << 8) | param[4]); + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_SET_KEYCODE; + event[2] = param[3]; + event[3] = param[4]; + event[4] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_KEYMAP_RESET: { + uint8_t event[3]; + dynamic_keymap_reset(); + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_KEYMAP_RESET; + event[2] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_GET_BUFFER: { + uint16_t offset = (param[0] << 8) | param[1]; + uint16_t size = param[2]; // size <= 28 + uint8_t event[size+3]; + uint8_t i; + dynamic_keymap_get_buffer(offset, size, ¶m[3]); + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_GET_BUFFER; + for (i = 0; i < size; i++) { + event[i+2] = param[i]; + } + event[i+2] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_SET_BUFFER: { + uint16_t offset = (param[0] << 8) | param[1]; + uint16_t size = param[2]; // size <= 28 + uint8_t event[3]; + dynamic_keymap_set_buffer(offset, size, ¶m[3]); + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_SET_BUFFER; + event[2] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_GET_LAYER_COUNT: { + uint8_t event[4]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_GET_LAYER_COUNT; + event[2] = dynamic_keymap_get_layer_count(); + event[3] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_GET_MACRO_COUNT: { + uint8_t event[4]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_GET_MACRO_COUNT; + event[2] = dynamic_keymap_macro_get_count(); + event[3] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE: { + uint16_t size = dynamic_keymap_macro_get_buffer_size(); + uint8_t event[5]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE; + event[2] = size >> 8; + event[3] = size & 0xFF; + event[4] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER: { + uint16_t offset = (param[0] << 8) | param[1]; + uint16_t size = param[2]; // size <= 28 + uint8_t event[size+3]; + uint8_t i; + dynamic_keymap_macro_get_buffer(offset, size, ¶m[3]); + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER; + for (i = 0; i < size; i++) { + event[i+2] = param[i]; + } + event[i+2] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_SET_MACRO_BUFFER: { + uint16_t offset = (param[0] << 8) | param[1]; + uint16_t size = param[2]; // size <= 28 + dynamic_keymap_macro_set_buffer(offset, size, ¶m[3]); + uint8_t event[3]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_SET_MACRO_BUFFER; + event[2] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_MACRO_RESET: { + uint8_t event[3]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_MACRO_RESET; + event[2] = WEBUSB_STOP_BIT; + dynamic_keymap_macro_reset(); + webusb_send(event, sizeof(event)); + return true; + } + case ORYX_CMD_LIVE_UPDATE_EEPROM_RESET: { + uint8_t event[3]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_EEPROM_RESET; + event[2] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + eeconfig_init(); + return true; + } + case ORYX_CMD_LIVE_UPDATE_KEYBOARD_RESET: { + uint8_t event[3]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LIVE_UPDATE_KEYBOARD_RESET; + event[2] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + reset_keyboard(); + return true; + } +#endif + default: + return webusb_receive_kb(data, length); + } +} + +void oryx_layer_event(void) { + uint8_t layer; + uint8_t event[4]; + layer = get_highest_layer(layer_state); +#ifdef WEBUSB_ENABLE + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LAYER; + event[2] = layer; + event[3] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); +#endif +} + +bool is_oryx_live_training_enabled(void) { return (oryx_state_live_training_enabled && webusb_state.paired); } + +bool process_record_oryx(uint16_t keycode, keyrecord_t *record) { + if(is_oryx_live_training_enabled()) { + uint8_t event[5]; + event[0] = WEBUSB_STATUS_OK; + event[1] = record->event.pressed ? ORYX_EVT_KEYDOWN : ORYX_EVT_KEYUP; + event[2] = record->event.key.col; + event[3] = record->event.key.row; + event[4] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + } + +#ifdef DYNAMIC_KEYMAP_ENABLE + switch (keycode) { + case MACRO00 ... MACRO15: + if (record->event.pressed) { + dynamic_keymap_macro_send(keycode - MACRO00); + } + return false; + } +#endif + return true; +} + +void layer_state_set_oryx(layer_state_t state) { + if(is_oryx_live_training_enabled()) { + uint8_t event[4]; + event[0] = WEBUSB_STATUS_OK; + event[1] = ORYX_EVT_LAYER; + event[2] = get_highest_layer(state); + event[3] = WEBUSB_STOP_BIT; + webusb_send(event, sizeof(event)); + } +} + +void eeconfig_init_oryx(void) { +#ifdef DYNAMIC_KEYMAP_ENABLE + // reread settings from flash into eeprom + dynamic_keymap_reset(); + dynamic_keymap_macro_reset(); + eeprom_update_block(FIRMWARE_VERSION, (uint8_t *)EECONFIG_SIZE, sizeof(uint8_t)*FIRMWARE_VERSION_SIZE); +} + +void matrix_init_oryx(void) { + uint8_t temp[FIRMWARE_VERSION_SIZE]; + uint8_t firmware[FIRMWARE_VERSION_SIZE] = FIRMWARE_VERSION; + eeprom_read_block(&temp, (uint8_t *)EECONFIG_SIZE, sizeof(uint8_t)*FIRMWARE_VERSION_SIZE); + if (!memcmp(&temp, &firmware, sizeof(uint8_t)*FIRMWARE_VERSION_SIZE)) { + eeconfig_init_oryx(); + } +#endif +} diff --git a/quantum/oryx.h b/quantum/oryx.h new file mode 100644 index 0000000000..b1fe78a061 --- /dev/null +++ b/quantum/oryx.h @@ -0,0 +1,82 @@ +#pragma once + +#include "quantum.h" +#include "webusb.h" + +#ifndef WEBUSB_ENABLE +# error "WebUSB needs to be enabled, please enable it!" +#endif + +// enum Oryx_Status_code { +// PLACEHOLDER = WEBUSB_STATUS_SAFE_RANGE, +// } + +enum Oryx_Command_Code { + ORYX_GET_LAYER = WEBUSB_CMD_SAFE_RANGE, + ORYX_CMD_LIVE_TRAINING, + ORYX_CMD_LIVE_UPDATE_GET_KEYCODE, + ORYX_CMD_LIVE_UPDATE_SET_KEYCODE, + ORYX_CMD_LIVE_UPDATE_KEYMAP_RESET, + ORYX_CMD_LIVE_UPDATE_GET_BUFFER, + ORYX_CMD_LIVE_UPDATE_SET_BUFFER, + ORYX_CMD_LIVE_UPDATE_GET_LAYER_COUNT, + ORYX_CMD_LIVE_UPDATE_GET_MACRO_COUNT, + ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE, + ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER, + ORYX_CMD_LIVE_UPDATE_SET_MACRO_BUFFER, + ORYX_CMD_LIVE_UPDATE_MACRO_RESET, + ORYX_CMD_LIVE_UPDATE_EEPROM_RESET, + ORYX_CMD_LIVE_UPDATE_KEYBOARD_RESET, + +}; + +enum Oryx_Event_Code { + ORYX_EVT_LAYER = WEBUSB_EVT_SAFE_RANGE, + ORYX_EVT_LIVE_TRAINING, + ORYX_EVT_LIVE_UPDATE_GET_KEYCODE, + ORYX_EVT_LIVE_UPDATE_SET_KEYCODE, + ORYX_EVT_LIVE_UPDATE_KEYMAP_RESET, + ORYX_EVT_LIVE_UPDATE_GET_BUFFER, + ORYX_EVT_LIVE_UPDATE_SET_BUFFER, + ORYX_EVT_LIVE_UPDATE_GET_LAYER_COUNT, + ORYX_EVT_LIVE_UPDATE_GET_MACRO_COUNT, + ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE, + ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER, + ORYX_EVT_LIVE_UPDATE_SET_MACRO_BUFFER, + ORYX_EVT_LIVE_UPDATE_MACRO_RESET, + ORYX_EVT_LIVE_UPDATE_EEPROM_RESET, + ORYX_EVT_LIVE_UPDATE_KEYBOARD_RESET, + ORYX_EVT_KEYDOWN, + ORYX_EVT_KEYUP, +}; + +#ifdef DYNAMIC_KEYMAP_ENABLE +enum dynamic_macros_keycodes { + MACRO00 = 0x5F12, + MACRO01, + MACRO02, + MACRO03, + MACRO04, + MACRO05, + MACRO06, + MACRO07, + MACRO08, + MACRO09, + MACRO10, + MACRO11, + MACRO12, + MACRO13, + MACRO14, + MACRO15, +}; +#endif + +extern bool oryx_state_live_training_enabled; + +bool webusb_receive_oryx(uint8_t *data, uint8_t length); +void oryx_layer_event(void); +bool is_oryx_live_training_enabled(void); +bool process_record_oryx(uint16_t keycode, keyrecord_t *record); +void layer_state_set_oryx(layer_state_t state); +void eeconfig_init_oryx(void); +void matrix_init_oryx(void); diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index bf359e994d..7fa4bad75a 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -225,7 +225,9 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { case KC_1 ... KC_0: # endif # ifndef NO_AUTO_SHIFT_SPECIAL +# ifndef NO_AUTO_SHIFT_TAB case KC_TAB: +# endif case KC_MINUS ... KC_SLASH: case KC_NONUS_BSLASH: # endif diff --git a/quantum/process_keycode/process_grave_esc.h b/quantum/process_keycode/process_grave_esc.h index bbf4483763..bbf4483763 100644..100755 --- a/quantum/process_keycode/process_grave_esc.h +++ b/quantum/process_keycode/process_grave_esc.h diff --git a/quantum/quantum.c b/quantum/quantum.c index b40b40544a..d5d97f3242 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -14,6 +14,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <ctype.h> #include "quantum.h" #ifdef BLUETOOTH_ENABLE @@ -144,7 +145,6 @@ void reset_keyboard(void) { /* Convert record into usable keycode via the contained event. */ uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) { return get_event_keycode(record->event, update_layer_cache); } - /* Convert event into usable keycode. Checks the layer cache to ensure that it * retains the correct keycode after a layer change, if the key is still pressed. * "update_layer_cache" is to ensure that it only updates the layer cache when @@ -220,6 +220,9 @@ bool process_record_quantum(keyrecord_t *record) { #ifdef HAPTIC_ENABLE process_haptic(keycode, record) && #endif // HAPTIC_ENABLE +#ifdef ORYX_ENABLE + process_record_oryx(keycode, record) && +#endif #if defined(VIA_ENABLE) process_record_via(keycode, record) && #endif @@ -321,6 +324,7 @@ bool process_record_quantum(keyrecord_t *record) { } } + return process_action_kb(record); } @@ -347,6 +351,9 @@ void matrix_init_quantum() { if (!eeconfig_is_enabled()) { eeconfig_init(); } +#if defined(ORYX_ENABLE) && defined(DYNAMIC_KEYMAP_ENABLE) + matrix_init_oryx(); +#endif #if defined(LED_NUM_LOCK_PIN) || defined(LED_CAPS_LOCK_PIN) || defined(LED_SCROLL_LOCK_PIN) || defined(LED_COMPOSE_PIN) || defined(LED_KANA_PIN) // TODO: remove calls to led_init_ports from keyboards and remove ifdef led_init_ports(); @@ -456,3 +463,16 @@ void api_send_unicode(uint32_t unicode) { __attribute__((weak)) void startup_user() {} __attribute__((weak)) void shutdown_user() {} + +#ifdef WEBUSB_ENABLE +__attribute__((weak)) bool webusb_receive_user(uint8_t *data, uint8_t length) { return false; } +__attribute__((weak)) bool webusb_receive_kb(uint8_t *data, uint8_t length) { return webusb_receive_user(data, length); } + +bool webusb_receive_quantum(uint8_t *data, uint8_t length) { +#ifdef ORYX_ENABLE + return webusb_receive_oryx(data, length); +#else + return webusb_receive_kb(data, length); +#endif +} +#endif diff --git a/quantum/quantum.h b/quantum/quantum.h index e24a4c43a3..a5ed1b66bd 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -176,11 +176,20 @@ extern layer_state_t layer_state; #endif #ifdef DIP_SWITCH_ENABLE -# include "dip_switch.h" + #include "dip_switch.h" +#endif + + +#ifdef WEBUSB_ENABLE +# include "webusb.h" +#endif + +#ifdef ORYX_ENABLE +# include "oryx.h" #endif #ifdef DYNAMIC_MACRO_ENABLE -# include "process_dynamic_macro.h" + #include "process_dynamic_macro.h" #endif #ifdef DYNAMIC_KEYMAP_ENABLE @@ -195,6 +204,7 @@ extern layer_state_t layer_state; # include "wpm.h" #endif + #ifdef USBPD_ENABLE # include "usbpd.h" #endif @@ -280,3 +290,6 @@ bool led_update_user(led_t led_state); bool led_update_kb(led_t led_state); void api_send_unicode(uint32_t unicode); + +bool webusb_receive_kb(uint8_t *data, uint8_t length); +bool webusb_receive_user(uint8_t *data, uint8_t length); diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index e49f8dcdaa..97d200c8cf 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -507,6 +507,8 @@ enum quantum_keycodes { DYN_MACRO_PLAY1, DYN_MACRO_PLAY2, + WEBUSB_PAIR, + JS_BUTTON0, JS_BUTTON_MIN = JS_BUTTON0, JS_BUTTON1, diff --git a/quantum/template/base/keymaps/default/keymap.c b/quantum/template/base/keymaps/default/keymap.c index d8020ab3e3..b8ffb0156c 100644 --- a/quantum/template/base/keymaps/default/keymap.c +++ b/quantum/template/base/keymaps/default/keymap.c @@ -27,6 +27,9 @@ enum custom_keycodes { QMKURL }; +// Defines the keycodes used by our macros in process_record_user +enum custom_keycodes { QMKBEST = SAFE_RANGE, QMKURL }; + const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* Base */ [_BASE] = LAYOUT( |