feat: hotkeys in config
This commit is contained in:
+1
-1
@@ -122,7 +122,7 @@ make -f Makefile.dev release-arch
|
|||||||
- [x] Arrows (up-down: bpm / left-right: cycle)
|
- [x] Arrows (up-down: bpm / left-right: cycle)
|
||||||
- [x] Save states (numkey: load / shift + numkey: save)
|
- [x] Save states (numkey: load / shift + numkey: save)
|
||||||
- [ ] (clean) static functions at top of files
|
- [ ] (clean) static functions at top of files
|
||||||
- [ ] Configurable key codes
|
- [x] Configurable key codes
|
||||||
- [ ] Key codes as inputs
|
- [ ] Key codes as inputs
|
||||||
- [ ] Mouse position and scroll as inputs
|
- [ ] Mouse position and scroll as inputs
|
||||||
- [ ] Joystick as input
|
- [ ] Joystick as input
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ When running, the following hotkeys are available:
|
|||||||
| <kbd>0</kbd>-<kbd>9</kbd> | Load state 0 to 9 |
|
| <kbd>0</kbd>-<kbd>9</kbd> | Load state 0 to 9 |
|
||||||
| <kbd>Shift</kbd> + <kbd>0</kbd>-<kbd>9</kbd> | Save state 0 to 9 |
|
| <kbd>Shift</kbd> + <kbd>0</kbd>-<kbd>9</kbd> | Save state 0 to 9 |
|
||||||
|
|
||||||
|
These are configurable in the [`forge_project.cfg`](#forge_projectcfg).
|
||||||
|
|
||||||
### CLI arguments
|
### CLI arguments
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
|
|||||||
@@ -269,4 +269,61 @@ MIDI_3_2_Z=
|
|||||||
# OTHER
|
# OTHER
|
||||||
# =====
|
# =====
|
||||||
|
|
||||||
SAVE_FILE_PREFIX=forge_default_save
|
# === SAVE FILES
|
||||||
|
# When loading/saving from last run or using save states
|
||||||
|
SAVE_FILE_PREFIX=forge_default_save
|
||||||
|
|
||||||
|
# === HOTKEYS
|
||||||
|
# You can change the default keycodes used on runtime
|
||||||
|
# Modifiers are encoded like this:
|
||||||
|
# 1000 -> shift
|
||||||
|
# 10000 -> control
|
||||||
|
# 100000 -> alt
|
||||||
|
# This means 110082 is control+alt+R
|
||||||
|
|
||||||
|
# R on (qwerty)
|
||||||
|
HOTKEY_RANDOMIZE=82
|
||||||
|
# SHIFT+R (qwerty)
|
||||||
|
HOTKEY_RESET=1082
|
||||||
|
# D (qwerty)
|
||||||
|
HOTKEY_DEMO=68
|
||||||
|
# A (qwerty)
|
||||||
|
HOTKEY_AUTORAND=65
|
||||||
|
# Left arrow
|
||||||
|
HOTKEY_AUTORAND_DOWN=263
|
||||||
|
# Right arrow
|
||||||
|
HOTKEY_AUTORAND_UP=262
|
||||||
|
# Down arrow
|
||||||
|
HOTKEY_TEMPO_DOWN=264
|
||||||
|
# Up arrow
|
||||||
|
HOTKEY_TEMPO_UP=265
|
||||||
|
|
||||||
|
# Number of load states keys
|
||||||
|
HOTKEY_LOAD_COUNT=10
|
||||||
|
|
||||||
|
# 1 to 9 then 0 keys
|
||||||
|
HOTKEY_LOAD_1=49
|
||||||
|
HOTKEY_LOAD_2=50
|
||||||
|
HOTKEY_LOAD_3=51
|
||||||
|
HOTKEY_LOAD_4=52
|
||||||
|
HOTKEY_LOAD_5=53
|
||||||
|
HOTKEY_LOAD_6=54
|
||||||
|
HOTKEY_LOAD_7=55
|
||||||
|
HOTKEY_LOAD_8=56
|
||||||
|
HOTKEY_LOAD_9=57
|
||||||
|
HOTKEY_LOAD_10=48
|
||||||
|
|
||||||
|
# Number of save states keys
|
||||||
|
HOTKEY_SAVE_COUNT=10
|
||||||
|
|
||||||
|
# 1 to 9 then 0 keys with shift
|
||||||
|
HOTKEY_SAVE_1=1049
|
||||||
|
HOTKEY_SAVE_2=1050
|
||||||
|
HOTKEY_SAVE_3=1051
|
||||||
|
HOTKEY_SAVE_4=1052
|
||||||
|
HOTKEY_SAVE_5=1053
|
||||||
|
HOTKEY_SAVE_6=1054
|
||||||
|
HOTKEY_SAVE_7=1055
|
||||||
|
HOTKEY_SAVE_8=1056
|
||||||
|
HOTKEY_SAVE_9=1057
|
||||||
|
HOTKEY_SAVE_10=1048
|
||||||
@@ -91,6 +91,17 @@ void config_file_read(ConfigFile *config, const char *path) {
|
|||||||
file_free(&file);
|
file_free(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool config_file_has(const ConfigFile *config, const char *key) {
|
||||||
|
ConfigFileItem c_key;
|
||||||
|
const ConfigFileItem *item;
|
||||||
|
|
||||||
|
strlcpy(c_key.key, key, STR_LEN);
|
||||||
|
|
||||||
|
item = (const ConfigFileItem *)hashmap_get(config->map, &c_key);
|
||||||
|
|
||||||
|
return item != NULL && strnlen(item->value, STR_LEN) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
||||||
const char *default_value) {
|
const char *default_value) {
|
||||||
ConfigFileItem c_key;
|
ConfigFileItem c_key;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
void config_file_read(ConfigFile *config, const char *path);
|
void config_file_read(ConfigFile *config, const char *path);
|
||||||
|
|
||||||
|
bool config_file_has(const ConfigFile *config, const char *key);
|
||||||
|
|
||||||
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
const char *config_file_get_str(const ConfigFile *config, const char *key,
|
||||||
const char *default_value);
|
const char *default_value);
|
||||||
|
|
||||||
|
|||||||
+98
-31
@@ -348,6 +348,68 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
|
|||||||
strlcpy(state_config->save_file_prefix,
|
strlcpy(state_config->save_file_prefix,
|
||||||
config_file_get_str(config, "SAVE_FILE_PREFIX", "forge_save"),
|
config_file_get_str(config, "SAVE_FILE_PREFIX", "forge_save"),
|
||||||
STR_LEN);
|
STR_LEN);
|
||||||
|
|
||||||
|
state_config->hotkey_randomize =
|
||||||
|
config_file_get_int(config, "HOTKEY_RANDOMIZE", 82);
|
||||||
|
state_config->hotkey_reset =
|
||||||
|
config_file_get_int(config, "HOTKEY_RESET", 1082);
|
||||||
|
state_config->hotkey_demo = config_file_get_int(config, "HOTKEY_DEMO", 68);
|
||||||
|
state_config->hotkey_autorand =
|
||||||
|
config_file_get_int(config, "HOTKEY_AUTORAND", 65);
|
||||||
|
state_config->hotkey_autorand_down =
|
||||||
|
config_file_get_int(config, "HOTKEY_AUTORAND_DOWN", 263);
|
||||||
|
state_config->hotkey_autorand_up =
|
||||||
|
config_file_get_int(config, "HOTKEY_AUTORAND_UP", 262);
|
||||||
|
state_config->hotkey_tempo_down =
|
||||||
|
config_file_get_int(config, "HOTKEY_TEMPO_DOWN", 264);
|
||||||
|
state_config->hotkey_tempo_up =
|
||||||
|
config_file_get_int(config, "HOTKEY_TEMPO_UP", 265);
|
||||||
|
|
||||||
|
if (config_file_has(config, "HOTKEY_LOAD_COUNT")) {
|
||||||
|
state_config->hotkey_load.length =
|
||||||
|
config_file_get_int(config, "HOTKEY_LOAD_COUNT", 0);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->hotkey_load.length; i++) {
|
||||||
|
snprintf(name, STR_LEN, "HOTKEY_LOAD_%d", i + 1);
|
||||||
|
state_config->hotkey_load.values[i] =
|
||||||
|
config_file_get_int(config, name, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state_config->hotkey_load.length = 10;
|
||||||
|
state_config->hotkey_load.values[0] = 49;
|
||||||
|
state_config->hotkey_load.values[1] = 50;
|
||||||
|
state_config->hotkey_load.values[2] = 51;
|
||||||
|
state_config->hotkey_load.values[3] = 52;
|
||||||
|
state_config->hotkey_load.values[4] = 53;
|
||||||
|
state_config->hotkey_load.values[5] = 54;
|
||||||
|
state_config->hotkey_load.values[6] = 55;
|
||||||
|
state_config->hotkey_load.values[7] = 56;
|
||||||
|
state_config->hotkey_load.values[8] = 57;
|
||||||
|
state_config->hotkey_load.values[9] = 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_file_has(config, "HOTKEY_SAVE_COUNT")) {
|
||||||
|
state_config->hotkey_save.length =
|
||||||
|
config_file_get_int(config, "HOTKEY_SAVE_COUNT", 0);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < state_config->hotkey_save.length; i++) {
|
||||||
|
snprintf(name, STR_LEN, "HOTKEY_SAVE_%d", i + 1);
|
||||||
|
state_config->hotkey_save.values[i] =
|
||||||
|
config_file_get_int(config, name, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state_config->hotkey_save.length = 10;
|
||||||
|
state_config->hotkey_save.values[0] = 1049;
|
||||||
|
state_config->hotkey_save.values[1] = 1050;
|
||||||
|
state_config->hotkey_save.values[2] = 1051;
|
||||||
|
state_config->hotkey_save.values[3] = 1052;
|
||||||
|
state_config->hotkey_save.values[4] = 1053;
|
||||||
|
state_config->hotkey_save.values[5] = 1054;
|
||||||
|
state_config->hotkey_save.values[6] = 1055;
|
||||||
|
state_config->hotkey_save.values[7] = 1056;
|
||||||
|
state_config->hotkey_save.values[8] = 1057;
|
||||||
|
state_config->hotkey_save.values[9] = 1048;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void state_midi_event(SharedContext *context, const StateConfig *state_config,
|
void state_midi_event(SharedContext *context, const StateConfig *state_config,
|
||||||
@@ -443,51 +505,57 @@ void state_midi_event(SharedContext *context, const StateConfig *state_config,
|
|||||||
|
|
||||||
void state_key_event(SharedContext *context, const StateConfig *state_config,
|
void state_key_event(SharedContext *context, const StateConfig *state_config,
|
||||||
unsigned int code, const MidiDevice *midi) {
|
unsigned int code, const MidiDevice *midi) {
|
||||||
if (code == 82) {
|
unsigned int index;
|
||||||
// R: randomize
|
|
||||||
log_info("[R] Randomized");
|
if (code == state_config->hotkey_randomize) {
|
||||||
|
log_info("[%d] Randomized", code);
|
||||||
randomize(context, state_config);
|
randomize(context, state_config);
|
||||||
update_values(context, state_config, midi);
|
update_values(context, state_config, midi);
|
||||||
} else if (code == 1082) {
|
} else if (code == state_config->hotkey_reset) {
|
||||||
log_info("[SHIFT+R] Reset");
|
log_info("[%d] Reset", code);
|
||||||
reset(context);
|
reset(context);
|
||||||
update_values(context, state_config, midi);
|
update_values(context, state_config, midi);
|
||||||
} else if (code == 68) {
|
} else if (code == state_config->hotkey_demo) {
|
||||||
// D: demo on/off
|
log_info((context->demo ? "[%d] Demo OFF" : "[%d] Demo ON"), code);
|
||||||
log_info((context->demo ? "[D] Demo OFF" : "[D] Demo ON"));
|
|
||||||
context->demo = !context->demo;
|
context->demo = !context->demo;
|
||||||
} else if (code == 65) {
|
} else if (code == state_config->hotkey_autorand) {
|
||||||
// A: auto random on/off
|
|
||||||
log_info(
|
log_info(
|
||||||
(context->auto_random ? "[A] Auto Random OFF" : "[A] Auto Random ON"));
|
(context->auto_random ? "[%d] Auto Random OFF" : "[%d] Auto Random ON"),
|
||||||
|
code);
|
||||||
context->auto_random = !context->auto_random;
|
context->auto_random = !context->auto_random;
|
||||||
} else if (code == 263) {
|
} else if (code == state_config->hotkey_autorand_down) {
|
||||||
// LEFT ARROW
|
|
||||||
if (context->auto_random_cycle > 1) {
|
if (context->auto_random_cycle > 1) {
|
||||||
context->auto_random_cycle -= 1;
|
context->auto_random_cycle -= 1;
|
||||||
}
|
}
|
||||||
log_info("[LEFT] Auto Random Cycle: %d", context->auto_random_cycle);
|
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
|
||||||
} else if (code == 262) {
|
} else if (code == state_config->hotkey_autorand_up) {
|
||||||
// RIGHT ARROW
|
|
||||||
context->auto_random_cycle += 1;
|
context->auto_random_cycle += 1;
|
||||||
log_info("[RIGHT] Auto Random Cycle: %d", context->auto_random_cycle);
|
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
|
||||||
} else if (code == 265) {
|
} else if (code == state_config->hotkey_tempo_up) {
|
||||||
// UP ARROW
|
|
||||||
tempo_set(&context->tempo, context->tempo.tempo + 1);
|
tempo_set(&context->tempo, context->tempo.tempo + 1);
|
||||||
log_info("[UP] Tempo: %f", context->tempo);
|
log_info("[%d] Tempo: %f", code, context->tempo);
|
||||||
} else if (code == 264) {
|
} else if (code == state_config->hotkey_tempo_down) {
|
||||||
// DOWN ARROW
|
|
||||||
if (context->tempo.tempo > 0) {
|
if (context->tempo.tempo > 0) {
|
||||||
tempo_set(&context->tempo, context->tempo.tempo - 1);
|
tempo_set(&context->tempo, context->tempo.tempo - 1);
|
||||||
}
|
}
|
||||||
log_info("[DOWN] Tempo: %f", context->tempo);
|
log_info("[%d] Tempo: %f", code, context->tempo);
|
||||||
} else if (code >= 48 && code <= 57) {
|
|
||||||
log_info("[%d] Loading state %d", code - 48, code - 48);
|
|
||||||
load_from_index_file(context, state_config, code - 48);
|
|
||||||
} else if (code >= 1048 && code <= 1057) {
|
|
||||||
log_info("[%d] Saving state %d", code - 1048, code - 1048);
|
|
||||||
save_to_index_file(context, state_config, code - 1048);
|
|
||||||
} else {
|
} else {
|
||||||
|
index = arr_uint_index_of(state_config->hotkey_load, code);
|
||||||
|
|
||||||
|
if (index != ARRAY_NOT_FOUND) {
|
||||||
|
log_info("[%d] Loading state %d", code, index + 1);
|
||||||
|
load_from_index_file(context, state_config, index + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = arr_uint_index_of(state_config->hotkey_save, code);
|
||||||
|
|
||||||
|
if (index != ARRAY_NOT_FOUND) {
|
||||||
|
log_info("[%d] Saving state %d", code, index + 1);
|
||||||
|
save_to_index_file(context, state_config, index + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log_info("[%d] No hotkey defined", code);
|
log_info("[%d] No hotkey defined", code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -550,8 +618,7 @@ bool state_background_write(SharedContext *context,
|
|||||||
void state_init(SharedContext *context, const StateConfig *state_config,
|
void state_init(SharedContext *context, const StateConfig *state_config,
|
||||||
bool demo, bool auto_random, unsigned int auto_random_cycles,
|
bool demo, bool auto_random, unsigned int auto_random_cycles,
|
||||||
unsigned int base_tempo, bool load_state) {
|
unsigned int base_tempo, bool load_state) {
|
||||||
tempo_init(&context->tempo);
|
tempo_init(&context->tempo, base_tempo);
|
||||||
tempo_set(&context->tempo, base_tempo);
|
|
||||||
context->demo = demo;
|
context->demo = demo;
|
||||||
context->auto_random = auto_random;
|
context->auto_random = auto_random;
|
||||||
context->auto_random_cycle = auto_random_cycles;
|
context->auto_random_cycle = auto_random_cycles;
|
||||||
|
|||||||
+4
-1
@@ -25,12 +25,15 @@ static void reset_tap_chain(Tempo *tempo, long t) {
|
|||||||
memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations));
|
memset(tempo->tap_durations, 0, sizeof(tempo->tap_durations));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tempo_init(Tempo *tempo) {
|
void tempo_init(Tempo *tempo, float value) {
|
||||||
long t;
|
long t;
|
||||||
|
|
||||||
t = now();
|
t = now();
|
||||||
|
|
||||||
reset_tap_chain(tempo, t);
|
reset_tap_chain(tempo, t);
|
||||||
|
|
||||||
|
tempo->tempo = value;
|
||||||
|
tempo->beat_length = 60000.0 / value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_chain_active(const Tempo tempo, long t) {
|
static bool is_chain_active(const Tempo tempo, long t) {
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
#ifndef TEMPO_H
|
#ifndef TEMPO_H
|
||||||
#define TEMPO_H
|
#define TEMPO_H
|
||||||
|
|
||||||
void tempo_init(Tempo *tempo);
|
void tempo_init(Tempo *tempo, float value);
|
||||||
|
|
||||||
void tempo_tap(Tempo *tempo);
|
void tempo_tap(Tempo *tempo);
|
||||||
|
|
||||||
|
|||||||
+12
@@ -214,6 +214,18 @@ typedef struct StateConfig {
|
|||||||
unsigned int tap_tempo_code;
|
unsigned int tap_tempo_code;
|
||||||
|
|
||||||
char save_file_prefix[STR_LEN];
|
char save_file_prefix[STR_LEN];
|
||||||
|
|
||||||
|
unsigned int hotkey_randomize;
|
||||||
|
unsigned int hotkey_reset;
|
||||||
|
unsigned int hotkey_demo;
|
||||||
|
unsigned int hotkey_autorand;
|
||||||
|
unsigned int hotkey_autorand_up;
|
||||||
|
unsigned int hotkey_autorand_down;
|
||||||
|
unsigned int hotkey_tempo_up;
|
||||||
|
unsigned int hotkey_tempo_down;
|
||||||
|
|
||||||
|
UintArray hotkey_load;
|
||||||
|
UintArray hotkey_save;
|
||||||
} StateConfig;
|
} StateConfig;
|
||||||
|
|
||||||
// timer.c
|
// timer.c
|
||||||
|
|||||||
Reference in New Issue
Block a user