summary refs log tree commit diff
path: root/quantum/process_keycode
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/process_keycode')
-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
7 files changed, 353 insertions, 60 deletions
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