diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index dc7f9c0..83c740c 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -117,11 +117,15 @@ make -f Makefile.dev release-arch - [x] Printable PDF of default scr/fx - [x] Add NanoKontrol setup file - [x] Find and fix opengl errors 0500 ? -- [ ] Improvements - - [ ] Record show as text files - - [ ] Play from record text file +- [ ] Extra features + - [ ] `--auto-random-cycle=4` + - [ ] Arrows (up-down: bpm / left-right: cycle) + - [ ] Save states (numkey: load / shift + numkey: save) + - [ ] Configurable key codes - [ ] Key codes as inputs - [ ] Mouse position and scroll as inputs + - [ ] Record show as text files + - [ ] Play from record text file - [ ] Fixes - [ ] Try to write NanoKontrol config - [ ] Investigate video device fps loss (bad unregister ?) diff --git a/README.md b/README.md index 0ed2496..392c4a3 100644 --- a/README.md +++ b/README.md @@ -166,34 +166,35 @@ When running, the following hotkeys are available: ### CLI arguments ```txt -usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-v=FILE] [-vs=SIZE] [-is=SIZE] [-sf=STATE_PATH] [-ls / -nls] [-ss / -nss] [-tm] [-tf] +usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-v=FILE] [-vs=SIZE] [-is=SIZE] [-sf=STATE_PATH] [-ls / -nls] [-ss / -nss] [-tm] [-tf] Fusion Of Real-time Generative Effects. options: - -h, --help show this help message and exit - -v, --version print version - -p, --project forge project directory (default: /usr/share/forge/default) - -c, --config config file name (default: forge_project.cfg) - -hr, --hot-reload hot reload of shaders scripts - -s, --screen output screen number (default: primary) - -m, --monitor monitor screen number (default: none) - -mo, --monitor-only no output screen - -w, --windowed not fullscreen - -t, --tempo base tempo (default: 60) - -d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random) - -ar, --auto-random randomize state every 4 beats - -nar, --no-auto-random do not randomize state (default) - -v, --video-in path to video capture device (multiple allowed) - -vs, --video-size video capture desired height (default: internal texture height) - -is, --internal-size internal texture height (default: 720) - -sf, --state-file saved state file (default: forge_saved_state.txt) - -ls, --load-state load saved state (default) - -nls, --no-load-state do not load saved state - -ss, --save-state save state (default) - -nss, --no-save-state do not save state - -tm, --trace-midi print midi code and values - -tf, --trace-fps print fps status of subsystems + -h, --help show this help message and exit + -v, --version print version + -p, --project forge project directory (default: /usr/share/forge/default) + -c, --config config file name (default: forge_project.cfg) + -hr, --hot-reload hot reload of shaders scripts + -s, --screen output screen number (default: primary) + -m, --monitor monitor screen number (default: none) + -mo, --monitor-only no output screen + -w, --windowed not fullscreen + -t, --tempo base tempo (default: 60) + -d, --demo demonstration mode (assume --no-save-state, --no-load-state, --auto-random) + -ar, --auto-random randomize state every cycle (4 beats) + -nar, --no-auto-random do not randomize state (default) + -arc, --auto-random-cycle auto random cycle length (default: 4) + -v, --video-in path to video capture device (multiple allowed) + -vs, --video-size video capture desired height (default: internal texture height) + -is, --internal-size internal texture height (default: 720) + -sf, --state-file saved state file (default: forge_saved_state.txt) + -ls, --load-state load saved state (default) + -nls, --no-load-state do not load saved state + -ss, --save-state save state (default) + -nss, --no-save-state do not save state + -tm, --trace-midi print midi code and values + -tf, --trace-fps print fps status of subsystems ``` ## Default Project diff --git a/src/args.c b/src/args.c index b42d3b2..bc29408 100644 --- a/src/args.c +++ b/src/args.c @@ -13,61 +13,64 @@ #include "string.h" static void print_help(int status_code) { - puts(PACKAGE - " " VERSION "\n\n" - "usage: " PACKAGE " " - "[-h] " - "[-v] " - "[-p=PROJECT_PATH] " - "[-c=CFG_FILE] " - "[-hr] " - "[-s=SCREEN] " - "[-m=SCREEN] " - "[-mo] " - "[-w] " - "[-t=TEMPO] " - "[-d] " - "[-ar / -nar] " - "[-v=FILE] " - "[-vs=SIZE] " - "[-is=SIZE] " - "[-sf=STATE_PATH] " - "[-ls / -nls] " - "[-ss / -nss] " - "[-tm] " - "[-tf] " - "\n\n" - "Fusion Of Real-time Generative Effects.\n\n" - "options:\n" - " -h, --help show this help message and exit\n" - " -v, --version print version\n" - " -p, --project forge project directory (default: " DATADIR - "/default)\n" - " -c, --config config file name (default: " - "forge_project.cfg)\n" - " -hr, --hot-reload hot reload of shaders scripts\n" - " -s, --screen output screen number (default: primary)\n" - " -m, --monitor monitor screen number (default: none)\n" - " -mo, --monitor-only no output screen\n" - " -w, --windowed not fullscreen\n" - " -t, --tempo base tempo (default: 60)\n" - " -d, --demo demonstration mode (assume " - "--no-save-state, --no-load-state, --auto-random)\n" - " -ar, --auto-random randomize state every 4 beats\n" - " -nar, --no-auto-random do not randomize state (default)\n" - " -v, --video-in path to video capture device (multiple " - "allowed)\n" - " -vs, --video-size video capture desired height (default: " - "internal texture height)\n" - " -is, --internal-size internal texture height (default: 720)\n" - " -sf, --state-file saved state file (default: " - "forge_saved_state.txt)\n" - " -ls, --load-state load saved state (default)\n" - " -nls, --no-load-state do not load saved state\n" - " -ss, --save-state save state (default)\n" - " -nss, --no-save-state do not save state\n" - " -tm, --trace-midi print midi code and values\n" - " -tf, --trace-fps print fps status of subsystems\n"); + puts( + PACKAGE + " " VERSION "\n\n" + "usage: " PACKAGE " " + "[-h] " + "[-v] " + "[-p=PROJECT_PATH] " + "[-c=CFG_FILE] " + "[-hr] " + "[-s=SCREEN] " + "[-m=SCREEN] " + "[-mo] " + "[-w] " + "[-t=TEMPO] " + "[-d] " + "[-ar / -nar] " + "[-arc=CYCLES] " + "[-v=FILE] " + "[-vs=SIZE] " + "[-is=SIZE] " + "[-sf=STATE_PATH] " + "[-ls / -nls] " + "[-ss / -nss] " + "[-tm] " + "[-tf] " + "\n\n" + "Fusion Of Real-time Generative Effects.\n\n" + "options:\n" + " -h, --help show this help message and exit\n" + " -v, --version print version\n" + " -p, --project forge project directory (default: " DATADIR + "/default)\n" + " -c, --config config file name (default: " + "forge_project.cfg)\n" + " -hr, --hot-reload hot reload of shaders scripts\n" + " -s, --screen output screen number (default: primary)\n" + " -m, --monitor monitor screen number (default: none)\n" + " -mo, --monitor-only no output screen\n" + " -w, --windowed not fullscreen\n" + " -t, --tempo base tempo (default: 60)\n" + " -d, --demo demonstration mode (assume " + "--no-save-state, --no-load-state, --auto-random)\n" + " -ar, --auto-random randomize state every cycle (4 beats)\n" + " -nar, --no-auto-random do not randomize state (default)\n" + " -arc, --auto-random-cycle auto random cycle length (default: 4)\n" + " -v, --video-in path to video capture device (multiple " + "allowed)\n" + " -vs, --video-size video capture desired height (default: " + "internal texture height)\n" + " -is, --internal-size internal texture height (default: 720)\n" + " -sf, --state-file saved state file (default: " + "forge_saved_state.txt)\n" + " -ls, --load-state load saved state (default)\n" + " -nls, --no-load-state do not load saved state\n" + " -ss, --save-state save state (default)\n" + " -nss, --no-save-state do not save state\n" + " -tm, --trace-midi print midi code and values\n" + " -tf, --trace-fps print fps status of subsystems\n"); exit(status_code); } @@ -124,6 +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->video_in.length = 0; params->video_size = 0; params->internal_size = 720; @@ -168,6 +172,11 @@ void args_parse(Parameters *params, int argc, char **argv) { params->auto_random = true; } 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) { + invalid_value(arg, value); + } } else if (is_arg(arg, "-v") || is_arg(arg, "--video-in")) { if (params->video_in.length == MAX_VIDEO) { log_error("maximum video input reached"); diff --git a/src/forge.c b/src/forge.c index 22e61f0..a00cda3 100644 --- a/src/forge.c +++ b/src/forge.c @@ -59,7 +59,8 @@ 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->base_tempo, params->state_file, params->load_state); + params->auto_random_cycles, params->base_tempo, params->state_file, + params->load_state); context->monitor = params->monitor; diff --git a/src/state.c b/src/state.c index 95abdcb..8ac4e14 100644 --- a/src/state.c +++ b/src/state.c @@ -314,7 +314,7 @@ bool state_background_write(SharedContext *context, last_change = false; while (!context->stop) { - beat_active = tempo_progress(&context->tempo, 1.0) < 0.25; + beat_active = tempo_progress(&context->tempo, 1.0) < 0.5; if (!midi->error && beat_active != last_active) { safe_midi_write(midi, state_config->tap_tempo_code, @@ -327,7 +327,8 @@ bool state_background_write(SharedContext *context, last_active = beat_active; - change = tempo_progress(&context->tempo, 4.0) < 0.25; + change = tempo_progress(&context->tempo, + (double)context->auto_random_cycles) < 0.5; if (context->auto_random && change && !last_change) { state_randomize(context, state_config); @@ -383,12 +384,14 @@ static void state_load(SharedContext *context, const StateConfig *state_config, } void state_init(SharedContext *context, const StateConfig *state_config, - bool demo, bool auto_random, unsigned int base_tempo, - const char *state_file, bool load_state) { + bool demo, bool auto_random, unsigned int auto_random_cycles, + unsigned int base_tempo, const char *state_file, + bool load_state) { tempo_init(&context->tempo); tempo_set(&context->tempo, base_tempo); context->demo = demo; context->auto_random = auto_random; + context->auto_random_cycles = 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/state.h b/src/state.h index fe0da1a..b726332 100644 --- a/src/state.h +++ b/src/state.h @@ -14,8 +14,9 @@ bool state_background_write(SharedContext *context, const MidiDevice *midi); void state_init(SharedContext *context, const StateConfig *state_config, - bool demo, bool auto_random, unsigned int base_tempo, - const char *state_file, bool load_state); + bool demo, bool auto_random, unsigned int auto_random_cycles, + unsigned int base_tempo, const char *state_file, + bool load_state); void state_reset(SharedContext *context); diff --git a/src/types.h b/src/types.h index 46ac92f..ab5730e 100644 --- a/src/types.h +++ b/src/types.h @@ -43,6 +43,7 @@ typedef struct Parameters { float base_tempo; bool demo; bool auto_random; + unsigned int auto_random_cycles; StringArray video_in; unsigned int video_size; unsigned int internal_size; @@ -182,6 +183,7 @@ typedef struct SharedContext { vec3 values[ARRAY_SIZE]; bool demo; bool auto_random; + unsigned int auto_random_cycles; unsigned int seeds[MAX_FRAG]; bool monitor;