summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2023-06-09 19:04:40 -0700
committerVito Caputo <vcaputo@pengaru.com>2023-06-11 21:53:50 -0700
commit074353394ff369f34dea5d05d052556466904b08 (patch)
tree56dd7c1d7edd11ecdbfd9e137ced26c9ecd8aed9 /src/modules
parent78f5f83627c8565946b9b636a6f86712b85779a9 (diff)
modules/mixer: add rudimentary mixer meta module
this is very early/unfinished, hence experimental flag
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/Makefile.am2
-rw-r--r--src/modules/mixer/Makefile.am3
-rw-r--r--src/modules/mixer/mixer.c302
3 files changed, 306 insertions, 1 deletions
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;
+}
© All Rights Reserved