diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index f035203..23d2a97 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -119,7 +119,7 @@ make -f Makefile.dev release-arch - [x] Find and fix opengl errors 0500 ? - [ ] Extra features - [x] `--auto-random-cycle=4` - - [ ] Arrows (up-down: bpm / left-right: cycle) + - [x] Arrows (up-down: bpm / left-right: cycle) - [ ] Save states (numkey: load / shift + numkey: save) - [ ] Configurable key codes - [ ] Key codes as inputs diff --git a/README.md b/README.md index 392c4a3..b5806ce 100644 --- a/README.md +++ b/README.md @@ -157,11 +157,15 @@ make install When running, the following hotkeys are available: -* Esc: Exit window -* R: Randomize internal values -* 0: Reset internal values to 0 -* D: Demo mode On/Off -* A: Auto Random mode On/Off +| Hotkey | Function | +| ------ | -------- | +| Esc | Exit FORGE | +| R | Randomize internal values | +| Shift + R | Reset internal values to 0 | +| D | Demo mode On/Off | +| A | Auto Random mode On/Off | +| / | Auto Random Cycle -/+ 1 | +| / | BPM +/- 1 | ### CLI arguments diff --git a/default/forge_project.cfg b/default/forge_project.cfg index 430fd97..c807a5f 100644 --- a/default/forge_project.cfg +++ b/default/forge_project.cfg @@ -37,6 +37,8 @@ UNIFORM_IN_FPS_PREFIX=iInputFPS UNIFORM_DEMO=iDemo # 0/1 if auto random UNIFORM_AUTORAND=iAutoRand +# auto random cycle length +UNIFORM_AUTORANDCYCLE=iAutoRandCycle # Current page UNIFORM_PAGE=iPage # Current selected shader diff --git a/default/inc_cp437.glsl b/default/inc_cp437.glsl index 1f2d2a3..a0b13bf 100644 --- a/default/inc_cp437.glsl +++ b/default/inc_cp437.glsl @@ -372,6 +372,20 @@ float write_int(vec2 uv, vec2 pos, uint value, uint magnitude) return d; } +float write_int_left(vec2 uv, vec2 pos, uint value, uint magnitude) +{ + int i; + uint m = 1; + float d = 0; + for (i = 0; i < magnitude; i++) { + if (i == 0 || value >= m) { + pos.x += 1; + m *= 10u; + } + } + return write_int(uv, pos, value, magnitude); +} + int read(sampler2D tex, vec2 uv, float k, int d, float t) { float inv_k = 1 / k; diff --git a/default/inc_debug.glsl b/default/inc_debug.glsl index a761932..4ebec7f 100644 --- a/default/inc_debug.glsl +++ b/default/inc_debug.glsl @@ -15,6 +15,7 @@ uniform int iInputFormat2; uniform int iDemo; uniform int iAutoRand; +uniform int iAutoRandCycle; uniform int iPage; uniform int iSelected; @@ -225,22 +226,22 @@ vec4 debug(vec2 vUV) float x = 0; x = -15; - f += write_5(uv3, vec2(x,13), texts[0]); - f += write_int(uv3, vec2(x - 3.5,13), iFPS, 3); + f += write_5(uv3, vec2(x - 4,13), texts[0]); + f += write_int(uv3, vec2(x + 1, 13), iFPS, 3); v = min(1, iFPS/60.0); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); x = 0; - f += write_5(uv3, vec2(x,13), texts[1]); - f += write_int(uv3, vec2(x - 3.5,13), int(iTempo), 3); + f += write_5(uv3, vec2(x - 4,13), texts[1]); + f += write_int(uv3, vec2(x + 1,13), int(iTempo), 3); v = fract(iBeats); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); x = 15; - f += write_5(uv3, vec2(x,13), texts[2]); - f += write_int(uv3, vec2(x - 5.5,13), int(iTime), 5); + f += write_5(uv3, vec2(x - 4,13), texts[2]); + f += write_int(uv3, vec2(x - 1,13), int(iTime), 5); v = fract(iTime); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); @@ -248,6 +249,7 @@ vec4 debug(vec2 vUV) if (iAutoRand > 0) { f += write_5(uv3, vec2(-4,-15), iDemo > 0 ? texts[3] : texts[4]); f += write_5(uv3, vec2(0,-15), texts[5]); + f += write_int_left(uv3, vec2(3, -15), iAutoRandCycle, 3); } else { f += write_5(uv3, vec2(-2,-15), iDemo > 0 ? texts[3] : texts[4]); } diff --git a/sample/forge_project.cfg b/sample/forge_project.cfg index e47fca2..e3af011 100644 --- a/sample/forge_project.cfg +++ b/sample/forge_project.cfg @@ -33,8 +33,6 @@ UNIFORM_BEATS=iBeats UNIFORM_FPS=iFPS # 0/1 if demo UNIFORM_DEMO=iDemo -# 0/1 if auto random -UNIFORM_AUTORAND=iAutoRand # Seed for shader X UNIFORM_SEED_PREFIX=iSeed diff --git a/sample/frag1.glsl b/sample/frag1.glsl index a0ab544..5faa9cc 100644 --- a/sample/frag1.glsl +++ b/sample/frag1.glsl @@ -10,7 +10,6 @@ uniform float iTempo; // current tempo in bpm uniform float iBeats; // elapsed beats since last tempo reset uniform int iFPS; // output window frames per seconds uniform int iDemo; // 0/1 if demo mode -uniform int iAutoRand; // 0/1 if auto random mode uniform int iSeed1; // a random seed assigned at start uniform vec2 iResolution; // output window resolution in pixels uniform vec3 iMidi1_1[20]; // all midi inputs defined diff --git a/src/args.c b/src/args.c index bc29408..e45625e 100644 --- a/src/args.c +++ b/src/args.c @@ -127,7 +127,7 @@ void args_parse(Parameters *params, int argc, char **argv) { params->base_tempo = 60.0f; params->demo = false; params->auto_random = false; - params->auto_random_cycles = 4; + params->auto_random_cycle = 4; params->video_in.length = 0; params->video_size = 0; params->internal_size = 720; @@ -173,8 +173,8 @@ void args_parse(Parameters *params, int argc, char **argv) { } else if (is_arg(arg, "-nar") || is_arg(arg, "--no-auto-random")) { params->auto_random = false; } else if (is_arg(arg, "-arc") || is_arg(arg, "--auto-random-cycle")) { - params->auto_random_cycles = parse_uint(arg, value); - if (params->auto_random_cycles == 0) { + params->auto_random_cycle = parse_uint(arg, value); + if (params->auto_random_cycle == 0) { invalid_value(arg, value); } } else if (is_arg(arg, "-v") || is_arg(arg, "--video-in")) { diff --git a/src/forge.c b/src/forge.c index 6807d91..b572206 100644 --- a/src/forge.c +++ b/src/forge.c @@ -59,7 +59,7 @@ static void compute_fps(bool trace_fps) { static void init_context(const Parameters *params, unsigned int in_count) { state_init(context, &project.state_config, params->demo, params->auto_random, - params->auto_random_cycles, params->base_tempo, params->state_file, + params->auto_random_cycle, params->base_tempo, params->state_file, params->load_state); context->monitor = params->monitor; diff --git a/src/shaders.c b/src/shaders.c index faffcb1..ddf54d1 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -280,6 +280,9 @@ static void init_single_program(ShaderProgram *program, unsigned int i, program->iautorand_locations[i] = glGetUniformLocation( program->programs[i], config_file_get_str(config, "UNIFORM_AUTORAND", "iAutoRand")); + program->iautorandcycle_locations[i] = glGetUniformLocation( + program->programs[i], + config_file_get_str(config, "UNIFORM_AUTORANDCYCLE", "iAutoRandCycle")); program->ipage_locations[i] = glGetUniformLocation( program->programs[i], config_file_get_str(config, "UNIFORM_PAGE", "iPage")); @@ -545,6 +548,8 @@ static void use_program(const ShaderProgram *program, int i, bool output, write_uniform_1i(program->idemo_locations[i], context->demo ? 1 : 0); write_uniform_1i(program->iautorand_locations[i], context->auto_random ? 1 : 0); + write_uniform_1i(program->iautorandcycle_locations[i], + context->auto_random_cycle); write_uniform_1i(program->ipage_locations[i], context->page); write_uniform_1i(program->iselected_locations[i], context->selected + 1); write_uniform_2f(program->ires_locations[i], &context->resolution); diff --git a/src/state.c b/src/state.c index 42d02ba..bea117c 100644 --- a/src/state.c +++ b/src/state.c @@ -301,6 +301,26 @@ void state_key_event(SharedContext *context, const StateConfig *state_config, log_info( (context->auto_random ? "[A] Auto Random OFF" : "[A] Auto Random ON")); context->auto_random = !context->auto_random; + } else if (code == 263) { + // LEFT ARROW + if (context->auto_random_cycle > 1) { + context->auto_random_cycle -= 1; + } + log_info("[LEFT] Auto Random Cycle: %d", context->auto_random_cycle); + } else if (code == 262) { + // RIGHT ARROW + context->auto_random_cycle += 1; + log_info("[RIGHT] Auto Random Cycle: %d", context->auto_random_cycle); + } else if (code == 265) { + // UP ARROW + tempo_set(&context->tempo, context->tempo.tempo + 1); + log_info("[UP] Tempo: %f", context->tempo); + } else if (code == 264) { + // DOWN ARROW + if (context->tempo.tempo > 0) { + tempo_set(&context->tempo, context->tempo.tempo - 1); + } + log_info("[DOWN] Tempo: %f", context->tempo); } else { log_info("[%d] No hotkey defined", code); } @@ -353,7 +373,7 @@ bool state_background_write(SharedContext *context, last_active = beat_active; change = tempo_progress(&context->tempo, - (double)context->auto_random_cycles) < 0.5; + (double)context->auto_random_cycle) < 0.5; if (context->auto_random && change && !last_change) { state_randomize(context, state_config); @@ -416,7 +436,7 @@ void state_init(SharedContext *context, const StateConfig *state_config, tempo_set(&context->tempo, base_tempo); context->demo = demo; context->auto_random = auto_random; - context->auto_random_cycles = auto_random_cycles; + context->auto_random_cycle = auto_random_cycles; context->state.length = state_config->select_frag_codes.length; memset(context->state.values, 0, sizeof(context->state.values)); diff --git a/src/tempo.c b/src/tempo.c index c7418e0..fb15833 100644 --- a/src/tempo.c +++ b/src/tempo.c @@ -99,8 +99,17 @@ static void add_tap_to_chain(Tempo *tempo, long t) { } void tempo_set(Tempo *tempo, float value) { + long t; + long progress; + + t = now(); + + progress = (t - tempo->last_reset) % tempo->beat_length; + tempo->tempo = value; tempo->beat_length = 60000.0 / value; + + reset_tap_chain(tempo, t - progress); } void tempo_tap(Tempo *tempo) { diff --git a/src/types.h b/src/types.h index ab5730e..7867e26 100644 --- a/src/types.h +++ b/src/types.h @@ -43,7 +43,7 @@ typedef struct Parameters { float base_tempo; bool demo; bool auto_random; - unsigned int auto_random_cycles; + unsigned int auto_random_cycle; StringArray video_in; unsigned int video_size; unsigned int internal_size; @@ -105,6 +105,7 @@ typedef struct ShaderProgram { GLuint iinfps_locations[ARRAY_SIZE]; GLuint idemo_locations[ARRAY_SIZE]; GLuint iautorand_locations[ARRAY_SIZE]; + GLuint iautorandcycle_locations[ARRAY_SIZE]; GLuint iseed_locations[ARRAY_SIZE]; GLuint istate_locations[ARRAY_SIZE]; GLuint ipage_locations[ARRAY_SIZE]; @@ -183,7 +184,7 @@ typedef struct SharedContext { vec3 values[ARRAY_SIZE]; bool demo; bool auto_random; - unsigned int auto_random_cycles; + unsigned int auto_random_cycle; unsigned int seeds[MAX_FRAG]; bool monitor;