diff --git a/.gitignore b/.gitignore index 0a62d5c..5b999ca 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ pkg forge-* confdeps.* conftest.* -state.txt \ No newline at end of file +forge_saved_state.txt \ No newline at end of file diff --git a/README.md b/README.md index 825fd3c..f5a4881 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ make install ## CLI arguments ```txt -usage: forge [-h] [-v] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-f=DIR_PATH] [-c=CFG_PATH] [-is=SIZE] [-v=FILE] [-vs=SIZE] [-t=TEMPO] [--demo] [-w] +usage: forge [-h] [-v] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-f=DIR_PATH] [-c=CFG_PATH] [-sf=STATE_PATH] [-ls / -nls] [-ss / -nss] [-is=SIZE] [-v=FILE] [-vs=SIZE] [-t=TEMPO] [--demo] [-w] Fusion Of Real-time Generative Effects. @@ -67,11 +67,16 @@ options: -mo, --monitor-only no output screen -f, --frag fragment shaders directory (default: /usr/share/forge/shaders) -c, --config fragment shaders config file (default: /usr/share/forge/default.cfg) + -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 -is, --internal-size internal texture height (default: 720) -v, --video-in path to video capture device (multiple allowed) -vs, --video-size video capture desired height (default: internal texture height) -t, --tempo base tempo (default: 60) - --demo demonstration mode + --demo demonstration mode (assume --no-save-state and --no-load-state) -w, --windowed not fullscreen ``` @@ -126,7 +131,7 @@ make -f Makefile.dev release-arch - [x] Write Midi events - [x] Send midi data to shaders - [x] Save midi state - - [ ] Load midi state from last save + - [x] Load midi state from last save - [x] State machine with A/B switch - [x] Tap-tempo feature - [ ] Clean code and fix things diff --git a/src/args.c b/src/args.c index 739d364..be35697 100644 --- a/src/args.c +++ b/src/args.c @@ -23,7 +23,8 @@ static void print_help(int status_code) { "[-f=DIR_PATH] " "[-c=CFG_PATH] " "[-sf=STATE_PATH] " - "[-es] " + "[-ls / -nls] " + "[-ss / -nss] " "[-is=SIZE] " "[-v=FILE] " "[-vs=SIZE] " @@ -41,17 +42,22 @@ static void print_help(int status_code) { " -mo, --monitor-only no output screen\n" " -f, --frag fragment shaders directory " "(default: " DATADIR "/shaders)\n" - " -sf, --state-file state save file (default: state.txt)\n" - " -es, --empty-state do not load state save file\n" " -c, --config fragment shaders config file " "(default: " DATADIR "/default.cfg)\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" " -is, --internal-size internal texture height (default: 720)\n" " -v, --video-in path to video capture device (multiple " "allowed)\n" " -vs, --video-size video capture desired height (default: " "internal texture height)\n" " -t, --tempo base tempo (default: 60)\n" - " --demo demonstration mode\n" + " --demo demonstration mode (assume --no-save-state " + "and --no-load-state)\n" " -w, --windowed not fullscreen\n"); exit(status_code); } @@ -97,8 +103,9 @@ Parameters args_parse(int argc, char **argv) { params.monitor_screen = 0; params.frag_path = DATADIR "/shaders"; params.config_path = DATADIR "/default.cfg"; - params.state_file = "state.txt"; - params.empty_state = false; + params.state_file = "forge_saved_state.txt"; + params.load_state = true; + params.save_state = false; params.internal_size = 720; params.video_size = 0; params.base_tempo = 60.0f; @@ -124,8 +131,14 @@ Parameters args_parse(int argc, char **argv) { params.config_path = value; } else if (is_arg(arg, "-sf") || is_arg(arg, "--state-file")) { params.state_file = value; - } else if (is_arg(arg, "-es") || is_arg(arg, "--empty-state")) { - params.empty_state = true; + } else if (is_arg(arg, "-ls") || is_arg(arg, "--load-state")) { + params.load_state = true; + } else if (is_arg(arg, "-nls") || is_arg(arg, "--no-load-state")) { + params.load_state = false; + } else if (is_arg(arg, "-ss") || is_arg(arg, "--save-state")) { + params.save_state = true; + } else if (is_arg(arg, "-nss") || is_arg(arg, "--no-save-state")) { + params.save_state = false; } else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) { params.internal_size = parse_uint(arg, value); if (params.internal_size == 0) { @@ -153,6 +166,8 @@ Parameters args_parse(int argc, char **argv) { params.monitor = true; } else if (is_arg(arg, "--demo")) { params.demo = true; + params.load_state = false; + params.save_state = false; } else if (is_arg(arg, "-w") || is_arg(arg, "--windowed")) { params.windowed = true; } else { diff --git a/src/config_file.c b/src/config_file.c index eb1ba9b..98f10aa 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -103,7 +103,7 @@ char *config_file_get_str(ConfigFile config, char *key, char *default_value) { } unsigned int config_file_get_int(ConfigFile config, char *key, - int default_value) { + unsigned int default_value) { ConfigFileItem c_key; ConfigFileItem *item; diff --git a/src/config_file.h b/src/config_file.h index 52a99b2..6f69d13 100644 --- a/src/config_file.h +++ b/src/config_file.h @@ -8,7 +8,7 @@ ConfigFile config_file_read(char *path, bool free_path); char *config_file_get_str(ConfigFile config, char *key, char *default_value); unsigned int config_file_get_int(ConfigFile config, char *key, - int default_value); + unsigned int default_value); void config_file_free(ConfigFile config); diff --git a/src/forge.c b/src/forge.c index b09bdbb..6c84ead 100644 --- a/src/forge.c +++ b/src/forge.c @@ -59,7 +59,7 @@ static void init_context(Parameters params, unsigned int in_count) { unsigned int i; state_init(context, state_config, params.demo, params.base_tempo, - params.state_file, params.empty_state); + params.state_file, params.load_state); context->monitor = params.monitor; @@ -315,7 +315,9 @@ void forge_run(Parameters params) { context->stop = true; - state_save(context, state_config, params.state_file); + if (params.save_state) { + state_save(context, state_config, params.state_file); + } shaders_free(program); diff --git a/src/state.c b/src/state.c index a427f1c..35abf99 100644 --- a/src/state.c +++ b/src/state.c @@ -321,21 +321,47 @@ bool state_background_midi_write(SharedContext *context, void state_load(SharedContext *context, StateConfig state_config, char *state_file) { - File saved_state; + ConfigFile saved_state; + char key[100]; + unsigned int i; - saved_state = file_read(state_file); + saved_state = config_file_read(state_file, false); - if (saved_state.error) { - return; + tempo_set(&context->tempo, + config_file_get_int(saved_state, "tempo", context->tempo.tempo)); + context->page = config_file_get_int(saved_state, "page", 0); + context->selected = config_file_get_int(saved_state, "selected", 0); + + for (i = 0; i < context->state.length; i++) { + sprintf(key, "seed_%d", i); + context->seeds[i] = + config_file_get_int(saved_state, key, context->seeds[i]); + sprintf(key, "state_%d", i); + context->state.values[i] = config_file_get_int(saved_state, key, 0); } - // TODO load state + for (i = 0; i < state_config.midi_active_counts.length; i++) { + sprintf(key, "active_%d", i); + context->active[i] = config_file_get_int(saved_state, key, 0); + } - file_free(&saved_state, false); + for (i = 0; i < state_config.midi_codes.length; i++) { + sprintf(key, "value_%d_x", i); + context->values[i][0] = + (float)config_file_get_int(saved_state, key, 0) / MIDI_MAX; + sprintf(key, "value_%d_y", i); + context->values[i][1] = + (float)config_file_get_int(saved_state, key, 0) / MIDI_MAX; + sprintf(key, "value_%d_z", i); + context->values[i][2] = + (float)config_file_get_int(saved_state, key, 0) / MIDI_MAX; + } + + config_file_free(saved_state); } void state_init(SharedContext *context, StateConfig state_config, bool demo, - unsigned int base_tempo, char *state_file, bool empty_state) { + unsigned int base_tempo, char *state_file, bool load_state) { unsigned int i; context->tempo = tempo_init(); @@ -361,7 +387,7 @@ void state_init(SharedContext *context, StateConfig state_config, bool demo, context->seeds[i] = rand_uint(1000); } - if (!empty_state) { + if (load_state) { state_load(context, state_config, state_file); } } diff --git a/src/state.h b/src/state.h index 9b6155a..426c57e 100644 --- a/src/state.h +++ b/src/state.h @@ -13,7 +13,7 @@ bool state_background_midi_write(SharedContext *context, StateConfig state_config, MidiDevice midi); void state_init(SharedContext *context, StateConfig state_config, bool demo, - unsigned int base_tempo, char *state_file, bool empty_state); + unsigned int base_tempo, char *state_file, bool load_state); void state_randomize(SharedContext *context, StateConfig state_config); diff --git a/src/types.h b/src/types.h index 095eda3..242c05d 100644 --- a/src/types.h +++ b/src/types.h @@ -39,7 +39,8 @@ typedef struct Parameters { char *frag_path; char *config_path; char *state_file; - bool empty_state; + bool load_state; + bool save_state; unsigned int internal_size; unsigned int video_size; float base_tempo;