summary refs log tree commit diff
path: root/quantum
diff options
context:
space:
mode:
authorThat-Canadian <poole.chris.11@gmail.com>2017-08-03 10:52:30 -0400
committerThat-Canadian <poole.chris.11@gmail.com>2017-08-03 10:52:30 -0400
commitc33434c0d64dd7cbd5f6371c7cb4ac5e05924944 (patch)
tree59fe34d95089a59fa4e615fd995c81d274147bba /quantum
parentdb5bb7dbbfa2d2eb4f41aa4c768c3c5c8d73f563 (diff)
parent07ba06d0b6e516bcfa4cbccbed9cfd8dc131072a (diff)
Merge branch 'master' into eco-keyboard
Diffstat (limited to 'quantum')
-rw-r--r--quantum/analog.c69
-rw-r--r--quantum/analog.h52
-rw-r--r--quantum/audio/audio.c54
-rw-r--r--quantum/audio/audio.h8
-rw-r--r--quantum/audio/musical_notes.h7
-rw-r--r--quantum/audio/song_list.h74
-rw-r--r--quantum/config_common.h2
-rw-r--r--quantum/keymap_common.c1
-rw-r--r--quantum/keymap_extras/keymap_steno.h76
-rw-r--r--quantum/keymap_extras/sendstring_colemak.h41
-rw-r--r--quantum/keymap_extras/sendstring_dvorak.h41
-rw-r--r--quantum/keymap_extras/sendstring_jis.h58
-rwxr-xr-xquantum/light_ws2812.c342
-rwxr-xr-xquantum/light_ws2812.h91
-rw-r--r--quantum/process_keycode/process_audio.c22
-rw-r--r--quantum/process_keycode/process_music.c153
-rw-r--r--quantum/process_keycode/process_music.h9
-rw-r--r--quantum/process_keycode/process_steno.c166
-rw-r--r--quantum/process_keycode/process_steno.h31
-rw-r--r--quantum/process_keycode/process_tap_dance.c18
-rw-r--r--quantum/process_keycode/process_tap_dance.h14
-rw-r--r--quantum/quantum.c209
-rw-r--r--quantum/quantum.h10
-rw-r--r--quantum/quantum_keycodes.h13
-rw-r--r--quantum/rgblight.h2
-rw-r--r--quantum/visualizer/common_gfxconf.h325
-rw-r--r--quantum/visualizer/default_animations.c176
-rw-r--r--quantum/visualizer/default_animations.h (renamed from quantum/visualizer/lcd_backlight_keyframes.h)18
-rw-r--r--quantum/visualizer/lcd_backlight_keyframes.c8
-rw-r--r--quantum/visualizer/lcd_keyframes.c4
-rw-r--r--quantum/visualizer/led_backlight_keyframes.c (renamed from quantum/visualizer/led_keyframes.c)24
-rw-r--r--quantum/visualizer/led_backlight_keyframes.h (renamed from quantum/visualizer/led_keyframes.h)22
-rw-r--r--quantum/visualizer/visualizer.c7
-rw-r--r--quantum/visualizer/visualizer.mk42
34 files changed, 1356 insertions, 833 deletions
diff --git a/quantum/analog.c b/quantum/analog.c
deleted file mode 100644
index 1ec38df75d..0000000000
--- a/quantum/analog.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Copyright 2015 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/>.
- */
-
-// Simple analog to digitial conversion
-
-#include <avr/io.h>
-#include <avr/pgmspace.h>
-#include <stdint.h>
-#include "analog.h"
-
-
-static uint8_t aref = (1<<REFS0); // default to AREF = Vcc
-
-
-void analogReference(uint8_t mode)
-{
-	aref = mode & 0xC0;
-}
-
-
-// Arduino compatible pin input
-int16_t analogRead(uint8_t pin)
-{
-#if defined(__AVR_ATmega32U4__)
-	static const uint8_t PROGMEM pin_to_mux[] = {
-		0x00, 0x01, 0x04, 0x05, 0x06, 0x07,
-		0x25, 0x24, 0x23, 0x22, 0x21, 0x20};
-	if (pin >= 12) return 0;
-	return adc_read(pgm_read_byte(pin_to_mux + pin));
-#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
-	if (pin >= 8) return 0;
-	return adc_read(pin);
-#else
-	return 0;
-#endif
-}
-
-// Mux input
-int16_t adc_read(uint8_t mux)
-{
-#if defined(__AVR_AT90USB162__)
-	return 0;
-#else
-	uint8_t low;
-
-	ADCSRA = (1<<ADEN) | ADC_PRESCALER;		// enable ADC
-	ADCSRB = (1<<ADHSM) | (mux & 0x20);		// high speed mode
-	ADMUX = aref | (mux & 0x1F);			// configure mux input
-	ADCSRA = (1<<ADEN) | ADC_PRESCALER | (1<<ADSC);	// start the conversion
-	while (ADCSRA & (1<<ADSC)) ;			// wait for result
-	low = ADCL;					// must read LSB first
-	return (ADCH << 8) | low;			// must read MSB only once!
-#endif
-}
-
-
diff --git a/quantum/analog.h b/quantum/analog.h
deleted file mode 100644
index 8d93de7dc2..0000000000
--- a/quantum/analog.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright 2015 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/>.
- */
-
-#ifndef _analog_h_included__
-#define _analog_h_included__
-
-#include <stdint.h>
-
-void analogReference(uint8_t mode);
-int16_t analogRead(uint8_t pin);
-int16_t adc_read(uint8_t mux);
-
-#define ADC_REF_POWER     (1<<REFS0)
-#define ADC_REF_INTERNAL  ((1<<REFS1) | (1<<REFS0))
-#define ADC_REF_EXTERNAL  (0)
-
-// These prescaler values are for high speed mode, ADHSM = 1
-#if F_CPU == 16000000L
-#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS1))
-#elif F_CPU == 8000000L
-#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS0))
-#elif F_CPU == 4000000L
-#define ADC_PRESCALER ((1<<ADPS2))
-#elif F_CPU == 2000000L
-#define ADC_PRESCALER ((1<<ADPS1) | (1<<ADPS0))
-#elif F_CPU == 1000000L
-#define ADC_PRESCALER ((1<<ADPS1))
-#else
-#define ADC_PRESCALER ((1<<ADPS0))
-#endif
-
-// some avr-libc versions do not properly define ADHSM
-#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
-#if !defined(ADHSM)
-#define ADHSM (7)
-#endif
-#endif
-
-#endif
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
index c924f2bd58..8e8570d26c 100644
--- a/quantum/audio/audio.c
+++ b/quantum/audio/audio.c
@@ -13,6 +13,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/>.
  */
+
 #include <stdio.h>
 #include <string.h>
 //#include <math.h>
@@ -98,7 +99,6 @@ uint16_t note_position = 0;
 float (* notes_pointer)[][2];
 uint16_t notes_count;
 bool     notes_repeat;
-float    notes_rest;
 bool     note_resting = false;
 
 uint8_t current_note = 0;
@@ -119,9 +119,17 @@ 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;
+
 void audio_init()
 {
 
+    if (audio_initialized)
+        return;
+
     // Check EEPROM
     if (!eeconfig_is_enabled())
     {
@@ -169,6 +177,11 @@ void audio_init()
     #endif
 
     audio_initialized = true;
+
+    if (audio_config.enable) {
+        PLAY_SONG(startup_song);
+    }
+
 }
 
 void stop_all_notes()
@@ -402,9 +415,12 @@ ISR(TIMER3_COMPA_vect)
         note_position++;
         bool end_of_note = false;
         if (TIMER_3_PERIOD > 0) {
-            end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF));
+            if (!note_resting) 
+                end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF - 1));
+            else
+                end_of_note = (note_position >= (note_length));
         } else {
-            end_of_note = (note_position >= (note_length * 0x7FF));
+            end_of_note = (note_position >= (note_length));
         }
 
         if (end_of_note) {
@@ -419,11 +435,16 @@ ISR(TIMER3_COMPA_vect)
                     return;
                 }
             }
-            if (!note_resting && (notes_rest > 0)) {
+            if (!note_resting) {
                 note_resting = true;
-                note_frequency = 0;
-                note_length = notes_rest;
                 current_note--;
+                if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
+                    note_frequency = 0;
+                    note_length = 1;
+                } else {
+                    note_frequency = (*notes_pointer)[current_note][0];
+                    note_length = 1;
+                }
             } else {
                 note_resting = false;
                 envelope_index = 0;
@@ -534,9 +555,12 @@ ISR(TIMER1_COMPA_vect)
         note_position++;
         bool end_of_note = false;
         if (TIMER_1_PERIOD > 0) {
-            end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF));
+            if (!note_resting) 
+                end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF - 1));
+            else
+                end_of_note = (note_position >= (note_length));
         } else {
-            end_of_note = (note_position >= (note_length * 0x7FF));
+            end_of_note = (note_position >= (note_length));
         }
 
         if (end_of_note) {
@@ -551,11 +575,16 @@ ISR(TIMER1_COMPA_vect)
                     return;
                 }
             }
-            if (!note_resting && (notes_rest > 0)) {
+            if (!note_resting) {
                 note_resting = true;
-                note_frequency = 0;
-                note_length = notes_rest;
                 current_note--;
+                if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
+                    note_frequency = 0;
+                    note_length = 1;
+                } else {
+                    note_frequency = (*notes_pointer)[current_note][0];
+                    note_length = 1;
+                }
             } else {
                 note_resting = false;
                 envelope_index = 0;
@@ -624,7 +653,7 @@ void play_note(float freq, int vol) {
 
 }
 
-void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest)
+void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat)
 {
 
     if (!audio_initialized) {
@@ -649,7 +678,6 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest)
         notes_pointer = np;
         notes_count = n_count;
         notes_repeat = n_repeat;
-        notes_rest = n_rest;
 
         place = 0;
         current_note = 0;
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
index 27fdc2ab63..79e0da2295 100644
--- a/quantum/audio/audio.h
+++ b/quantum/audio/audio.h
@@ -86,7 +86,7 @@ void play_sample(uint8_t * s, uint16_t l, bool r);
 void play_note(float freq, int vol);
 void stop_note(float freq);
 void stop_all_notes(void);
-void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest);
+void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat);
 
 #define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \
                            0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \
@@ -98,8 +98,10 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest)
 // length. This works around the limitation of C's sizeof operation on pointers.
 // The global float array for the song must be used here.
 #define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
-#define PLAY_NOTE_ARRAY(note_array, note_repeat, note_rest_style) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), (note_repeat), (note_rest_style));
-
+#define PLAY_NOTE_ARRAY(note_array, note_repeat, deprecated_arg) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), (note_repeat)); \
+	_Pragma ("message \"'PLAY_NOTE_ARRAY' macro is deprecated\"")
+#define PLAY_SONG(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), false)
+#define PLAY_LOOP(note_array) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), true)
 
 bool is_playing_notes(void);
 
diff --git a/quantum/audio/musical_notes.h b/quantum/audio/musical_notes.h
index a3aaa2f199..647b695640 100644
--- a/quantum/audio/musical_notes.h
+++ b/quantum/audio/musical_notes.h
@@ -51,12 +51,6 @@
 #define ED_NOTE(n)                     EIGHTH_DOT_NOTE(n)
 #define SD_NOTE(n)                     SIXTEENTH_DOT_NOTE(n)
 
-// Note Styles
-// Staccato makes sure there is a rest between each note. Think: TA TA TA
-// Legato makes notes flow together. Think: TAAA
-#define STACCATO 0.01
-#define LEGATO   0
-
 // Note Timbre
 // Changes how the notes sound
 #define TIMBRE_12       0.125
@@ -65,7 +59,6 @@
 #define TIMBRE_75       0.750
 #define TIMBRE_DEFAULT  TIMBRE_50
 
-
 // Notes - # = Octave
 
 #define NOTE_REST         0.00
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h
index db2d1a94cd..f355d371bd 100644
--- a/quantum/audio/song_list.h
+++ b/quantum/audio/song_list.h
@@ -18,9 +18,7 @@
 #ifndef SONG_LIST_H
 #define SONG_LIST_H
 
-#define COIN_SOUND \
-    E__NOTE(_A5  ),\
-    HD_NOTE(_E6  ),
+#define NO_SOUND
 
 #define ODE_TO_JOY                                          \
     Q__NOTE(_E4), Q__NOTE(_E4), Q__NOTE(_F4), Q__NOTE(_G4), \
@@ -55,18 +53,29 @@
     E__NOTE(_CS4), E__NOTE(_B4),  QD_NOTE(_AS4), \
     E__NOTE(_AS4), E__NOTE(_AS4), QD_NOTE(_B4),
 
+#define STARTUP_SOUND  \
+    E__NOTE(_E6),     \
+    E__NOTE(_A6),     \
+    ED_NOTE(_E7),
+
 #define GOODBYE_SOUND \
     E__NOTE(_E7),     \
     E__NOTE(_A6),     \
     ED_NOTE(_E6),
 
-#define STARTUP_SOUND  \
+#define PLANCK_SOUND  \
     ED_NOTE(_E7 ),     \
     E__NOTE(_CS7),     \
     E__NOTE(_E6 ),     \
     E__NOTE(_A6 ),     \
     M__NOTE(_CS7, 20),
 
+#define PREONIC_SOUND \
+    M__NOTE(_B5, 20),  \
+    E__NOTE(_B6),      \
+    M__NOTE(_DS6, 20), \
+    E__NOTE(_B6),
+
 #define QWERTY_SOUND \
     E__NOTE(_GS6 ),  \
     E__NOTE(_A6  ),  \
@@ -107,7 +116,8 @@
     S__NOTE(_REST),  \
     ED_NOTE(_E7  ),
 
-#define MUSIC_SCALE_SOUND \
+
+#define MUSIC_ON_SOUND \
     E__NOTE(_A5 ),        \
     E__NOTE(_B5 ),        \
     E__NOTE(_CS6),        \
@@ -117,6 +127,50 @@
     E__NOTE(_GS6),        \
     E__NOTE(_A6 ),
 
+#define MUSIC_SCALE_SOUND MUSIC_ON_SOUND
+
+#define MUSIC_OFF_SOUND \
+    E__NOTE(_A6 ),        \
+    E__NOTE(_GS6 ),        \
+    E__NOTE(_FS6),        \
+    E__NOTE(_E6 ),        \
+    E__NOTE(_D6 ),        \
+    E__NOTE(_CS6),        \
+    E__NOTE(_B5),        \
+    E__NOTE(_A5 ),
+
+#define VOICE_CHANGE_SOUND \
+    Q__NOTE(_A5 ),        \
+    Q__NOTE(_CS6),        \
+    Q__NOTE(_E6 ),        \
+    Q__NOTE(_A6 ),
+
+#define CHROMATIC_SOUND \
+    Q__NOTE(_A5 ),        \
+    Q__NOTE(_AS5 ),        \
+    Q__NOTE(_B5),        \
+    Q__NOTE(_C6 ),        \
+    Q__NOTE(_CS6 ),        
+
+#define MAJOR_SOUND \
+    Q__NOTE(_A5 ),        \
+    Q__NOTE(_B5 ),        \
+    Q__NOTE(_CS6),        \
+    Q__NOTE(_D6 ),        \
+    Q__NOTE(_E6 ),        
+
+#define GUITAR_SOUND \
+    Q__NOTE(_E5 ),        \
+    Q__NOTE(_A5),        \
+    Q__NOTE(_D6 ),        \
+    Q__NOTE(_G6 ),
+
+#define VIOLIN_SOUND \
+    Q__NOTE(_G5 ),        \
+    Q__NOTE(_D6),        \
+    Q__NOTE(_A6 ),        \
+    Q__NOTE(_E7 ),
+
 #define CAPS_LOCK_ON_SOUND \
     E__NOTE(_A3),          \
     E__NOTE(_B3),
@@ -141,6 +195,16 @@
     E__NOTE(_E5),          \
     E__NOTE(_D5),
 
+#define AG_NORM_SOUND \
+    E__NOTE(_A5),      \
+    E__NOTE(_A5),
+
+#define AG_SWAP_SOUND \
+    SD_NOTE(_B5),      \
+    SD_NOTE(_A5),      \
+    SD_NOTE(_B5),      \
+    SD_NOTE(_A5),
+
 #define UNICODE_WINDOWS \
     E__NOTE(_B5),       \
     S__NOTE(_E6),
diff --git a/quantum/config_common.h b/quantum/config_common.h
index c88e02d918..4c6a702af4 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -100,4 +100,6 @@
 
 #define API_SYSEX_MAX_SIZE 32
 
+#include "song_list.h"
+
 #endif
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index b1460c53cc..1c522e8b8b 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -169,7 +169,6 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
 }
 
 // translates key to keycode
-__attribute__ ((weak))
 uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
 {
     // Read entire word (16bits)
diff --git a/quantum/keymap_extras/keymap_steno.h b/quantum/keymap_extras/keymap_steno.h
new file mode 100644
index 0000000000..4ce91cc135
--- /dev/null
+++ b/quantum/keymap_extras/keymap_steno.h
@@ -0,0 +1,76 @@
+/* Copyright 2017 Joseph Wasson
+ *
+ * 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/>.
+ */
+#ifndef KEYMAP_STENO_H
+#define KEYMAP_STENO_H
+
+#include "keymap.h"
+
+// List of keycodes for the steno keyboard. To prevent
+// errors, this must be <= 42 total entries in order to
+// support the GeminiPR protocol.
+enum steno_keycodes {
+  STN__MIN = QK_STENO,
+  STN_FN  = STN__MIN,
+  STN_NUM,
+  STN_N1 = STN_NUM,
+  STN_N2,
+  STN_N3,
+  STN_N4,
+  STN_N5,
+  STN_N6,
+  STN_SL,
+  STN_S1 = STN_SL,
+  STN_S2,
+  STN_TL,
+  STN_KL,
+  STN_PL,
+  STN_WL,
+  STN_HL,
+  STN_RL,
+  STN_A,
+  STN_O,
+  STN_STR,
+  STN_ST1 = STN_STR,
+  STN_ST2,
+  STN_RES1,
+  STN_RE1 = STN_RES1,
+  STN_RES2,
+  STN_RE2 = STN_RES2,
+  STN_PWR,
+  STN_ST3,
+  STN_ST4,
+  STN_E,
+  STN_U,
+  STN_FR,
+  STN_RR,
+  STN_PR,
+  STN_BR,
+  STN_LR,
+  STN_GR,
+  STN_TR,
+  STN_SR,
+  STN_DR,
+  STN_N7,
+  STN_N8,
+  STN_N9,
+  STN_NA,
+  STN_NB,
+  STN_NC,
+  STN_ZR,
+  STN__MAX = STN_ZR, // must be less than QK_STENO_BOLT
+};
+
+#endif
diff --git a/quantum/keymap_extras/sendstring_colemak.h b/quantum/keymap_extras/sendstring_colemak.h
new file mode 100644
index 0000000000..fa9ace9290
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_colemak.h
@@ -0,0 +1,41 @@
+/* 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/>.
+ */
+/* Sendstring definitions for the Colemak layout */
+#ifndef SENDSTRING_COLEMAK
+#define SENDSTRING_COLEMAK
+
+#include "keymap_colemak.h"
+
+const uint8_t ascii_to_keycode_lut[0x80] PROGMEM = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, KC_ESC, 0, 0, 0, 0,
+    KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
+    KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
+    KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
+    KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
+    KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
+    CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
+    CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
+    CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
+    KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
+    CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
+    CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
+    CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
+};
+
+#endif
diff --git a/quantum/keymap_extras/sendstring_dvorak.h b/quantum/keymap_extras/sendstring_dvorak.h
new file mode 100644
index 0000000000..f5c5c818b8
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_dvorak.h
@@ -0,0 +1,41 @@
+/* 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/>.
+ */
+/* Sendstring definitions for the Dvorak layout */
+#ifndef SENDSTRING_DVORAK
+#define SENDSTRING_DVORAK
+
+#include "keymap_dvorak.h"
+
+const uint8_t ascii_to_keycode_lut[0x80] PROGMEM = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, KC_ESC, 0, 0, 0, 0,
+    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,
+    DV_0, DV_1, DV_2, DV_3, DV_4, DV_5, DV_6, DV_7,
+    DV_8, DV_9, DV_SCLN, DV_SCLN, DV_COMM, DV_EQL, DV_DOT, DV_SLSH,
+    DV_2, DV_A, DV_B, DV_C, DV_D, DV_E, DV_F, DV_G,
+    DV_H, DV_I, DV_J, DV_K, DV_L, DV_M, DV_N, DV_O,
+    DV_P, DV_Q, DV_R, DV_S, DV_T, DV_U, DV_V, DV_W,
+    DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_6, DV_MINS,
+    DV_GRV, DV_A, DV_B, DV_C, DV_D, DV_E, DV_F, DV_G,
+    DV_H, DV_I, DV_J, DV_K, DV_L, DV_M, DV_N, DV_O,
+    DV_P, DV_Q, DV_R, DV_S, DV_T, DV_U, DV_V, DV_W,
+    DV_X, DV_Y, DV_Z, DV_LBRC, DV_BSLS, DV_RBRC, DV_GRV, KC_DEL
+};
+
+#endif
diff --git a/quantum/keymap_extras/sendstring_jis.h b/quantum/keymap_extras/sendstring_jis.h
new file mode 100644
index 0000000000..c5a38c6a5b
--- /dev/null
+++ b/quantum/keymap_extras/sendstring_jis.h
@@ -0,0 +1,58 @@
+/* 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/>.
+ */
+/* Sendstring definitions for the JIS keyboard layout */
+#ifndef SENDSTRING_JIS
+#define SENDSTRING_JIS
+
+const bool ascii_to_shift_lut[0x80] PROGMEM = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 1, 1, 1, 1,
+    0, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 0, 0, 0, 0, 1,
+    1, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 1, 1, 1, 1, 0
+};
+
+const uint8_t ascii_to_keycode_lut[0x80] PROGMEM = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, KC_ESC, 0, 0, 0, 0,
+    KC_SPC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
+    KC_8, KC_9, KC_QUOT, KC_SCLN, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
+    KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
+    KC_8, KC_9, KC_QUOT, KC_SCLN, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
+    KC_LBRC, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
+    KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
+    KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
+    KC_X, KC_Y, KC_Z, KC_RBRC, KC_JYEN, KC_BSLS, KC_EQL, KC_RO,
+    KC_LBRC, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
+    KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
+    KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
+    KC_X, KC_Y, KC_Z, KC_RBRC, KC_JYEN, KC_BSLS, KC_EQL, KC_DEL,
+};
+
+#endif
diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c
deleted file mode 100755
index 2506e3d8ec..0000000000
--- a/quantum/light_ws2812.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
-* light weight WS2812 lib V2.0b
-*
-* Controls WS2811/WS2812/WS2812B RGB-LEDs
-* Author: Tim (cpldcpu@gmail.com)
-*
-* Jan 18th, 2014  v2.0b Initial Version
-* Nov 29th, 2015  v2.3  Added SK6812RGBW support
-*
-* 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 "light_ws2812.h"
-#include <avr/interrupt.h>
-#include <avr/io.h>
-#include <util/delay.h>
-#include "debug.h"
-
-#ifdef RGBW_BB_TWI
-
-// Port for the I2C
-#define I2C_DDR DDRD
-#define I2C_PIN PIND
-#define I2C_PORT PORTD
-
-// Pins to be used in the bit banging
-#define I2C_CLK 0
-#define I2C_DAT 1
-
-#define I2C_DATA_HI()\
-I2C_DDR &= ~ (1 << I2C_DAT);\
-I2C_PORT |= (1 << I2C_DAT);
-#define I2C_DATA_LO()\
-I2C_DDR |= (1 << I2C_DAT);\
-I2C_PORT &= ~ (1 << I2C_DAT);
-
-#define I2C_CLOCK_HI()\
-I2C_DDR &= ~ (1 << I2C_CLK);\
-I2C_PORT |= (1 << I2C_CLK);
-#define I2C_CLOCK_LO()\
-I2C_DDR |= (1 << I2C_CLK);\
-I2C_PORT &= ~ (1 << I2C_CLK);
-
-#define I2C_DELAY 1
-
-void I2C_WriteBit(unsigned char c)
-{
-    if (c > 0)
-    {
-        I2C_DATA_HI();
-    }
-    else
-    {
-        I2C_DATA_LO();
-    }
-
-    I2C_CLOCK_HI();
-    _delay_us(I2C_DELAY);
-
-    I2C_CLOCK_LO();
-    _delay_us(I2C_DELAY);
-
-    if (c > 0)
-    {
-        I2C_DATA_LO();
-    }
-
-    _delay_us(I2C_DELAY);
-}
-
-// Inits bitbanging port, must be called before using the functions below
-//
-void I2C_Init(void)
-{
-    I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
-
-    I2C_CLOCK_HI();
-    I2C_DATA_HI();
-
-    _delay_us(I2C_DELAY);
-}
-
-// Send a START Condition
-//
-void I2C_Start(void)
-{
-    // set both to high at the same time
-    I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
-    _delay_us(I2C_DELAY);
-
-    I2C_DATA_LO();
-    _delay_us(I2C_DELAY);
-
-    I2C_CLOCK_LO();
-    _delay_us(I2C_DELAY);
-}
-
-// Send a STOP Condition
-//
-void I2C_Stop(void)
-{
-    I2C_CLOCK_HI();
-    _delay_us(I2C_DELAY);
-
-    I2C_DATA_HI();
-    _delay_us(I2C_DELAY);
-}
-
-// write a byte to the I2C slave device
-//
-unsigned char I2C_Write(unsigned char c)
-{
-    for (char i = 0; i < 8; i++)
-    {
-        I2C_WriteBit(c & 128);
-
-        c <<= 1;
-    }
-
-    
-    I2C_WriteBit(0);
-    _delay_us(I2C_DELAY);
-    _delay_us(I2C_DELAY);
-  
-    // _delay_us(I2C_DELAY);
-    //return I2C_ReadBit();
-    return 0;
-}
-
-
-#endif
-
-// Setleds for standard RGB
-void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds)
-{
-   // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
-   ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF));
-}
-
-void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask)
-{
-  // ws2812_DDRREG |= pinmask; // Enable DDR
-  // new universal format (DDR)
-  _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask;
-
-  ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
-  _delay_us(50);
-}
-
-// Setleds for SK6812RGBW
-void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds)
-{
-
-  #ifdef RGBW_BB_TWI
-    uint8_t sreg_prev, twcr_prev;
-    sreg_prev=SREG;
-    twcr_prev=TWCR;
-    cli();
-    TWCR &= ~(1<<TWEN);
-    I2C_Init();
-    I2C_Start();
-    I2C_Write(0x84);
-    uint16_t datlen = leds<<2;
-    uint8_t curbyte;
-    uint8_t * data = (uint8_t*)ledarray;
-    while (datlen--) {
-      curbyte=*data++;
-      I2C_Write(curbyte);
-    }
-    I2C_Stop();
-    SREG=sreg_prev;
-    TWCR=twcr_prev;
-  #endif
-
-
-  // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
-  // new universal format (DDR)
-  _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF);
-
-  ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF));
-
-
-  #ifndef RGBW_BB_TWI
-    _delay_us(80);
-  #endif
-}
-
-void ws2812_sendarray(uint8_t *data,uint16_t datlen)
-{
-  ws2812_sendarray_mask(data,datlen,_BV(RGB_DI_PIN & 0xF));
-}
-
-/*
-  This routine writes an array of bytes with RGB values to the Dataout pin
-  using the fast 800kHz clockless WS2811/2812 protocol.
-*/
-
-// Timing in ns
-#define w_zeropulse   350
-#define w_onepulse    900
-#define w_totalperiod 1250
-
-// Fixed cycles used by the inner loop
-#define w_fixedlow    2
-#define w_fixedhigh   4
-#define w_fixedtotal  8
-
-// Insert NOPs to match the timing, if possible
-#define w_zerocycles    (((F_CPU/1000)*w_zeropulse          )/1000000)
-#define w_onecycles     (((F_CPU/1000)*w_onepulse    +500000)/1000000)
-#define w_totalcycles   (((F_CPU/1000)*w_totalperiod +500000)/1000000)
-
-// w1 - nops between rising edge and falling edge - low
-#define w1 (w_zerocycles-w_fixedlow)
-// w2   nops between fe low and fe high
-#define w2 (w_onecycles-w_fixedhigh-w1)
-// w3   nops to complete loop
-#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
-
-#if w1>0
-  #define w1_nops w1
-#else
-  #define w1_nops  0
-#endif
-
-// The only critical timing parameter is the minimum pulse length of the "0"
-// Warn or throw error if this timing can not be met with current F_CPU settings.
-#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
-#if w_lowtime>550
-   #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
-#elif w_lowtime>450
-   #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
-   #warning "Please consider a higher clockspeed, if possible"
-#endif
-
-#if w2>0
-#define w2_nops w2
-#else
-#define w2_nops  0
-#endif
-
-#if w3>0
-#define w3_nops w3
-#else
-#define w3_nops  0
-#endif
-
-#define w_nop1  "nop      \n\t"
-#define w_nop2  "rjmp .+0 \n\t"
-#define w_nop4  w_nop2 w_nop2
-#define w_nop8  w_nop4 w_nop4
-#define w_nop16 w_nop8 w_nop8
-
-void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
-{
-  uint8_t curbyte,ctr,masklo;
-  uint8_t sreg_prev;
-
-  // masklo  =~maskhi&ws2812_PORTREG;
-  // maskhi |=        ws2812_PORTREG;
-  masklo  =~maskhi&_SFR_IO8((RGB_DI_PIN >> 4) + 2);
-  maskhi |=        _SFR_IO8((RGB_DI_PIN >> 4) + 2);
-  sreg_prev=SREG;
-  cli();
-
-  while (datlen--) {
-    curbyte=(*data++);
-
-    asm volatile(
-    "       ldi   %0,8  \n\t"
-    "loop%=:            \n\t"
-    "       out   %2,%3 \n\t"    //  '1' [01] '0' [01] - re
-#if (w1_nops&1)
-w_nop1
-#endif
-#if (w1_nops&2)
-w_nop2
-#endif
-#if (w1_nops&4)
-w_nop4
-#endif
-#if (w1_nops&8)
-w_nop8
-#endif
-#if (w1_nops&16)
-w_nop16
-#endif
-    "       sbrs  %1,7  \n\t"    //  '1' [03] '0' [02]
-    "       out   %2,%4 \n\t"    //  '1' [--] '0' [03] - fe-low
-    "       lsl   %1    \n\t"    //  '1' [04] '0' [04]
-#if (w2_nops&1)
-  w_nop1
-#endif
-#if (w2_nops&2)
-  w_nop2
-#endif
-#if (w2_nops&4)
-  w_nop4
-#endif
-#if (w2_nops&8)
-  w_nop8
-#endif
-#if (w2_nops&16)
-  w_nop16
-#endif
-    "       out   %2,%4 \n\t"    //  '1' [+1] '0' [+1] - fe-high
-#if (w3_nops&1)
-w_nop1
-#endif
-#if (w3_nops&2)
-w_nop2
-#endif
-#if (w3_nops&4)
-w_nop4
-#endif
-#if (w3_nops&8)
-w_nop8
-#endif
-#if (w3_nops&16)
-w_nop16
-#endif
-
-    "       dec   %0    \n\t"    //  '1' [+2] '0' [+2]
-    "       brne  loop%=\n\t"    //  '1' [+3] '0' [+4]
-    :	"=&d" (ctr)
-    :	"r" (curbyte), "I" (_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r" (maskhi), "r" (masklo)
-    );
-  }
-
-  SREG=sreg_prev;
-}
diff --git a/quantum/light_ws2812.h b/quantum/light_ws2812.h
deleted file mode 100755
index 60924a0fb6..0000000000
--- a/quantum/light_ws2812.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * light weight WS2812 lib include
- *
- * Version 2.3  - Nev 29th 2015
- * Author: Tim (cpldcpu@gmail.com)
- *
- * Please do not change this file! All configuration is handled in "ws2812_config.h"
- *
- * 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/>.
- */
-
-#ifndef LIGHT_WS2812_H_
-#define LIGHT_WS2812_H_
-
-#include <avr/io.h>
-#include <avr/interrupt.h>
-//#include "ws2812_config.h"
-//#include "i2cmaster.h"
-
-#ifdef RGBW
-  #define LED_TYPE struct cRGBW
-#else
-  #define LED_TYPE struct cRGB
-#endif
-
-
-/*
- *  Structure of the LED array
- *
- * cRGB:     RGB  for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106
- * cRGBW:    RGBW for SK6812RGBW
- */
-
-struct cRGB  { uint8_t g; uint8_t r; uint8_t b; };
-struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;};
-
-
-
-/* User Interface
- *
- * Input:
- *         ledarray:           An array of GRB data describing the LED colors
- *         number_of_leds:     The number of LEDs to write
- *         pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
- *
- * The functions will perform the following actions:
- *         - Set the data-out pin as output
- *         - Send out the LED data
- *         - Wait 50�s to reset the LEDs
- */
-
-void ws2812_setleds     (LED_TYPE *ledarray, uint16_t number_of_leds);
-void ws2812_setleds_pin (LED_TYPE *ledarray, uint16_t number_of_leds,uint8_t pinmask);
-void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);
-
-/*
- * Old interface / Internal functions
- *
- * The functions take a byte-array and send to the data output as WS2812 bitstream.
- * The length is the number of bytes to send - three per LED.
- */
-
-void ws2812_sendarray     (uint8_t *array,uint16_t length);
-void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);
-
-
-/*
- * Internal defines
- */
-#ifndef CONCAT
-#define CONCAT(a, b)            a ## b
-#endif
-#ifndef CONCAT_EXP
-#define CONCAT_EXP(a, b)   CONCAT(a, b)
-#endif
-
-// #define ws2812_PORTREG  CONCAT_EXP(PORT,ws2812_port)
-// #define ws2812_DDRREG   CONCAT_EXP(DDR,ws2812_port)
-
-#endif /* LIGHT_WS2812_H_ */
diff --git a/quantum/process_keycode/process_audio.c b/quantum/process_keycode/process_audio.c
index 0b6380ed39..32057ae8dc 100644
--- a/quantum/process_keycode/process_audio.c
+++ b/quantum/process_keycode/process_audio.c
@@ -1,10 +1,19 @@
 #include "audio.h"
 #include "process_audio.h"
 
+#ifndef VOICE_CHANGE_SONG
+    #define VOICE_CHANGE_SONG SONG(VOICE_CHANGE_SOUND)
+#endif
+float voice_change_song[][2] = VOICE_CHANGE_SONG;
+
+#ifndef PITCH_STANDARD_A
+    #define PITCH_STANDARD_A 440.0f
+#endif
+
 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;
+    return pow(2.0, (note - 69) / 12.0) * PITCH_STANDARD_A;
 }
 
 bool process_audio(uint16_t keycode, keyrecord_t *record) {
@@ -20,12 +29,9 @@ bool process_audio(uint16_t keycode, keyrecord_t *record) {
     }
 
     if (keycode == AU_TOG && record->event.pressed) {
-        if (is_audio_on())
-        {
+        if (is_audio_on()) {
             audio_off();
-        }
-        else
-        {
+        } else {
             audio_on();
         }
         return false;
@@ -33,13 +39,13 @@ bool process_audio(uint16_t keycode, keyrecord_t *record) {
 
     if (keycode == MUV_IN && record->event.pressed) {
         voice_iterate();
-        music_scale_user();
+        PLAY_SONG(voice_change_song);
         return false;
     }
 
     if (keycode == MUV_DE && record->event.pressed) {
         voice_deiterate();
-        music_scale_user();
+        PLAY_SONG(voice_change_song);
         return false;
     }
 
diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c
index 217dca2807..63841d1e87 100644
--- a/quantum/process_keycode/process_music.c
+++ b/quantum/process_keycode/process_music.c
@@ -27,6 +27,7 @@
 bool music_activated = false;
 uint8_t music_starting_note = 0x0C;
 int music_offset = 7;
+uint8_t music_mode = MUSIC_MODE_CHROMATIC;
 
 // music sequencer
 static bool music_sequence_recording = false;
@@ -39,6 +40,39 @@ static uint8_t music_sequence_position = 0;
 static uint16_t music_sequence_timer = 0;
 static uint16_t music_sequence_interval = 100;
 
+#ifdef AUDIO_ENABLE
+  #ifndef MUSIC_ON_SONG
+    #define MUSIC_ON_SONG SONG(MUSIC_ON_SOUND)
+  #endif
+  #ifndef MUSIC_OFF_SONG
+    #define MUSIC_OFF_SONG SONG(MUSIC_OFF_SOUND)
+  #endif
+  #ifndef CHROMATIC_SONG
+    #define CHROMATIC_SONG SONG(CHROMATIC_SOUND)
+  #endif
+  #ifndef GUITAR_SONG
+    #define GUITAR_SONG SONG(GUITAR_SOUND)
+  #endif
+  #ifndef VIOLIN_SONG
+    #define VIOLIN_SONG SONG(VIOLIN_SOUND)
+  #endif
+  #ifndef MAJOR_SONG
+    #define MAJOR_SONG SONG(MAJOR_SOUND)
+  #endif
+  float music_mode_songs[NUMBER_OF_MODES][5][2] = {
+    CHROMATIC_SONG,
+    GUITAR_SONG,
+    VIOLIN_SONG,
+    MAJOR_SONG
+  };
+  float music_on_song[][2] = MUSIC_ON_SONG;
+  float music_off_song[][2] = MUSIC_OFF_SONG;
+#endif
+
+#ifndef MUSIC_MASK
+  #define MUSIC_MASK keycode < 0xFF
+#endif
+
 static void music_noteon(uint8_t note) {
     #ifdef AUDIO_ENABLE
     process_audio_noteon(note);
@@ -79,70 +113,71 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {
     }
 
     if (keycode == MU_TOG && record->event.pressed) {
-        if (music_activated)
-        {
+        if (music_activated) {
             music_off();
-        }
-        else
-        {
+        } else {
             music_on();
         }
         return false;
     }
 
-    if (music_activated) {
+    if (keycode == MU_MOD && record->event.pressed) {
+      music_mode_cycle();
+      return false;
+    }
 
-      if (keycode == KC_LCTL && record->event.pressed) { // Start recording
-        music_all_notes_off();
-        music_sequence_recording = true;
-        music_sequence_recorded = false;
-        music_sequence_playing = false;
-        music_sequence_count = 0;
-        return false;
-      }
+    if (music_activated) {
+      if (record->event.pressed) {
+        if (keycode == KC_LCTL) { // Start recording
+          music_all_notes_off();
+          music_sequence_recording = true;
+          music_sequence_recorded = false;
+          music_sequence_playing = false;
+          music_sequence_count = 0;
+          return false;
+        }
 
-      if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing
-        music_all_notes_off();
-        if (music_sequence_recording) { // was recording
-          music_sequence_recorded = true;
+        if (keycode == KC_LALT) { // Stop recording/playing
+          music_all_notes_off();
+          if (music_sequence_recording) { // was recording
+            music_sequence_recorded = true;
+          }
+          music_sequence_recording = false;
+          music_sequence_playing = false;
+          return false;
         }
-        music_sequence_recording = false;
-        music_sequence_playing = false;
-        return false;
-      }
 
-      if (keycode == KC_LGUI && record->event.pressed && music_sequence_recorded) { // Start playing
-        music_all_notes_off();
-        music_sequence_recording = false;
-        music_sequence_playing = true;
-        music_sequence_position = 0;
-        music_sequence_timer = 0;
-        return false;
-      }
+        if (keycode == KC_LGUI && music_sequence_recorded) { // Start playing
+          music_all_notes_off();
+          music_sequence_recording = false;
+          music_sequence_playing = true;
+          music_sequence_position = 0;
+          music_sequence_timer = 0;
+          return false;
+        }
 
-      if (keycode == KC_UP) {
-        if (record->event.pressed)
-            music_sequence_interval-=10;
-        return false;
-      }
+        if (keycode == KC_UP) {
+          music_sequence_interval-=10;
+          return false;
+        }
 
-      if (keycode == KC_DOWN) {
-        if (record->event.pressed)
-            music_sequence_interval+=10;
-        return false;
+        if (keycode == KC_DOWN) {
+          music_sequence_interval+=10;
+          return false;
+        }
       }
 
-      #define MUSIC_MODE_GUITAR
-
-      #ifdef MUSIC_MODE_CHROMATIC
-      uint8_t note = (music_starting_note + record->event.key.col + music_offset - 3)+12*(MATRIX_ROWS - record->event.key.row);
-      #elif defined(MUSIC_MODE_GUITAR)
-      uint8_t note = (music_starting_note + record->event.key.col + music_offset + 32)+5*(MATRIX_ROWS - record->event.key.row);
-      #elif defined(MUSIC_MODE_VIOLIN)
-      uint8_t note = (music_starting_note + record->event.key.col + music_offset + 32)+7*(MATRIX_ROWS - record->event.key.row);
-      #else
-      uint8_t note = (music_starting_note + SCALE[record->event.key.col + music_offset] - 3)+12*(MATRIX_ROWS - record->event.key.row);
-      #endif
+      uint8_t note;
+      if (music_mode == MUSIC_MODE_CHROMATIC) 
+        note = (music_starting_note + record->event.key.col + music_offset - 3)+12*(MATRIX_ROWS - record->event.key.row);
+      else if (music_mode == MUSIC_MODE_GUITAR)
+        note = (music_starting_note + record->event.key.col + music_offset + 32)+5*(MATRIX_ROWS - record->event.key.row);
+      else if (music_mode == MUSIC_MODE_VIOLIN)
+        note = (music_starting_note + record->event.key.col + music_offset + 32)+7*(MATRIX_ROWS - record->event.key.row);
+      else if (music_mode == MUSIC_MODE_MAJOR)
+        note = (music_starting_note + SCALE[record->event.key.col + music_offset] - 3)+12*(MATRIX_ROWS - record->event.key.row);
+      else
+        note = music_starting_note;
 
       if (record->event.pressed) {
         music_noteon(note);
@@ -154,7 +189,7 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {
         music_noteoff(note);
       }
 
-      if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
+      if (MUSIC_MASK)
         return false;
     }
 
@@ -175,12 +210,26 @@ void music_toggle(void) {
 
 void music_on(void) {
     music_activated = 1;
+    #ifdef AUDIO_ENABLE
+      PLAY_SONG(music_on_song);
+    #endif
     music_on_user();
 }
 
 void music_off(void) {
-    music_activated = 0;
     music_all_notes_off();
+    music_activated = 0;
+    #ifdef AUDIO_ENABLE
+      PLAY_SONG(music_off_song);
+    #endif
+}
+
+void music_mode_cycle(void) {
+  music_all_notes_off();
+  music_mode = (music_mode + 1) % NUMBER_OF_MODES;
+  #ifdef AUDIO_ENABLE
+    PLAY_SONG(music_mode_songs[music_mode]);
+  #endif
 }
 
 void matrix_scan_music(void) {
diff --git a/quantum/process_keycode/process_music.h b/quantum/process_keycode/process_music.h
index 8dfbf041f4..ee027197c2 100644
--- a/quantum/process_keycode/process_music.h
+++ b/quantum/process_keycode/process_music.h
@@ -21,6 +21,14 @@
 
 #if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))
 
+enum music_modes {
+  MUSIC_MODE_CHROMATIC,
+  MUSIC_MODE_GUITAR,
+  MUSIC_MODE_VIOLIN,
+  MUSIC_MODE_MAJOR,
+  NUMBER_OF_MODES
+};
+
 bool process_music(uint16_t keycode, keyrecord_t *record);
 
 bool is_music_on(void);
@@ -31,6 +39,7 @@ void music_off(void);
 void music_on_user(void);
 void music_scale_user(void);
 void music_all_notes_off(void);
+void music_mode_cycle(void);
 
 void matrix_scan_music(void);
 
diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c
new file mode 100644
index 0000000000..71e5e8ff1c
--- /dev/null
+++ b/quantum/process_keycode/process_steno.c
@@ -0,0 +1,166 @@
+/* Copyright 2017 Joseph Wasson
+ *
+ * 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 "process_steno.h"
+#include "quantum_keycodes.h"
+#include "keymap_steno.h"
+#include "virtser.h"
+
+// TxBolt Codes
+#define TXB_NUL 0
+#define TXB_S_L 0b00000001
+#define TXB_T_L 0b00000010
+#define TXB_K_L 0b00000100
+#define TXB_P_L 0b00001000
+#define TXB_W_L 0b00010000
+#define TXB_H_L 0b00100000
+#define TXB_R_L 0b01000001
+#define TXB_A_L 0b01000010
+#define TXB_O_L 0b01000100
+#define TXB_STR 0b01001000
+#define TXB_E_R 0b01010000
+#define TXB_U_R 0b01100000
+#define TXB_F_R 0b10000001
+#define TXB_R_R 0b10000010
+#define TXB_P_R 0b10000100
+#define TXB_B_R 0b10001000
+#define TXB_L_R 0b10010000
+#define TXB_G_R 0b10100000
+#define TXB_T_R 0b11000001
+#define TXB_S_R 0b11000010
+#define TXB_D_R 0b11000100
+#define TXB_Z_R 0b11001000
+#define TXB_NUM 0b11010000
+
+#define TXB_GRP0 0b00000000
+#define TXB_GRP1 0b01000000
+#define TXB_GRP2 0b10000000
+#define TXB_GRP3 0b11000000
+#define TXB_GRPMASK 0b11000000
+
+#define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6)
+
+#define BOLT_STATE_SIZE 4
+#define GEMINI_STATE_SIZE 6
+
+uint8_t state[MAX(BOLT_STATE_SIZE, GEMINI_STATE_SIZE)] = {0};
+uint8_t pressed = 0;
+steno_mode_t mode;
+
+uint8_t boltmap[64] = {
+  TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM,
+  TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L,
+  TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL,
+  TXB_NUL, TXB_STR, TXB_STR, TXB_E_R, TXB_U_R, TXB_F_R, TXB_R_R,
+  TXB_P_R, TXB_B_R, TXB_L_R, TXB_G_R, TXB_T_R, TXB_S_R, TXB_D_R,
+  TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R
+};
+
+#define BOLTMAP_MASK (sizeof(boltmap) - 1)
+
+
+void steno_clear_state(void) {
+  memset(state, 0, sizeof(state));
+}
+
+void steno_init() {
+  if (!eeconfig_is_enabled()) {
+    eeconfig_init();
+  }
+  mode = eeprom_read_byte(EECONFIG_STENOMODE);
+}
+
+void steno_set_mode(steno_mode_t new_mode) {
+  steno_clear_state();
+  mode = new_mode;
+  eeprom_update_byte(EECONFIG_STENOMODE, mode);
+}
+
+void send_steno_state(uint8_t size, bool send_empty) {
+  for (uint8_t i = 0; i < size; ++i) {
+    if (state[i] || send_empty) {
+      virtser_send(state[i]);
+    }
+  }
+  steno_clear_state();
+}
+
+bool update_state_bolt(uint8_t key) {
+  uint8_t boltcode = boltmap[key];
+  state[TXB_GET_GROUP(boltcode)] |= boltcode;
+  return false;
+}
+
+bool send_state_bolt(void) {
+  send_steno_state(BOLT_STATE_SIZE, false);
+  virtser_send(0); // terminating byte
+  return false;
+}
+
+bool update_state_gemini(uint8_t key) {
+  state[key / 7] |= 1 << (6 - (key % 7));
+  return false;
+}
+
+bool send_state_gemini(void) {
+  state[0] |= 0x80; // Indicate start of packet
+  send_steno_state(GEMINI_STATE_SIZE, true);
+  return false;
+}
+
+bool process_steno(uint16_t keycode, keyrecord_t *record) {
+  switch (keycode) {
+    case QK_STENO_BOLT:
+      if (IS_PRESSED(record->event)) {
+        steno_set_mode(STENO_MODE_BOLT);
+      }
+      return false;
+
+    case QK_STENO_GEMINI:
+      if (IS_PRESSED(record->event)) {
+        steno_set_mode(STENO_MODE_GEMINI);
+      }
+      return false;
+
+    case STN__MIN...STN__MAX:
+      if (IS_PRESSED(record->event)) {
+        uint8_t key = keycode - QK_STENO;
+        ++pressed;
+        switch(mode) {
+          case STENO_MODE_BOLT:
+            return update_state_bolt(key);
+          case STENO_MODE_GEMINI:
+            return update_state_gemini(key);
+          default:
+            return false;
+        }
+      } else {
+        --pressed;
+        if (pressed <= 0) {
+          pressed = 0;
+          switch(mode) {
+            case STENO_MODE_BOLT:
+              return send_state_bolt();
+            case STENO_MODE_GEMINI:
+              return send_state_gemini();
+            default:
+              return false;
+          }
+        }
+      }
+
+  }
+  return true;
+}
diff --git a/quantum/process_keycode/process_steno.h b/quantum/process_keycode/process_steno.h
new file mode 100644
index 0000000000..3bbcbeaaf8
--- /dev/null
+++ b/quantum/process_keycode/process_steno.h
@@ -0,0 +1,31 @@
+/* Copyright 2017 Joseph Wasson
+ *
+ * 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/>.
+ */
+#ifndef PROCESS_STENO_H
+#define PROCESS_STENO_H
+
+#include "quantum.h"
+
+#if defined(STENO_ENABLE) && !defined(VIRTSER_ENABLE)
+  #error "must have virtser enabled to use steno"
+#endif
+
+typedef enum { STENO_MODE_BOLT, STENO_MODE_GEMINI } steno_mode_t;
+
+bool process_steno(uint16_t keycode, keyrecord_t *record);
+void steno_init(void);
+void steno_set_mode(steno_mode_t mode);
+
+#endif
\ No newline at end of file
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index 4fd45810bb..00870c4e7f 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -41,6 +41,24 @@ void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) {
   }
 }
 
+void qk_tap_dance_dual_role_finished (qk_tap_dance_state_t *state, void *user_data) {
+  qk_tap_dance_dual_role_t *pair = (qk_tap_dance_dual_role_t *)user_data;
+
+  if (state->count == 1) {
+    register_code16 (pair->kc);
+  } else if (state->count == 2) {
+    layer_invert (pair->layer);
+  }
+}
+
+void qk_tap_dance_dual_role_reset (qk_tap_dance_state_t *state, void *user_data) {
+  qk_tap_dance_dual_role_t *pair = (qk_tap_dance_dual_role_t *)user_data;
+
+  if (state->count == 1) {
+    unregister_code16 (pair->kc);
+  }
+}
+
 static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state,
                                                  void *user_data,
                                                  qk_tap_dance_user_fn_t fn)
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index f42c154a05..37a27c5366 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -54,11 +54,22 @@ typedef struct
   uint16_t kc2;
 } qk_tap_dance_pair_t;
 
+typedef struct
+{
+  uint16_t kc;
+  uint8_t layer;
+} qk_tap_dance_dual_role_t;
+
 #define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \
     .fn = { NULL, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset }, \
     .user_data = (void *)&((qk_tap_dance_pair_t) { kc1, kc2 }),  \
   }
 
+#define ACTION_TAP_DANCE_DUAL_ROLE(kc, layer) { \
+    .fn = { NULL, qk_tap_dance_dual_role_finished, qk_tap_dance_dual_role_reset }, \
+    .user_data = (void *)&((qk_tap_dance_dual_role_t) { kc, layer }), \
+  }
+
 #define ACTION_TAP_DANCE_FN(user_fn) {  \
     .fn = { NULL, user_fn, NULL }, \
     .user_data = NULL, \
@@ -86,6 +97,9 @@ void reset_tap_dance (qk_tap_dance_state_t *state);
 void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data);
 void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data);
 
+void qk_tap_dance_dual_role_finished (qk_tap_dance_state_t *state, void *user_data);
+void qk_tap_dance_dual_role_reset (qk_tap_dance_state_t *state, void *user_data);
+
 #else
 
 #define TD(n) KC_NO
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 5bb7b04d53..1f8ce6c46f 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -30,6 +30,25 @@ extern backlight_config_t backlight_config;
 #include "fauxclicky.h"
 #endif
 
+#ifdef AUDIO_ENABLE
+  #ifndef GOODBYE_SONG
+    #define GOODBYE_SONG SONG(GOODBYE_SOUND)
+  #endif
+  #ifndef AG_NORM_SONG
+    #define AG_NORM_SONG SONG(AG_NORM_SOUND)
+  #endif
+  #ifndef AG_SWAP_SONG
+    #define AG_SWAP_SONG SONG(AG_SWAP_SOUND)
+  #endif
+  #ifndef DEFAULT_LAYER_SONGS
+    #define DEFAULT_LAYER_SONGS { }
+  #endif
+  float goodbye_song[][2] = GOODBYE_SONG;
+  float ag_norm_song[][2] = AG_NORM_SONG;
+  float ag_swap_song[][2] = AG_SWAP_SONG;
+  float default_layer_songs[][16][2] = DEFAULT_LAYER_SONGS;
+#endif
+
 static void do_code16 (uint16_t code, void (*f) (uint8_t)) {
   switch (code) {
   case QK_MODS ... QK_MODS_MAX:
@@ -116,9 +135,15 @@ void reset_keyboard(void) {
   clear_keyboard();
 #if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_ENABLE_BASIC))
   music_all_notes_off();
+  uint16_t timer_start = timer_read();
+  PLAY_SONG(goodbye_song);
   shutdown_user();
-#endif
+  while(timer_elapsed(timer_start) < 250) 
+    wait_ms(1);
+  stop_all_notes();
+#else
   wait_ms(250);
+#endif
 #ifdef CATERINA_BOOTLOADER
   *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific
 #endif
@@ -175,6 +200,9 @@ bool process_record_quantum(keyrecord_t *record) {
   #ifdef AUDIO_ENABLE
     process_audio(keycode, record) &&
   #endif
+  #ifdef STENO_ENABLE
+    process_steno(keycode, record) &&
+  #endif
   #if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))
     process_music(keycode, record) &&
   #endif
@@ -351,6 +379,9 @@ bool process_record_quantum(keyrecord_t *record) {
           case MAGIC_SWAP_ALT_GUI:
             keymap_config.swap_lalt_lgui = true;
             keymap_config.swap_ralt_rgui = true;
+            #ifdef AUDIO_ENABLE
+              PLAY_SONG(ag_swap_song);
+            #endif
             break;
           case MAGIC_UNSWAP_CONTROL_CAPSLOCK:
             keymap_config.swap_control_capslock = false;
@@ -379,6 +410,9 @@ bool process_record_quantum(keyrecord_t *record) {
           case MAGIC_UNSWAP_ALT_GUI:
             keymap_config.swap_lalt_lgui = false;
             keymap_config.swap_ralt_rgui = false;
+            #ifdef AUDIO_ENABLE
+              PLAY_SONG(ag_norm_song);
+            #endif
             break;
           case MAGIC_TOGGLE_NKRO:
             keymap_config.nkro = !keymap_config.nkro;
@@ -455,103 +489,8 @@ bool process_record_quantum(keyrecord_t *record) {
   return process_action_kb(record);
 }
 
-#ifdef JIS_KEYCODE
-static const uint16_t ascii_to_shift_lut[8] PROGMEM = {
-  0x0000, /*0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0,*/
-  0x0000, /*0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0,*/
-  0x7ff0, /*0, 1, 1, 1, 1, 1, 1, 1,
-            1, 1, 1, 1, 0, 0, 0, 0,*/
-  0x000f, /*0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 1, 1, 1, 1,*/
-  0x7fff, /*0, 1, 1, 1, 1, 1, 1, 1,
-            1, 1, 1, 1, 1, 1, 1, 1,*/
-  0xffe1, /*1, 1, 1, 1, 1, 1, 1, 1,
-            1, 1, 1, 0, 0, 0, 0, 1,*/
-  0x8000, /*1, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0,*/
-  0x001e, /*0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 1, 1, 1, 1, 0*/
-};
-
-static const struct {
-  uint8_t controls_0[16],
-          controls_1[16],
-          numerics[16],
-          alphabets_0[16],
-          alphabets_1[16];
-} lower_to_keycode PROGMEM = {
-  .controls_0 = {
-    0, 0, 0, 0, 0, 0, 0, 0,
-    KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0, 
-  },
-  .controls_1 = {
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, KC_ESC, 0, 0, 0, 0,
-  },
-  .numerics = {
-    KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
-    KC_8, KC_9, KC_QUOT, KC_SCLN, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
-  },
-  .alphabets_0 = {
-    KC_LBRC, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
-    KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
-  },
-  .alphabets_1 = {
-    KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
-    KC_X, KC_Y, KC_Z, KC_RBRC, KC_JYEN, KC_BSLS, KC_EQL, KC_RO,
-  },
-};
-static const uint8_t* ascii_to_keycode_lut[8] = {
-  lower_to_keycode.controls_0,
-  lower_to_keycode.controls_1,
-  lower_to_keycode.numerics,
-  lower_to_keycode.numerics,
-  lower_to_keycode.alphabets_0,
-  lower_to_keycode.alphabets_1,
-  lower_to_keycode.alphabets_0,
-  lower_to_keycode.alphabets_1
-};
-
-void send_string(const char *str) {
-    while (1) {
-        uint8_t keycode;
-        bool shift;
-        uint8_t ascii_code = pgm_read_byte(str);
-
-        if ( ascii_code == 0x00u ){ break; }
-        else if (ascii_code == 0x20u) {
-          keycode = KC_SPC;
-          shift = false;
-        }
-        else if (ascii_code == 0x7Fu) {
-          keycode = KC_DEL;
-          shift = false;
-        }
-        else {
-          int hi = ascii_code>>4 & 0x0f,
-              lo = ascii_code & 0x0f;
-          keycode = pgm_read_byte(&ascii_to_keycode_lut[hi][lo]);
-          shift = !!( pgm_read_word(&ascii_to_shift_lut[hi]) & (0x8000u>>lo) );
-        }
-
-        if (shift) {
-            register_code(KC_LSFT);
-            register_code(keycode);
-            unregister_code(keycode);
-            unregister_code(KC_LSFT);
-        }
-        else {
-            register_code(keycode);
-            unregister_code(keycode);
-        }
-        ++str;
-    }
-}
-
-#else
-static const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = {
+__attribute__ ((weak))
+const bool ascii_to_shift_lut[0x80] PROGMEM = {
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
@@ -570,7 +509,8 @@ static const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = {
     0, 0, 0, 1, 1, 1, 1, 0
 };
 
-static const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = {
+__attribute__ ((weak))
+const uint8_t ascii_to_keycode_lut[0x80] PROGMEM = {
     0, 0, 0, 0, 0, 0, 0, 0,
     KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
@@ -590,12 +530,16 @@ static const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = {
 };
 
 void send_string(const char *str) {
+  send_string_with_delay(str, 0);
+}
+
+void send_string_with_delay(const char *str, uint8_t interval) {
     while (1) {
         uint8_t keycode;
         uint8_t ascii_code = pgm_read_byte(str);
         if (!ascii_code) break;
-        keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]);
-        if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) {
+        keycode = pgm_read_byte(&ascii_to_keycode_lut[ascii_code]);
+        if (pgm_read_byte(&ascii_to_shift_lut[ascii_code])) {
             register_code(KC_LSFT);
             register_code(keycode);
             unregister_code(keycode);
@@ -606,54 +550,18 @@ void send_string(const char *str) {
             unregister_code(keycode);
         }
         ++str;
+        // interval
+        { uint8_t ms = interval; while (ms--) wait_ms(1); }
     }
 }
 
-#endif
-
-/* for users whose OSes are set to Colemak */
-#if 0
-#include "keymap_colemak.h"
-
-const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = {
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 1, 1, 1, 1, 1, 1, 0,
-    1, 1, 1, 1, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 1, 0, 1, 0, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 0, 0, 0, 1, 1,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 1, 1, 1, 1, 0
-};
-
-const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = {
-    0, 0, 0, 0, 0, 0, 0, 0,
-    KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, KC_ESC, 0, 0, 0, 0,
-    KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
-    KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
-    KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
-    KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
-    KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
-    CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
-    CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
-    CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
-    KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
-    CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
-    CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
-    CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
-};
-
-#endif
+void set_single_persistent_default_layer(uint8_t default_layer) {
+  #ifdef AUDIO_ENABLE
+    PLAY_SONG(default_layer_songs[default_layer]);
+  #endif
+  eeconfig_update_default_layer(1U<<default_layer);
+  default_layer_set(1U<<default_layer);
+}
 
 void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
   if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) {
@@ -705,6 +613,9 @@ void matrix_init_quantum() {
   #ifdef BACKLIGHT_ENABLE
     backlight_init_ports();
   #endif
+  #ifdef AUDIO_ENABLE
+    audio_init();
+  #endif
   matrix_init_kb();
 }
 
@@ -814,14 +725,14 @@ void backlight_set(uint8_t level)
       //   _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
       // #endif
     #endif
-  } 
+  }
   #ifndef NO_BACKLIGHT_CLOCK
     else if ( level == BACKLIGHT_LEVELS ) {
       // Turn on PWM control of backlight pin
       TCCR1A |= _BV(COM1x1);
       // Set the brightness
       OCR1x = 0xFFFF;
-    } 
+    }
     else {
       // Turn on PWM control of backlight pin
       TCCR1A |= _BV(COM1x1);
@@ -839,7 +750,7 @@ uint8_t backlight_tick = 0;
 
 void backlight_task(void) {
   #ifdef NO_BACKLIGHT_CLOCK
-  if ((0xFFFF >> ((BACKLIGHT_LEVELS - backlight_config.level) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) { 
+  if ((0xFFFF >> ((BACKLIGHT_LEVELS - backlight_config.level) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) {
     #if BACKLIGHT_ON_STATE == 0
       // PORTx &= ~n
       _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 2bf18d095e..453cb43f88 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -56,9 +56,14 @@ extern uint32_t default_layer_state;
 #endif // MIDI_ENABLE
 
 #ifdef AUDIO_ENABLE
+	#include "audio.h"
  	#include "process_audio.h"
 #endif
 
+#ifdef STENO_ENABLE
+	#include "process_steno.h"
+#endif
+
 #if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))
 	#include "process_music.h"
 #endif
@@ -95,11 +100,16 @@ extern uint32_t default_layer_state;
 #endif
 
 #define SEND_STRING(str) send_string(PSTR(str))
+extern const bool ascii_to_shift_lut[0x80];
+extern const uint8_t ascii_to_keycode_lut[0x80];
 void send_string(const char *str);
+void send_string_with_delay(const char *str, uint8_t interval);
 
 // For tri-layer
 void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
 
+void set_single_persistent_default_layer(uint8_t default_layer);
+
 void tap_random_base64(void);
 
 #define IS_LAYER_ON(layer)  (layer_state & (1UL << (layer)))
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index 6038e31c46..acdb9248d6 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -26,6 +26,10 @@
 #endif
 #endif
 
+// Fillers to make layering more clear
+#define _______ KC_TRNS
+#define XXXXXXX KC_NO
+
 enum quantum_keycodes {
     // Ranges used in shortucuts - not to be used directly
     QK_TMK                = 0x0000,
@@ -67,6 +71,12 @@ enum quantum_keycodes {
     QK_TAP_DANCE_MAX      = 0x57FF,
     QK_LAYER_TAP_TOGGLE   = 0x5800,
     QK_LAYER_TAP_TOGGLE_MAX = 0x58FF,
+#ifdef STENO_ENABLE
+    QK_STENO              = 0x5A00,
+    QK_STENO_BOLT         = 0x5A30,
+    QK_STENO_GEMINI       = 0x5A31,
+    QK_STENO_MAX          = 0x5A3F,
+#endif
     QK_MOD_TAP            = 0x6000,
     QK_MOD_TAP_MAX        = 0x7FFF,
 #if defined(UNICODEMAP_ENABLE) && defined(UNICODE_ENABLE)
@@ -128,6 +138,9 @@ enum quantum_keycodes {
     MU_OFF,
     MU_TOG,
 
+    // Music mode cycle
+    MU_MOD,
+
     // Music voice iterate
     MUV_IN,
     MUV_DE,
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index 92130192ce..8fea96a9e8 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -61,7 +61,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include "eeconfig.h"
-#include "light_ws2812.h"
+#include "ws2812.h"
 
 extern LED_TYPE led[RGBLED_NUM];
 
diff --git a/quantum/visualizer/common_gfxconf.h b/quantum/visualizer/common_gfxconf.h
new file mode 100644
index 0000000000..eb705b1881
--- /dev/null
+++ b/quantum/visualizer/common_gfxconf.h
@@ -0,0 +1,325 @@
+/**
+ * This file has a different license to the rest of the uGFX system.
+ * You can copy, modify and distribute this file as you see fit.
+ * You do not need to publish your source modifications to this file.
+ * The only thing you are not permitted to do is to relicense it
+ * under a different license.
+ */
+
+/**
+ * Copy this file into your project directory and rename it as gfxconf.h
+ * Edit your copy to turn on the uGFX features you want to use.
+ * The values below are the defaults.
+ *
+ * Only remove the comments from lines where you want to change the
+ * default value. This allows definitions to be included from
+ * driver makefiles when required and provides the best future
+ * compatibility for your project.
+ *
+ * Please use spaces instead of tabs in this file.
+ */
+
+#ifndef COMMON_GFXCONF_H
+#define COMMON_GFXCONF_H
+
+
+///////////////////////////////////////////////////////////////////////////
+// GOS - One of these must be defined, preferably in your Makefile       //
+///////////////////////////////////////////////////////////////////////////
+//#define GFX_USE_OS_CHIBIOS                           TRUE
+//#define GFX_USE_OS_FREERTOS                          FALSE
+//    #define GFX_FREERTOS_USE_TRACE                   FALSE
+//#define GFX_USE_OS_WIN32                             FALSE
+//#define GFX_USE_OS_LINUX                             FALSE
+//#define GFX_USE_OS_OSX                               FALSE
+//#define GFX_USE_OS_ECOS                              FALSE
+//#define GFX_USE_OS_RAWRTOS                           FALSE
+//#define GFX_USE_OS_ARDUINO                           FALSE
+//#define GFX_USE_OS_KEIL                              FALSE
+//#define GFX_USE_OS_CMSIS                             FALSE
+//#define GFX_USE_OS_RAW32                             FALSE
+//    #define INTERRUPTS_OFF()                         optional_code
+//    #define INTERRUPTS_ON()                          optional_code
+// These are not defined by default for some reason
+#define GOS_NEED_X_THREADS	FALSE
+#define GOS_NEED_X_HEAP		FALSE
+
+// Options that (should where relevant) apply to all operating systems
+    #define GFX_NO_INLINE                            FALSE
+//    #define GFX_COMPILER                             GFX_COMPILER_UNKNOWN
+//    #define GFX_CPU                                  GFX_CPU_UNKNOWN
+//    #define GFX_OS_HEAP_SIZE                         0
+//    #define GFX_OS_NO_INIT                           FALSE
+//    #define GFX_OS_INIT_NO_WARNING                   FALSE
+//    #define GFX_OS_PRE_INIT_FUNCTION                 myHardwareInitRoutine
+//    #define GFX_OS_EXTRA_INIT_FUNCTION               myOSInitRoutine
+//    #define GFX_OS_EXTRA_DEINIT_FUNCTION             myOSDeInitRoutine
+
+
+///////////////////////////////////////////////////////////////////////////
+// GDISP                                                                 //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GDISP                                TRUE
+
+//#define GDISP_NEED_AUTOFLUSH                         FALSE
+//#define GDISP_NEED_TIMERFLUSH                        FALSE
+//#define GDISP_NEED_VALIDATION                        TRUE
+//#define GDISP_NEED_CLIP                              TRUE
+#define GDISP_NEED_CIRCLE                            TRUE
+#define GDISP_NEED_ELLIPSE                           TRUE
+#define GDISP_NEED_ARC                               TRUE
+#define GDISP_NEED_ARCSECTORS                        TRUE
+#define GDISP_NEED_CONVEX_POLYGON                    TRUE
+//#define GDISP_NEED_SCROLL                            FALSE
+#define GDISP_NEED_PIXELREAD                         TRUE
+#define GDISP_NEED_CONTROL                           TRUE
+//#define GDISP_NEED_QUERY                             FALSE
+//#define GDISP_NEED_MULTITHREAD                       FALSE
+//#define GDISP_NEED_STREAMING                         FALSE
+#define GDISP_NEED_TEXT                              TRUE
+//    #define GDISP_NEED_TEXT_WORDWRAP                 FALSE
+//    #define GDISP_NEED_ANTIALIAS                     FALSE
+//    #define GDISP_NEED_UTF8                          FALSE
+    #define GDISP_NEED_TEXT_KERNING                  TRUE
+//    #define GDISP_INCLUDE_FONT_UI1                   FALSE
+//    #define GDISP_INCLUDE_FONT_UI2                   FALSE		// The smallest preferred font.
+//    #define GDISP_INCLUDE_FONT_LARGENUMBERS          FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS10          FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS12          FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS16          FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS20          FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS24          FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS32          FALSE
+    #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12      TRUE
+//    #define GDISP_INCLUDE_FONT_FIXED_10X20           FALSE
+//    #define GDISP_INCLUDE_FONT_FIXED_7X14            FALSE
+    #define GDISP_INCLUDE_FONT_FIXED_5X8             TRUE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA       FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA       FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA       FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA       FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA       FALSE
+//    #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA   FALSE
+//    #define GDISP_INCLUDE_USER_FONTS                 FALSE
+
+//#define GDISP_NEED_IMAGE                             FALSE
+//    #define GDISP_NEED_IMAGE_NATIVE                  FALSE
+//    #define GDISP_NEED_IMAGE_GIF                     FALSE
+//    #define GDISP_NEED_IMAGE_BMP                     FALSE
+//        #define GDISP_NEED_IMAGE_BMP_1               FALSE
+//        #define GDISP_NEED_IMAGE_BMP_4               FALSE
+//        #define GDISP_NEED_IMAGE_BMP_4_RLE           FALSE
+//        #define GDISP_NEED_IMAGE_BMP_8               FALSE
+//        #define GDISP_NEED_IMAGE_BMP_8_RLE           FALSE
+//        #define GDISP_NEED_IMAGE_BMP_16              FALSE
+//        #define GDISP_NEED_IMAGE_BMP_24              FALSE
+//        #define GDISP_NEED_IMAGE_BMP_32              FALSE
+//    #define GDISP_NEED_IMAGE_JPG                     FALSE
+//    #define GDISP_NEED_IMAGE_PNG                     FALSE
+//    #define GDISP_NEED_IMAGE_ACCOUNTING              FALSE
+#ifdef EMULATOR
+#define GDISP_NEED_PIXMAP                            TRUE
+#endif
+//    #define GDISP_NEED_PIXMAP_IMAGE                  FALSE
+
+//#define GDISP_DEFAULT_ORIENTATION                    GDISP_ROTATE_LANDSCAPE    // If not defined the native hardware orientation is used.
+//#define GDISP_LINEBUF_SIZE                           128
+//#define GDISP_STARTUP_COLOR                          Black
+#define GDISP_NEED_STARTUP_LOGO                      FALSE
+
+//#define GDISP_TOTAL_DISPLAYS		                 2
+
+    #ifdef GDISP_DRIVER_LIST
+        // For code and speed optimization define as TRUE or FALSE if all controllers have the same capability
+        #define GDISP_HARDWARE_STREAM_WRITE          FALSE
+        #define GDISP_HARDWARE_STREAM_READ           FALSE
+        #define GDISP_HARDWARE_STREAM_POS            FALSE
+        #define GDISP_HARDWARE_DRAWPIXEL             TRUE
+        #define GDISP_HARDWARE_CLEARS                FALSE
+        #define GDISP_HARDWARE_FILLS                 FALSE
+        //#define GDISP_HARDWARE_BITFILLS              FALSE
+        #define GDISP_HARDWARE_SCROLL                FALSE
+        #define GDISP_HARDWARE_PIXELREAD             TRUE
+        #define GDISP_HARDWARE_CONTROL               TRUE
+        #define GDISP_HARDWARE_QUERY                 FALSE
+        #define GDISP_HARDWARE_CLIP                  FALSE
+
+        #define GDISP_PIXELFORMAT                    GDISP_PIXELFORMAT_RGB888
+    #endif
+
+// The custom format is not defined for some reason, so define it as error
+// so we don't get compiler warnings
+#define GDISP_PIXELFORMAT_CUSTOM GDISP_PIXELFORMAT_ERROR
+
+#define GDISP_USE_GFXNET                             FALSE
+//    #define GDISP_GFXNET_PORT                        13001
+//    #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP         FALSE
+//    #define GDISP_DONT_WAIT_FOR_NET_DISPLAY          FALSE
+//    #define GDISP_GFXNET_UNSAFE_SOCKETS              FALSE
+
+
+///////////////////////////////////////////////////////////////////////////
+// GWIN                                                                  //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GWIN                                 FALSE
+
+//#define GWIN_NEED_WINDOWMANAGER                      FALSE
+//    #define GWIN_REDRAW_IMMEDIATE                    FALSE
+//    #define GWIN_REDRAW_SINGLEOP                     FALSE
+//    #define GWIN_NEED_FLASHING                       FALSE
+//        #define GWIN_FLASHING_PERIOD                 250
+
+//#define GWIN_NEED_CONSOLE                            FALSE
+//    #define GWIN_CONSOLE_USE_HISTORY                 FALSE
+//        #define GWIN_CONSOLE_HISTORY_AVERAGING       FALSE
+//        #define GWIN_CONSOLE_HISTORY_ATCREATE        FALSE
+//    #define GWIN_CONSOLE_ESCSEQ                      FALSE
+//    #define GWIN_CONSOLE_USE_BASESTREAM              FALSE
+//    #define GWIN_CONSOLE_USE_FLOAT                   FALSE
+//#define GWIN_NEED_GRAPH                              FALSE
+//#define GWIN_NEED_GL3D                               FALSE
+
+//#define GWIN_NEED_WIDGET                             FALSE
+//#define GWIN_FOCUS_HIGHLIGHT_WIDTH                   1
+//    #define GWIN_NEED_LABEL                          FALSE
+//        #define GWIN_LABEL_ATTRIBUTE                 FALSE
+//    #define GWIN_NEED_BUTTON                         FALSE
+//        #define GWIN_BUTTON_LAZY_RELEASE             FALSE
+//    #define GWIN_NEED_SLIDER                         FALSE
+//        #define GWIN_SLIDER_NOSNAP                   FALSE
+//        #define GWIN_SLIDER_DEAD_BAND                5
+//        #define GWIN_SLIDER_TOGGLE_INC               20
+//    #define GWIN_NEED_CHECKBOX                       FALSE
+//    #define GWIN_NEED_IMAGE                          FALSE
+//        #define GWIN_NEED_IMAGE_ANIMATION            FALSE
+//    #define GWIN_NEED_RADIO                          FALSE
+//    #define GWIN_NEED_LIST                           FALSE
+//        #define GWIN_NEED_LIST_IMAGES                FALSE
+//    #define GWIN_NEED_PROGRESSBAR                    FALSE
+//        #define GWIN_PROGRESSBAR_AUTO                FALSE
+//    #define GWIN_NEED_KEYBOARD                       FALSE
+//        #define GWIN_KEYBOARD_DEFAULT_LAYOUT         VirtualKeyboard_English1
+//        #define GWIN_NEED_KEYBOARD_ENGLISH1          TRUE
+//    #define GWIN_NEED_TEXTEDIT                       FALSE
+//    #define GWIN_FLAT_STYLING                        FALSE
+//    #define GWIN_WIDGET_TAGS                         FALSE
+
+//#define GWIN_NEED_CONTAINERS                         FALSE
+//    #define GWIN_NEED_CONTAINER                      FALSE
+//    #define GWIN_NEED_FRAME                          FALSE
+//    #define GWIN_NEED_TABSET                         FALSE
+//        #define GWIN_TABSET_TABHEIGHT                18
+
+
+///////////////////////////////////////////////////////////////////////////
+// GEVENT                                                                //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GEVENT                               TRUE
+
+//#define GEVENT_ASSERT_NO_RESOURCE                    FALSE
+//#define GEVENT_MAXIMUM_SIZE                          32
+//#define GEVENT_MAX_SOURCE_LISTENERS                  32
+
+
+///////////////////////////////////////////////////////////////////////////
+// GTIMER                                                                //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GTIMER                               FALSE
+
+//#define GTIMER_THREAD_PRIORITY                       HIGH_PRIORITY
+//#define GTIMER_THREAD_WORKAREA_SIZE                  2048
+
+
+///////////////////////////////////////////////////////////////////////////
+// GQUEUE                                                                //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GQUEUE                               FALSE
+
+//#define GQUEUE_NEED_ASYNC                            FALSE
+//#define GQUEUE_NEED_GSYNC                            FALSE
+//#define GQUEUE_NEED_FSYNC                            FALSE
+//#define GQUEUE_NEED_BUFFERS                          FALSE
+
+///////////////////////////////////////////////////////////////////////////
+// GINPUT                                                                //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GINPUT                               FALSE
+
+//#define GINPUT_NEED_MOUSE                            FALSE
+//    #define GINPUT_TOUCH_STARTRAW                    FALSE
+//    #define GINPUT_TOUCH_NOTOUCH                     FALSE
+//    #define GINPUT_TOUCH_NOCALIBRATE                 FALSE
+//    #define GINPUT_TOUCH_NOCALIBRATE_GUI             FALSE
+//    #define GINPUT_MOUSE_POLL_PERIOD                 25
+//    #define GINPUT_MOUSE_CLICK_TIME                  300
+//    #define GINPUT_TOUCH_CXTCLICK_TIME               700
+//    #define GINPUT_TOUCH_USER_CALIBRATION_LOAD       FALSE
+//    #define GINPUT_TOUCH_USER_CALIBRATION_SAVE       FALSE
+//    #define GMOUSE_DRIVER_LIST                       GMOUSEVMT_Win32, GMOUSEVMT_Win32
+//#define GINPUT_NEED_KEYBOARD                         FALSE
+//    #define GINPUT_KEYBOARD_POLL_PERIOD              200
+//    #define GKEYBOARD_DRIVER_LIST                    GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32
+//    #define GKEYBOARD_LAYOUT_OFF                     FALSE
+//        #define GKEYBOARD_LAYOUT_SCANCODE2_US        FALSE
+//#define GINPUT_NEED_TOGGLE                           FALSE
+//#define GINPUT_NEED_DIAL                             FALSE
+
+
+///////////////////////////////////////////////////////////////////////////
+// GFILE                                                                 //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GFILE                                FALSE
+
+//#define GFILE_NEED_PRINTG                            FALSE
+//#define GFILE_NEED_SCANG                             FALSE
+//#define GFILE_NEED_STRINGS                           FALSE
+//#define GFILE_NEED_FILELISTS                         FALSE
+//#define GFILE_NEED_STDIO                             FALSE
+//#define GFILE_NEED_NOAUTOMOUNT                       FALSE
+//#define GFILE_NEED_NOAUTOSYNC                        FALSE
+
+//#define GFILE_NEED_MEMFS                             FALSE
+//#define GFILE_NEED_ROMFS                             FALSE
+//#define GFILE_NEED_RAMFS                             FALSE
+//#define GFILE_NEED_FATFS                             FALSE
+//#define GFILE_NEED_NATIVEFS                          FALSE
+//#define GFILE_NEED_CHBIOSFS                          FALSE
+
+//#define GFILE_ALLOW_FLOATS                           FALSE
+//#define GFILE_ALLOW_DEVICESPECIFIC                   FALSE
+//#define GFILE_MAX_GFILES                             3
+
+///////////////////////////////////////////////////////////////////////////
+// GADC                                                                  //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GADC                                 FALSE
+
+//#define GADC_MAX_LOWSPEED_DEVICES                    4
+
+
+///////////////////////////////////////////////////////////////////////////
+// GAUDIO                                                                //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GAUDIO                               FALSE
+// There seems to be a bug in the ugfx code, the wrong define is used
+// So define it in order to avoid warnings
+#define GFX_USE_GAUDIN                               GFX_USE_GAUDIO
+//    #define GAUDIO_NEED_PLAY                         FALSE
+//    #define GAUDIO_NEED_RECORD                       FALSE
+
+
+///////////////////////////////////////////////////////////////////////////
+// GMISC                                                                 //
+///////////////////////////////////////////////////////////////////////////
+#define GFX_USE_GMISC                                TRUE
+
+//#define GMISC_NEED_ARRAYOPS                          FALSE
+//#define GMISC_NEED_FASTTRIG                          FALSE
+//#define GMISC_NEED_FIXEDTRIG                         FALSE
+//#define GMISC_NEED_INVSQRT                           FALSE
+//    #define GMISC_INVSQRT_MIXED_ENDIAN               FALSE
+//    #define GMISC_INVSQRT_REAL_SLOW                  FALSE
+#define GMISC_NEED_MATRIXFLOAT2D                     TRUE
+#define GMISC_NEED_MATRIXFIXED2D                     FALSE
+
+#endif /* COMMON_GFXCONF_H */
diff --git a/quantum/visualizer/default_animations.c b/quantum/visualizer/default_animations.c
new file mode 100644
index 0000000000..2d03273720
--- /dev/null
+++ b/quantum/visualizer/default_animations.c
@@ -0,0 +1,176 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * 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/>.
+ */
+
+#if defined(VISUALIZER_ENABLE)
+
+#include "default_animations.h"
+#include "visualizer.h"
+#ifdef LCD_ENABLE
+#include "lcd_keyframes.h"
+#endif
+#ifdef LCD_BACKLIGHT_ENABLE
+#include "lcd_backlight_keyframes.h"
+#endif
+
+#ifdef BACKLIGHT_ENABLE
+#include "led_backlight_keyframes.h"
+#endif
+
+#include "visualizer_keyframes.h"
+
+
+#if defined(LCD_ENABLE) || defined(LCD_BACKLIGHT_ENABLE) || defined(BACKLIGHT_ENABLE)
+
+static bool keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
+#ifdef LCD_ENABLE
+    lcd_keyframe_enable(animation, state);
+#endif
+#ifdef LCD_BACKLIGHT_ENABLE
+    lcd_backlight_keyframe_enable(animation, state);
+#endif
+#ifdef BACKLIGHT_ENABLE
+    led_backlight_keyframe_enable(animation, state);
+#endif
+    return false;
+}
+
+static bool keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
+#ifdef LCD_ENABLE
+    lcd_keyframe_disable(animation, state);
+#endif
+#ifdef LCD_BACKLIGHT_ENABLE
+    lcd_backlight_keyframe_disable(animation, state);
+#endif
+#ifdef BACKLIGHT_ENABLE
+    led_backlight_keyframe_disable(animation, state);
+#endif
+    return false;
+}
+
+static bool keyframe_fade_in(keyframe_animation_t* animation, visualizer_state_t* state) {
+    bool ret = false;
+#ifdef LCD_BACKLIGHT_ENABLE
+    ret |= lcd_backlight_keyframe_animate_color(animation, state);
+#endif
+#ifdef BACKLIGHT_ENABLE
+    ret |= led_backlight_keyframe_fade_in_all(animation, state);
+#endif
+    return ret;
+}
+
+static bool keyframe_fade_out(keyframe_animation_t* animation, visualizer_state_t* state) {
+    bool ret = false;
+#ifdef LCD_BACKLIGHT_ENABLE
+    ret |= lcd_backlight_keyframe_animate_color(animation, state);
+#endif
+#ifdef BACKLIGHT_ENABLE
+    ret |= led_backlight_keyframe_fade_out_all(animation, state);
+#endif
+    return ret;
+}
+
+
+// Don't worry, if the startup animation is long, you can use the keyboard like normal
+// during that time
+keyframe_animation_t default_startup_animation = {
+#if LCD_ENABLE
+    .num_frames = 3,
+#else
+    .num_frames = 2,
+#endif
+    .loop = false,
+    .frame_lengths = {
+        0, 
+#if LCD_ENABLE
+        0, 
+#endif
+        gfxMillisecondsToTicks(5000)},
+    .frame_functions = {
+            keyframe_enable,
+#if LCD_ENABLE
+            lcd_keyframe_draw_logo,
+#endif
+            keyframe_fade_in,
+    },
+};
+
+keyframe_animation_t default_suspend_animation = {
+#if LCD_ENABLE
+    .num_frames = 3,
+#else
+    .num_frames = 2,
+#endif
+    .loop = false,
+    .frame_lengths = {
+#if LCD_ENABLE
+        0, 
+#endif
+        gfxMillisecondsToTicks(1000), 
+        0},
+    .frame_functions = {
+#if LCD_ENABLE
+            lcd_keyframe_display_layer_text,
+#endif
+            keyframe_fade_out,
+            keyframe_disable,
+    },
+};
+#endif
+
+#if defined(BACKLIGHT_ENABLE)
+#define CROSSFADE_TIME 1000
+#define GRADIENT_TIME 3000
+
+keyframe_animation_t led_test_animation = {
+    .num_frames = 14,
+    .loop = true,
+    .frame_lengths = {
+        gfxMillisecondsToTicks(1000), // fade in
+        gfxMillisecondsToTicks(1000), // no op (leds on)
+        gfxMillisecondsToTicks(1000), // fade out
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
+        0,           // mirror leds
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
+        0,           // normal leds
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+
+    },
+    .frame_functions = {
+        led_backlight_keyframe_fade_in_all,
+        keyframe_no_operation,
+        led_backlight_keyframe_fade_out_all,
+        led_backlight_keyframe_crossfade,
+        led_backlight_keyframe_left_to_right_gradient,
+        led_backlight_keyframe_crossfade,
+        led_backlight_keyframe_top_to_bottom_gradient,
+        led_backlight_keyframe_mirror_orientation,
+        led_backlight_keyframe_crossfade,
+        led_backlight_keyframe_left_to_right_gradient,
+        led_backlight_keyframe_crossfade,
+        led_backlight_keyframe_top_to_bottom_gradient,
+        led_backlight_keyframe_normal_orientation,
+        led_backlight_keyframe_crossfade,
+    },
+};
+#endif
+
+#endif
diff --git a/quantum/visualizer/lcd_backlight_keyframes.h b/quantum/visualizer/default_animations.h
index e1c125cf91..51320b8b8a 100644
--- a/quantum/visualizer/lcd_backlight_keyframes.h
+++ b/quantum/visualizer/default_animations.h
@@ -14,17 +14,17 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_
-#define QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_
+#ifndef DEFAULT_ANIMATIONS_H_
+#define DEFAULT_ANIMATIONS_H_
 
 #include "visualizer.h"
 
-// Animates the LCD backlight color between the current color and the target color (of the state)
-bool backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state);
-// Sets the backlight color to the target color
-bool backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state);
+// You can use these default animations, but of course you can also write your own custom ones instead
+extern keyframe_animation_t default_startup_animation;
+extern keyframe_animation_t default_suspend_animation;
 
-bool backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
-bool backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
+// An animation for testing and demonstrating the led support, should probably not be used for real world
+// cases
+extern keyframe_animation_t led_test_animation;
 
-#endif /* QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_ */
+#endif /* DEFAULT_ANIMATIONS_H_ */
diff --git a/quantum/visualizer/lcd_backlight_keyframes.c b/quantum/visualizer/lcd_backlight_keyframes.c
index 8436d4e3dd..8c402baf6c 100644
--- a/quantum/visualizer/lcd_backlight_keyframes.c
+++ b/quantum/visualizer/lcd_backlight_keyframes.c
@@ -16,7 +16,7 @@
 
 #include "lcd_backlight_keyframes.h"
 
-bool backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool lcd_backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state) {
     int frame_length = animation->frame_lengths[animation->current_frame];
     int current_pos = frame_length - animation->time_left_in_frame;
     uint8_t t_h = LCD_HUE(state->target_lcd_color);
@@ -49,7 +49,7 @@ bool backlight_keyframe_animate_color(keyframe_animation_t* animation, visualize
     return true;
 }
 
-bool backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool lcd_backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)animation;
     state->prev_lcd_color = state->target_lcd_color;
     state->current_lcd_color = state->target_lcd_color;
@@ -60,14 +60,14 @@ bool backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_st
     return false;
 }
 
-bool backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool lcd_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)animation;
     (void)state;
     lcd_backlight_hal_color(0, 0, 0);
     return false;
 }
 
-bool backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool lcd_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)animation;
     (void)state;
     lcd_backlight_color(LCD_HUE(state->current_lcd_color),
diff --git a/quantum/visualizer/lcd_keyframes.c b/quantum/visualizer/lcd_keyframes.c
index 82e4184d2c..75eb457001 100644
--- a/quantum/visualizer/lcd_keyframes.c
+++ b/quantum/visualizer/lcd_keyframes.c
@@ -166,8 +166,8 @@ bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t*
     // or state structs, here we use the image
 
     //gdispGBlitArea is a tricky function to use since it supports blitting part of the image
-    // if you have full screen image, then just use 128 and 32 for both source and target dimensions
-    gdispGBlitArea(GDISP, 0, 0, 128, 32, 0, 0, 128, (pixel_t*)resource_lcd_logo);
+    // if you have full screen image, then just use LCD_WIDTH and LCD_HEIGHT for both source and target dimensions
+    gdispGBlitArea(GDISP, 0, 0, LCD_WIDTH, LCD_HEIGHT, 0, 0, LCD_WIDTH, (pixel_t*)resource_lcd_logo);
 
     return false;
 }
diff --git a/quantum/visualizer/led_keyframes.c b/quantum/visualizer/led_backlight_keyframes.c
index 7e6e5d1ab9..eb3f5561d8 100644
--- a/quantum/visualizer/led_keyframes.c
+++ b/quantum/visualizer/led_backlight_keyframes.c
@@ -23,7 +23,7 @@ SOFTWARE.
 */
 #include "gfx.h"
 #include "math.h"
-#include "led_keyframes.h"
+#include "led_backlight_keyframes.h"
 
 static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) {
     int frame_length = animation->frame_lengths[animation->current_frame];
@@ -41,8 +41,8 @@ static void keyframe_fade_all_leds_from_to(keyframe_animation_t* animation, uint
 }
 
 // TODO: Should be customizable per keyboard
-#define NUM_ROWS LED_NUM_ROWS
-#define NUM_COLS LED_NUM_COLS
+#define NUM_ROWS LED_HEIGHT
+#define NUM_COLS LED_WIDTH
 
 static uint8_t crossfade_start_frame[NUM_ROWS][NUM_COLS];
 static uint8_t crossfade_end_frame[NUM_ROWS][NUM_COLS];
@@ -55,19 +55,19 @@ static uint8_t compute_gradient_color(float t, float index, float num) {
     return (uint8_t)(255.0f * v);
 }
 
-bool led_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     keyframe_fade_all_leds_from_to(animation, 0, 255);
     return true;
 }
 
-bool led_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     keyframe_fade_all_leds_from_to(animation, 255, 0);
     return true;
 }
 
-bool led_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     float frame_length = animation->frame_lengths[animation->current_frame];
     float current_pos = frame_length - animation->time_left_in_frame;
@@ -79,7 +79,7 @@ bool led_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visual
     return true;
 }
 
-bool led_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     float frame_length = animation->frame_lengths[animation->current_frame];
     float current_pos = frame_length - animation->time_left_in_frame;
@@ -98,7 +98,7 @@ static void copy_current_led_state(uint8_t* dest) {
         }
     }
 }
-bool led_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     if (animation->first_update_of_frame) {
         copy_current_led_state(&crossfade_start_frame[0][0]);
@@ -114,28 +114,28 @@ bool led_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t*
     return true;
 }
 
-bool led_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)animation;
     gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180);
     return false;
 }
 
-bool led_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)animation;
     gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0);
     return false;
 }
 
-bool led_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)animation;
     gdispGSetPowerMode(LED_DISPLAY, powerOff);
     return false;
 }
 
-bool led_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)animation;
     gdispGSetPowerMode(LED_DISPLAY, powerOn);
diff --git a/quantum/visualizer/led_keyframes.h b/quantum/visualizer/led_backlight_keyframes.h
index a59a4f37d1..487151013a 100644
--- a/quantum/visualizer/led_keyframes.h
+++ b/quantum/visualizer/led_backlight_keyframes.h
@@ -22,21 +22,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
 
-#ifndef LED_KEYFRAMES_H
-#define LED_KEYFRAMES_H
+#ifndef LED_BACKLIGHT_KEYFRAMES_H
+#define LED_BACKLIGHT_KEYFRAMES_H
 
 #include "visualizer.h"
 
-bool led_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state);
-bool led_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state);
-bool led_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
-bool led_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
-bool led_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
-bool led_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
-bool led_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
 
-bool led_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
-bool led_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
 
 extern keyframe_animation_t led_test_animation;
 
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
index cc99d1e3b6..5b4d8d603e 100644
--- a/quantum/visualizer/visualizer.c
+++ b/quantum/visualizer/visualizer.c
@@ -52,7 +52,8 @@ SOFTWARE.
 
 // Define this in config.h
 #ifndef VISUALIZER_THREAD_PRIORITY
-#define "Visualizer thread priority not defined"
+// The visualizer needs gfx thread priorities
+#define VISUALIZER_THREAD_PRIORITY (NORMAL_PRIORITY - 2)
 #endif
 
 static visualizer_keyboard_status_t current_status = {
@@ -255,6 +256,9 @@ static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
         .mods = 0xFF,
         .leds = 0xFFFFFFFF,
         .suspended = false,
+    #ifdef BACKLIGHT_ENABLE
+        .backlight_level = 0,
+    #endif
     #ifdef VISUALIZER_USER_DATA_SIZE
         .user_data = {0},
     #endif
@@ -299,6 +303,7 @@ static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
                 else {
                     gdispGSetPowerMode(LED_DISPLAY, powerOff);
                 }
+                state.status.backlight_level = current_status.backlight_level;
             }
     #endif
             if (visualizer_enabled) {
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk
index 0f7d8636cf..102d23b7ef 100644
--- a/quantum/visualizer/visualizer.mk
+++ b/quantum/visualizer/visualizer.mk
@@ -20,6 +20,30 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
+define ADD_DRIVER
+    $(1)_DRIVER:=$(strip $($(1)_DRIVER))
+    $(1)_WIDTH:=$(strip $($(1)_WIDTH))
+    $(1)_HEIGHT:=$(strip $($(1)_HEIGHT))
+    ifeq ($($(1)_DRIVER),)
+        $$(error $(1)_DRIVER is not defined)
+    endif
+    ifeq ($($(1)_WIDTH),)
+        $$(error $(1)_WIDTH is not defined)
+    endif
+    ifeq ($($(1)_HEIGHT),)
+        $$(error $(1)_HEIGHT is not defined)
+    endif
+    OPT_DEFS+=-D$(1)_WIDTH=$($(1)_WIDTH)
+    OPT_DEFS+=-D$(1)_HEIGHT=$($(1)_HEIGHT)
+    GFXDEFS+=-D$(1)_WIDTH=$($(1)_WIDTH)
+    GFXDEFS+=-D$(1)_HEIGHT=$($(1)_HEIGHT)
+    $(1)_DISPLAY_NUMBER:=$$(words $$(GDISP_DRIVER_LIST))
+    OPT_DEFS+=-D$(1)_DISPLAY_NUMBER=$$($(1)_DISPLAY_NUMBER)
+    include $(TOP_DIR)/drivers/ugfx/gdisp/$($(1)_DRIVER)/driver.mk
+endef
+
+GDISP_DRIVER_LIST:=
+
 SRC += $(VISUALIZER_DIR)/visualizer.c \
 	$(VISUALIZER_DIR)/visualizer_keyframes.c
 EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR)
@@ -40,16 +64,32 @@ SRC += $(VISUALIZER_DIR)/lcd_backlight_keyframes.c
 # Note, that the linker will strip out any resources that are not actually in use
 SRC += $(VISUALIZER_DIR)/resources/lcd_logo.c
 OPT_DEFS += -DLCD_BACKLIGHT_ENABLE
+$(eval $(call ADD_DRIVER,LCD))
 endif
 
 ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
-SRC += $(VISUALIZER_DIR)/led_keyframes.c
+SRC += $(VISUALIZER_DIR)/led_backlight_keyframes.c
+$(eval $(call ADD_DRIVER,LED))
 endif
 
+SRC += $(VISUALIZER_DIR)/default_animations.c
+
 include $(GFXLIB)/gfx.mk
+# For the common_gfxconf.h
+GFXINC += quantum/visualizer
+
 GFXSRC := $(patsubst $(TOP_DIR)/%,%,$(GFXSRC))
 GFXDEFS := $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS)))
 
+GDISP_LIST_COMMA=,
+GDISP_LIST_EMPTY=
+GDISP_LIST_SPACE=$(GDISP_LIST_EMPTY) $(GDISP_LIST_EMPTY)
+
+GDISP_DRIVER_LIST := $(strip $(GDISP_DRIVER_LIST))
+GDISP_DRIVER_LIST := $(subst $(GDISP_LIST_SPACE),$(GDISP_LIST_COMMA),$(GDISP_DRIVER_LIST))
+
+GFXDEFS +=-DGDISP_DRIVER_LIST="$(GDISP_DRIVER_LIST)"
+
 ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","")
     SRC += keyboards/$(KEYBOARD)/keymaps/$(KEYMAP)/visualizer.c
 else