summaryrefslogtreecommitdiffstats
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/audio/audio.c322
-rw-r--r--quantum/audio/song_list.h27
-rw-r--r--quantum/audio/voices.c1
-rw-r--r--quantum/fauxclicky.c68
-rw-r--r--quantum/fauxclicky.h99
-rw-r--r--quantum/keymap_common.c5
-rw-r--r--quantum/keymap_extras/keymap_french.h4
-rw-r--r--quantum/process_keycode/process_audio.c62
-rw-r--r--quantum/process_keycode/process_audio.h11
-rw-r--r--quantum/process_keycode/process_midi.c292
-rw-r--r--quantum/process_keycode/process_midi.h225
-rw-r--r--quantum/process_keycode/process_music.c118
-rw-r--r--quantum/process_keycode/process_music.h6
-rw-r--r--quantum/process_keycode/process_ucis.c133
-rw-r--r--quantum/process_keycode/process_ucis.h35
-rw-r--r--quantum/process_keycode/process_unicode.c285
-rw-r--r--quantum/process_keycode/process_unicode.h160
-rw-r--r--quantum/process_keycode/process_unicode_common.c85
-rw-r--r--quantum/process_keycode/process_unicode_common.h132
-rw-r--r--quantum/process_keycode/process_unicodemap.c56
-rw-r--r--quantum/process_keycode/process_unicodemap.h9
-rw-r--r--quantum/quantum.c179
-rw-r--r--quantum/quantum.h18
-rw-r--r--quantum/quantum_keycodes.h291
-rw-r--r--quantum/template/config.h23
-rw-r--r--quantum/template/keymaps/default/Makefile2
-rw-r--r--quantum/template/rules.mk3
27 files changed, 1667 insertions, 984 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
index 2a315fd168..e1e81fd2b8 100644
--- a/quantum/audio/audio.c
+++ b/quantum/audio/audio.c
@@ -89,15 +89,15 @@ void audio_init()
}
audio_config.raw = eeconfig_read_audio();
- // Set port PC6 (OC3A and /OC4A) as output
+ // Set port PC6 (OC3A and /OC4A) as output
DDRC |= _BV(PORTC6);
DISABLE_AUDIO_COUNTER_3_ISR;
- // 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
+ // 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
TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
@@ -106,6 +106,8 @@ void audio_init()
void stop_all_notes()
{
+ dprintf("audio stop all notes");
+
if (!audio_initialized) {
audio_init();
}
@@ -128,6 +130,8 @@ void stop_all_notes()
void stop_note(float freq)
{
+ dprintf("audio stop note freq=%d", (int)freq);
+
if (playing_note) {
if (!audio_initialized) {
audio_init();
@@ -183,159 +187,161 @@ float vibrato(float average_freq) {
ISR(TIMER3_COMPA_vect)
{
- float freq;
-
- 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_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) {
- end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF));
- } else {
- end_of_note = (note_position >= (note_length * 0x7FF));
- }
-
- 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 && (notes_rest > 0)) {
- note_resting = true;
- note_frequency = 0;
- note_length = notes_rest;
- current_note--;
- } 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;
- }
+ float freq;
+
+ 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_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) {
+ end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF));
+ } else {
+ end_of_note = (note_position >= (note_length * 0x7FF));
+ }
+
+ 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 && (notes_rest > 0)) {
+ note_resting = true;
+ note_frequency = 0;
+ note_length = notes_rest;
+ current_note--;
+ } 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) {
- DISABLE_AUDIO_COUNTER_3_ISR;
+ if (audio_config.enable && voices < 8) {
+ DISABLE_AUDIO_COUNTER_3_ISR;
- // Cancel notes if notes are playing
- if (playing_notes)
- stop_all_notes();
+ // Cancel notes if notes are playing
+ if (playing_notes)
+ stop_all_notes();
- playing_note = true;
+ playing_note = true;
- envelope_index = 0;
+ envelope_index = 0;
- if (freq > 0) {
- frequencies[voices] = freq;
- volumes[voices] = vol;
- voices++;
- }
+ if (freq > 0) {
+ frequencies[voices] = freq;
+ volumes[voices] = vol;
+ voices++;
+ }
ENABLE_AUDIO_COUNTER_3_ISR;
ENABLE_AUDIO_COUNTER_3_OUTPUT;
- }
+ }
}
@@ -346,37 +352,37 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest)
audio_init();
}
- if (audio_config.enable) {
+ if (audio_config.enable) {
- DISABLE_AUDIO_COUNTER_3_ISR;
+ DISABLE_AUDIO_COUNTER_3_ISR;
- // Cancel note if a note is playing
- if (playing_note)
- stop_all_notes();
+ // Cancel note if a note is playing
+ if (playing_note)
+ stop_all_notes();
- playing_notes = true;
+ playing_notes = true;
- notes_pointer = np;
- notes_count = n_count;
- notes_repeat = n_repeat;
- notes_rest = n_rest;
+ notes_pointer = np;
+ notes_count = n_count;
+ notes_repeat = n_repeat;
+ notes_rest = n_rest;
- place = 0;
- current_note = 0;
+ 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;
+ note_position = 0;
ENABLE_AUDIO_COUNTER_3_ISR;
ENABLE_AUDIO_COUNTER_3_OUTPUT;
- }
+ }
}
bool is_playing_notes(void) {
- return playing_notes;
+ return playing_notes;
}
bool is_audio_on(void) {
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h
index 8022ca6729..400915db91 100644
--- a/quantum/audio/song_list.h
+++ b/quantum/audio/song_list.h
@@ -122,4 +122,31 @@
E__NOTE(_E5), \
E__NOTE(_D5),
+#define COIN_SOUND \
+ E__NOTE(_A5 ), \
+ HD_NOTE(_E6 ),
+
+#define ONE_UP_SOUND \
+ Q__NOTE(_E6 ), \
+ Q__NOTE(_G6 ), \
+ Q__NOTE(_E7 ), \
+ Q__NOTE(_C7 ), \
+ Q__NOTE(_D7 ), \
+ Q__NOTE(_G7 ),
+
+#define SONIC_RING \
+ E__NOTE(_E6), \
+ E__NOTE(_G6), \
+ HD_NOTE(_C7),
+
+#define ZELDA_PUZZLE \
+ Q__NOTE(_G5), \
+ Q__NOTE(_FS5), \
+ Q__NOTE(_DS5), \
+ Q__NOTE(_A4), \
+ Q__NOTE(_GS4), \
+ Q__NOTE(_E5), \
+ Q__NOTE(_GS5), \
+ HD_NOTE(_C6),
+
#endif
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c
index 8326e91eaa..c2edb75f01 100644
--- a/quantum/audio/voices.c
+++ b/quantum/audio/voices.c
@@ -24,6 +24,7 @@ void voice_deiterate() {
float voice_envelope(float frequency) {
// envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz
+ __attribute__ ((unused))
uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency));
switch (voice) {
diff --git a/quantum/fauxclicky.c b/quantum/fauxclicky.c
new file mode 100644
index 0000000000..13273e7058
--- /dev/null
+++ b/quantum/fauxclicky.c
@@ -0,0 +1,68 @@
+/*
+Copyright 2017 Priyadi Iman Nurcahyo
+
+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 <avr/interrupt.h>
+#include <avr/io.h>
+#include <timer.h>
+#include <fauxclicky.h>
+#include <stdbool.h>
+#include <musical_notes.h>
+
+__attribute__ ((weak))
+float fauxclicky_pressed_note[2] = MUSICAL_NOTE(_F3, 2);
+__attribute__ ((weak))
+float fauxclicky_released_note[2] = MUSICAL_NOTE(_A3, 2);
+__attribute__ ((weak))
+float fauxclicky_beep_note[2] = MUSICAL_NOTE(_C3, 2);
+
+bool fauxclicky_enabled = true;
+uint16_t note_start = 0;
+bool note_playing = false;
+uint16_t note_period = 0;
+
+void fauxclicky_init()
+{
+ // Set port PC6 (OC3A and /OC4A) as output
+ DDRC |= _BV(PORTC6);
+
+ // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
+ TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
+ TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
+}
+
+void fauxclicky_stop()
+{
+ FAUXCLICKY_DISABLE_OUTPUT;
+ note_playing = false;
+}
+
+void fauxclicky_play(float note[2]) {
+ if (!fauxclicky_enabled) return;
+ if (note_playing) fauxclicky_stop();
+ FAUXCLICKY_TIMER_PERIOD = (uint16_t)(((float)F_CPU) / (note[0] * FAUXCLICKY_CPU_PRESCALER));
+ FAUXCLICKY_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (note[0] * FAUXCLICKY_CPU_PRESCALER)) / 2);
+ note_playing = true;
+ note_period = (note[1] / 16) * (60 / (float)FAUXCLICKY_TEMPO) * 100; // check this
+ note_start = timer_read();
+ FAUXCLICKY_ENABLE_OUTPUT;
+}
+
+void fauxclicky_check() {
+ if (!note_playing) return;
+
+ if (timer_elapsed(note_start) > note_period) {
+ fauxclicky_stop();
+ }
+}
diff --git a/quantum/fauxclicky.h b/quantum/fauxclicky.h
new file mode 100644
index 0000000000..109bd0d83e
--- /dev/null
+++ b/quantum/fauxclicky.h
@@ -0,0 +1,99 @@
+/*
+Copyright 2017 Priyadi Iman Nurcahyo
+
+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/>.
+*/
+
+#ifdef AUDIO_ENABLE
+#error "AUDIO_ENABLE and FAUXCLICKY_ENABLE cannot be both enabled"
+#endif
+
+#include "musical_notes.h"
+#include "stdbool.h"
+
+__attribute__ ((weak))
+float fauxclicky_pressed_note[2];
+__attribute__ ((weak))
+float fauxclicky_released_note[2];
+__attribute__ ((weak))
+float fauxclicky_beep_note[2];
+
+bool fauxclicky_enabled;
+
+//
+// tempo in BPM
+//
+
+#ifndef FAUXCLICKY_TEMPO
+#define FAUXCLICKY_TEMPO TEMPO_DEFAULT
+#endif
+
+// beep on press
+#define FAUXCLICKY_ACTION_PRESS fauxclicky_play(fauxclicky_pressed_note)
+
+// beep on release
+#define FAUXCLICKY_ACTION_RELEASE fauxclicky_play(fauxclicky_released_note)
+
+// general purpose beep
+#define FAUXCLICKY_BEEP fauxclicky_play(fauxclicky_beep_note)
+
+// enable
+#define FAUXCLICKY_ON fauxclicky_enabled = true
+
+// disable
+#define FAUXCLICKY_OFF do { \
+ fauxclicky_enabled = false; \
+ fauxclicky_stop(); \
+} while (0)
+
+// toggle
+#define FAUXCLICKY_TOGGLE do { \
+ if (fauxclicky_enabled) { \
+ FAUXCLICKY_OFF; \
+ } else { \
+ FAUXCLICKY_ON; \
+ } \
+} while (0)
+
+//
+// pin configuration
+//
+
+#ifndef FAUXCLICKY_CPU_PRESCALER
+#define FAUXCLICKY_CPU_PRESCALER 8
+#endif
+
+#ifndef FAUXCLICKY_ENABLE_OUTPUT
+#define FAUXCLICKY_ENABLE_OUTPUT TCCR3A |= _BV(COM3A1);
+#endif
+
+#ifndef FAUXCLICKY_DISABLE_OUTPUT
+#define FAUXCLICKY_DISABLE_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
+#endif
+
+#ifndef FAUXCLICKY_TIMER_PERIOD
+#define FAUXCLICKY_TIMER_PERIOD ICR3
+#endif
+
+#ifndef FAUXCLICKY_DUTY_CYCLE
+#define FAUXCLICKY_DUTY_CYCLE OCR3A
+#endif
+
+//
+// definitions
+//
+
+void fauxclicky_init(void);
+void fauxclicky_stop(void);
+void fauxclicky_play(float note[2]);
+void fauxclicky_check(void);
+
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index 5190f24e87..002eabd85e 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -119,8 +119,11 @@ action_t action_for_key(uint8_t layer, keypos_t key)
mod = keycode & 0xFF;
action.code = ACTION_MODS_ONESHOT(mod);
break;
+ case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
+ action.code = ACTION_LAYER_TAP_TOGGLE(keycode & 0xFF);
+ break;
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
- action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
+ action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0x1F, keycode & 0xFF);
break;
#ifdef BACKLIGHT_ENABLE
case BL_0 ... BL_15:
diff --git a/quantum/keymap_extras/keymap_french.h b/quantum/keymap_extras/keymap_french.h
index 834c69650e..401bbdf644 100644
--- a/quantum/keymap_extras/keymap_french.h
+++ b/quantum/keymap_extras/keymap_french.h
@@ -4,7 +4,9 @@
#include "keymap.h"
// Alt gr
+#ifndef ALGR
#define ALGR(kc) RALT(kc)
+#endif
#define NO_ALGR KC_RALT
// Normal characters
@@ -72,7 +74,7 @@
#define FR_PIPE ALGR(KC_6)
#define FR_GRV ALGR(KC_7)
#define FR_BSLS ALGR(KC_8)
-#define FR_CIRC ALGR(KC_9)
+#define FR_CCIRC ALGR(KC_9)
#define FR_AT ALGR(KC_0)
#define FR_RBRC ALGR(FR_RPRN)
#define FR_RCBR ALGR(FR_EQL)
diff --git a/quantum/process_keycode/process_audio.c b/quantum/process_keycode/process_audio.c
new file mode 100644
index 0000000000..0b6380ed39
--- /dev/null
+++ b/quantum/process_keycode/process_audio.c
@@ -0,0 +1,62 @@
+#include "audio.h"
+#include "process_audio.h"
+
+static float compute_freq_for_midi_note(uint8_t note)
+{
+ // https://en.wikipedia.org/wiki/MIDI_tuning_standard
+ return pow(2.0, (note - 69) / 12.0) * 440.0f;
+}
+
+bool process_audio(uint16_t keycode, keyrecord_t *record) {
+
+ if (keycode == AU_ON && record->event.pressed) {
+ audio_on();
+ return false;
+ }
+
+ if (keycode == AU_OFF && record->event.pressed) {
+ audio_off();
+ return false;
+ }
+
+ if (keycode == AU_TOG && record->event.pressed) {
+ if (is_audio_on())
+ {
+ audio_off();
+ }
+ else
+ {
+ audio_on();
+ }
+ return false;
+ }
+
+ if (keycode == MUV_IN && record->event.pressed) {
+ voice_iterate();
+ music_scale_user();
+ return false;
+ }
+
+ if (keycode == MUV_DE && record->event.pressed) {
+ voice_deiterate();
+ music_scale_user();
+ return false;
+ }
+
+ return true;
+}
+
+void process_audio_noteon(uint8_t note) {
+ play_note(compute_freq_for_midi_note(note), 0xF);
+}
+
+void process_audio_noteoff(uint8_t note) {
+ stop_note(compute_freq_for_midi_note(note));
+}
+
+void process_audio_all_notes_off(void) {
+ stop_all_notes();
+}
+
+__attribute__ ((weak))
+void audio_on_user() {} \ No newline at end of file
diff --git a/quantum/process_keycode/process_audio.h b/quantum/process_keycode/process_audio.h
new file mode 100644
index 0000000000..7ac15b7330
--- /dev/null
+++ b/quantum/process_keycode/process_audio.h
@@ -0,0 +1,11 @@
+#ifndef PROCESS_AUDIO_H
+#define PROCESS_AUDIO_H
+
+bool process_audio(uint16_t keycode, keyrecord_t *record);
+void process_audio_noteon(uint8_t note);
+void process_audio_noteoff(uint8_t note);
+void process_audio_all_notes_off(void);
+
+void audio_on_user(void);
+
+#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c
index 577dad43ac..700c6ce8e6 100644
--- a/quantum/process_keycode/process_midi.c
+++ b/quantum/process_keycode/process_midi.c
@@ -1,68 +1,238 @@
#include "process_midi.h"
-bool midi_activated = false;
-uint8_t midi_starting_note = 0x0C;
-int midi_offset = 7;
-
-bool process_midi(uint16_t keycode, keyrecord_t *record) {
- if (keycode == MI_ON && record->event.pressed) {
- midi_activated = true;
-#ifdef AUDIO_ENABLE
- music_scale_user();
-#endif
- return false;
- }
+#ifdef MIDI_ENABLE
+#include "midi.h"
+
+#ifdef MIDI_BASIC
+
+void process_midi_basic_noteon(uint8_t note)
+{
+ midi_send_noteon(&midi_device, 0, note, 128);
+}
+
+void process_midi_basic_noteoff(uint8_t note)
+{
+ midi_send_noteoff(&midi_device, 0, note, 0);
+}
+
+void process_midi_all_notes_off(void)
+{
+ midi_send_cc(&midi_device, 0, 0x7B, 0);
+}
+
+#endif // MIDI_BASIC
+
+#ifdef MIDI_ADVANCED
+
+#include "timer.h"
+
+static uint8_t tone_status[MIDI_TONE_COUNT];
+
+static uint8_t midi_modulation;
+static int8_t midi_modulation_step;
+static uint16_t midi_modulation_timer;
+
+inline uint8_t compute_velocity(uint8_t setting)
+{
+ return (setting + 1) * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN + 1));
+}
- if (keycode == MI_OFF && record->event.pressed) {
- midi_activated = false;
- midi_send_cc(&midi_device, 0, 0x7B, 0);
- return false;
+void midi_init(void)
+{
+ midi_config.octave = MI_OCT_2 - MIDI_OCTAVE_MIN;
+ midi_config.transpose = 0;
+ midi_config.velocity = (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN);
+ midi_config.channel = 0;
+ midi_config.modulation_interval = 8;
+
+ for (uint8_t i = 0; i < MIDI_TONE_COUNT; i++)
+ {
+ tone_status[i] = MIDI_INVALID_NOTE;
}
- if (midi_activated) {
- if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) {
- if (record->event.pressed) {
- midi_starting_note++; // Change key
- midi_send_cc(&midi_device, 0, 0x7B, 0);
- }
- return false;
- }
- if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) {
- if (record->event.pressed) {
- midi_starting_note--; // Change key
- midi_send_cc(&midi_device, 0, 0x7B, 0);
- }
- return false;
- }
- if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
- midi_offset++; // Change scale
- midi_send_cc(&midi_device, 0, 0x7B, 0);
- return false;
- }
- if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
- midi_offset--; // Change scale
- midi_send_cc(&midi_device, 0, 0x7B, 0);
- return false;
- }
- // basic
- // uint8_t note = (midi_starting_note + SCALE[record->event.key.col + midi_offset])+12*(MATRIX_ROWS - record->event.key.row);
- // advanced
- // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+12*(MATRIX_ROWS - record->event.key.row);
- // guitar
- uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+5*(MATRIX_ROWS - record->event.key.row);
- // violin
- // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+7*(MATRIX_ROWS - record->event.key.row);
-
- if (record->event.pressed) {
- // midi_send_noteon(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127);
- midi_send_noteon(&midi_device, 0, note, 127);
- } else {
- // midi_send_noteoff(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127);
- midi_send_noteoff(&midi_device, 0, note, 127);
- }
-
- if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
- return false;
+ midi_modulation = 0;
+ midi_modulation_step = 0;
+ midi_modulation_timer = 0;
+}
+
+void midi_task(void)
+{
+ if (timer_elapsed(midi_modulation_timer) < midi_config.modulation_interval)
+ return;
+ midi_modulation_timer = timer_read();
+
+ if (midi_modulation_step != 0)
+ {
+ dprintf("midi modulation %d\n", midi_modulation);
+ midi_send_cc(&midi_device, midi_config.channel, 0x1, midi_modulation);
+
+ if (midi_modulation_step < 0 && midi_modulation < -midi_modulation_step) {
+ midi_modulation = 0;
+ midi_modulation_step = 0;
+ return;
+ }
+
+ midi_modulation += midi_modulation_step;
+
+ if (midi_modulation > 127)
+ midi_modulation = 127;
}
- return true;
}
+