diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/modules/Makefile.am | 2 | ||||
-rw-r--r-- | src/modules/mixer/Makefile.am | 3 | ||||
-rw-r--r-- | src/modules/mixer/mixer.c | 302 | ||||
-rw-r--r-- | src/til.c | 2 |
5 files changed, 309 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index f8d717d..b5f4e62 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,7 @@ SUBDIRS = libs modules noinst_LTLIBRARIES = libtil.la libtil_la_SOURCES = til.c til.h til_args.c til_args.h til_fb.c til_fb.h til_jenkins.c til_jenkins.h til_limits.h til_module_context.c til_module_context.h til_settings.h til_settings.c til_setup.c til_setup.h til_stream.c til_stream.h til_tap.h til_threads.c til_threads.h til_util.c til_util.h libtil_la_CPPFLAGS = -I@top_srcdir@/src -libtil_la_LIBADD = modules/blinds/libblinds.la modules/checkers/libcheckers.la modules/compose/libcompose.la modules/drizzle/libdrizzle.la modules/flui2d/libflui2d.la modules/julia/libjulia.la modules/meta2d/libmeta2d.la modules/moire/libmoire.la modules/montage/libmontage.la modules/pixbounce/libpixbounce.la modules/plasma/libplasma.la modules/plato/libplato.la modules/ray/libray.la modules/rkt/librkt.la modules/roto/libroto.la modules/rtv/librtv.la modules/shapes/libshapes.la modules/snow/libsnow.la modules/sparkler/libsparkler.la modules/spiro/libspiro.la modules/stars/libstars.la modules/strobe/libstrobe.la modules/submit/libsubmit.la modules/swab/libswab.la modules/swarm/libswarm.la modules/voronoi/libvoronoi.la libs/grid/libgrid.la libs/puddle/libpuddle.la libs/ray/libray.la libs/rocket/librocket.la libs/sig/libsig.la libs/txt/libtxt.la libs/ascii/libascii.la libs/din/libdin.la +libtil_la_LIBADD = modules/blinds/libblinds.la modules/checkers/libcheckers.la modules/compose/libcompose.la modules/drizzle/libdrizzle.la modules/flui2d/libflui2d.la modules/julia/libjulia.la modules/meta2d/libmeta2d.la modules/mixer/libmixer.la modules/moire/libmoire.la modules/montage/libmontage.la modules/pixbounce/libpixbounce.la modules/plasma/libplasma.la modules/plato/libplato.la modules/ray/libray.la modules/rkt/librkt.la modules/roto/libroto.la modules/rtv/librtv.la modules/shapes/libshapes.la modules/snow/libsnow.la modules/sparkler/libsparkler.la modules/spiro/libspiro.la modules/stars/libstars.la modules/strobe/libstrobe.la modules/submit/libsubmit.la modules/swab/libswab.la modules/swarm/libswarm.la modules/voronoi/libvoronoi.la libs/grid/libgrid.la libs/puddle/libpuddle.la libs/ray/libray.la libs/rocket/librocket.la libs/sig/libsig.la libs/txt/libtxt.la libs/ascii/libascii.la libs/din/libdin.la bin_PROGRAMS = rototiller rototiller_SOURCES = fps.c fps.h main.c mem_fb.c setup.h setup.c til.h til_fb.c til_fb.h til_settings.c til_settings.h til_threads.c til_threads.h til_util.c til_util.h diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index c1326ac..d34e0c7 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -1 +1 @@ -SUBDIRS = blinds checkers compose drizzle flui2d julia meta2d moire montage pixbounce plasma plato ray rkt roto rtv shapes snow sparkler spiro stars strobe submit swab swarm voronoi +SUBDIRS = blinds checkers compose drizzle flui2d julia meta2d mixer moire montage pixbounce plasma plato ray rkt roto rtv shapes snow sparkler spiro stars strobe submit swab swarm voronoi diff --git a/src/modules/mixer/Makefile.am b/src/modules/mixer/Makefile.am new file mode 100644 index 0000000..8d265d5 --- /dev/null +++ b/src/modules/mixer/Makefile.am @@ -0,0 +1,3 @@ +noinst_LTLIBRARIES = libmixer.la +libmixer_la_SOURCES = mixer.c +libmixer_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/mixer/mixer.c b/src/modules/mixer/mixer.c new file mode 100644 index 0000000..55234d3 --- /dev/null +++ b/src/modules/mixer/mixer.c @@ -0,0 +1,302 @@ +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "til.h" +#include "til_fb.h" +#include "til_module_context.h" +#include "til_settings.h" +#include "til_stream.h" +#include "til_tap.h" +#include "til_util.h" + +/* Copyright (C) 2023 - Vito Caputo <vcaputo@pengaru.com> */ + +/* This implements a rudimentary mixing module for things like fades */ + +typedef enum mixer_style_t { + MIXER_STYLE_FLICKER, +} mixer_style_t; + +typedef struct mixer_input_t { + til_module_context_t *module_ctxt; + /* XXX: it's expected that inputs will get more settable attributes to stick in here */ +} mixer_input_t; + +typedef struct mixer_context_t { + til_module_context_t til_module_context; + + struct { + til_tap_t T; + } taps; + + struct { + float T; + } vars; + + float *T; + + size_t n_inputs; + mixer_input_t inputs[]; +} mixer_context_t; + +typedef struct mixer_setup_input_t { + char *module; + til_setup_t *setup; +} mixer_setup_input_t; + +typedef struct mixer_setup_t { + til_setup_t til_setup; + + mixer_style_t style; + size_t n_inputs; + mixer_setup_input_t inputs[]; +} mixer_setup_t; + +#define MIXER_DEFAULT_STYLE MIXER_STYLE_FLICKER + +static til_module_context_t * mixer_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup); +static void mixer_destroy_context(til_module_context_t *context); +static void mixer_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr); +static int mixer_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup); + + +til_module_t mixer_module = { + .create_context = mixer_create_context, + .destroy_context = mixer_destroy_context, + .render_fragment = mixer_render_fragment, + .name = "mixer", + .description = "Module blender", + .setup = mixer_setup, + .flags = TIL_MODULE_EXPERIMENTAL, +}; + + +static til_module_context_t * mixer_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup) +{ + mixer_setup_t *s = (mixer_setup_t *)setup; + mixer_context_t *ctxt; + int r; + + assert(setup); + + ctxt = til_module_context_new(module, sizeof(mixer_context_t) + s->n_inputs * sizeof(mixer_input_t), stream, seed, ticks, n_cpus, setup); + if (!ctxt) + return NULL; + + for (size_t i = 0; i < s->n_inputs; i++) { + const til_module_t *input_module; + input_module = til_lookup_module(((mixer_setup_t *)setup)->inputs[i].module); + r = til_module_create_context(input_module, stream, rand_r(&seed), ticks, n_cpus, s->inputs[i].setup, &ctxt->inputs[i].module_ctxt); + if (r < 0) + return til_module_context_free(&ctxt->til_module_context); + + ctxt->n_inputs++; + } + + ctxt->taps.T = til_tap_init_float(ctxt, &ctxt->T, 1, &ctxt->vars.T, "T"); + + return &ctxt->til_module_context; +} + + +static void mixer_destroy_context(til_module_context_t *context) +{ + mixer_context_t *ctxt = (mixer_context_t *)context; + + for (size_t i = 0; i < ctxt->n_inputs; i++) + til_module_context_free(ctxt->inputs[i].module_ctxt); + + free(context); +} + +static inline float randf(unsigned *seed) +{ + return 1.f / RAND_MAX * rand_r(seed); +} + +static void mixer_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr) +{ + mixer_context_t *ctxt = (mixer_context_t *)context; + til_fb_fragment_t *fragment = *fragment_ptr; + size_t i = 0; + + if (!til_stream_tap_context(stream, context, NULL, &ctxt->taps.T)) + *ctxt->T = cosf(ticks * .001f) * .5f + .5f; + + switch (((mixer_setup_t *)context->setup)->style) { + case MIXER_STYLE_FLICKER: + if (randf(&context->seed) < *ctxt->T) + i = 1; + else + i = 0; + break; + + default: + assert(0); + } + + //for (size_t i = 0; i < ctxt->n_inputs; i++) + til_module_render(ctxt->inputs[i].module_ctxt, stream, ticks, &fragment); + + *fragment_ptr = fragment; +} + + +static void mixer_setup_free(til_setup_t *setup) +{ + mixer_setup_t *s = (mixer_setup_t *)setup; + + if (s) { + for (size_t i = 0; i < s->n_inputs; i++) { + free(s->inputs[i].module); + til_setup_free(s->inputs[i].setup); + } + free(setup); + } +} + + +static int mixer_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup) +{ + const char *style_values[] = { + "flicker", + NULL + }; + const char *style; + const til_settings_t *inputs_settings; + const char *inputs; + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_spec_t){ + .name = "Mixer blend style", + .key = "style", + .values = style_values, + .preferred = style_values[MIXER_DEFAULT_STYLE], + .annotations = NULL + }, + &style, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_spec_t){ + .name = "Comma-separated list of module inputs", + .key = "inputs", + .preferred = "stars,plato", + .annotations = NULL, + //.random = mixer_random_inputs_setting, + .as_nested_settings = 1, + }, + &inputs, /* XXX: unused in raw-value form, we want the settings instance */ + res_setting, + res_desc); + if (r) + return r; + + assert(res_setting && *res_setting && (*res_setting)->value_as_nested_settings); + inputs_settings = (*res_setting)->value_as_nested_settings; + { + til_setting_t *input_setting; + + for (size_t i = 0; til_settings_get_value_by_idx(inputs_settings, i, &input_setting); i++) { + if (!input_setting->value_as_nested_settings) { + r = til_setting_desc_new( inputs_settings, + &(til_setting_spec_t){ + .as_nested_settings = 1, + }, res_desc); + if (r < 0) + return r; + + *res_setting = input_setting; + + return 1; + } + } + + for (size_t i = 0; til_settings_get_value_by_idx(inputs_settings, i, &input_setting); i++) { + til_setting_t *input_module_setting; + const char *input = til_settings_get_value_by_idx(input_setting->value_as_nested_settings, 0, &input_module_setting); + const til_module_t *input_module; + + if (!input_module_setting) + return -EINVAL; + + if (!input_module_setting->desc) { + r = til_setting_desc_new( input_setting->value_as_nested_settings, + &(til_setting_spec_t){ + .name = "Input module name", + .preferred = "none", + .as_label = 1, + }, res_desc); + if (r < 0) + return r; + + *res_setting = input_module_setting; + + return 1; + } + + input_module = til_lookup_module(input); + if (!input_module) + return -EINVAL; + + if (input_module->setup) { + r = input_module->setup(input_setting->value_as_nested_settings, res_setting, res_desc, NULL); + if (r) + return r; + } + } + } + + if (res_setup) { + size_t n_inputs = til_settings_get_count(inputs_settings); + til_setting_t *input_setting; + mixer_setup_t *setup; + + setup = til_setup_new(settings, sizeof(*setup) + n_inputs * sizeof(setup->inputs[0]), mixer_setup_free); + if (!setup) + return -ENOMEM; + + for (int i = 0; style_values[i]; i++) { + if (!strcasecmp(style_values[i], style)) + setup->style = i; + } + + setup->n_inputs = n_inputs; + + for (size_t i = 0; til_settings_get_value_by_idx(inputs_settings, i, &input_setting); i++) { + const char *input = til_settings_get_value_by_idx(input_setting->value_as_nested_settings, 0, NULL); + const til_module_t *input_module; + + setup->inputs[i].module = strdup(input); + if (!setup->inputs[i].module) { + til_setup_free(&setup->til_setup); + + return -ENOMEM; + } + + input_module = til_lookup_module(input); + if (!input_module) { + til_setup_free(&setup->til_setup); + + return -EINVAL; + } + + r = til_module_setup_finalize(input_module, input_setting->value_as_nested_settings, &setup->inputs[i].setup); + if (r < 0) { + til_setup_free(&setup->til_setup); + + return r; + } + } + + *res_setup = &setup->til_setup; + } + + return 0; +} @@ -32,6 +32,7 @@ extern til_module_t drizzle_module; extern til_module_t flui2d_module; extern til_module_t julia_module; extern til_module_t meta2d_module; +extern til_module_t mixer_module; extern til_module_t moire_module; extern til_module_t montage_module; extern til_module_t pixbounce_module; @@ -60,6 +61,7 @@ static const til_module_t *modules[] = { &flui2d_module, &julia_module, &meta2d_module, + &mixer_module, &moire_module, &montage_module, &pixbounce_module, |