diff options
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/rkt/rkt.c | 252 | 
1 files changed, 197 insertions, 55 deletions
| diff --git a/src/modules/rkt/rkt.c b/src/modules/rkt/rkt.c index 1022119..42f51e7 100644 --- a/src/modules/rkt/rkt.c +++ b/src/modules/rkt/rkt.c @@ -24,27 +24,37 @@   * GNU Rocket (https://github.com/rocket/rocket)   */ +typedef struct rkt_scene_t { +	const til_module_t	*module; +	til_module_context_t	*module_ctxt; +} rkt_scene_t; +  typedef struct rkt_context_t {  	til_module_context_t	til_module_context; -	const til_module_t	*seq_module; -	til_module_context_t	*seq_module_ctxt; -  	struct sync_device	*sync_device; +	const struct sync_track	*scene_track;  	double			rows_per_ms;  	double			rocket_row;  	unsigned		last_ticks;  	unsigned		paused:1; +	rkt_scene_t		scenes[];  } rkt_context_t; +typedef struct rkt_setup_scene_t { +	char			*module_name; +	til_setup_t		*setup; +} rkt_setup_scene_t; +  typedef struct rkt_setup_t {  	til_setup_t		til_setup; -	const char		*seq_module_name;  	const char		*base;  	double			rows_per_ms;  	unsigned		connect:1;  	const char		*host;  	unsigned short		port; +	size_t			n_scenes; +	rkt_setup_scene_t	scenes[];  } rkt_setup_t; @@ -71,15 +81,10 @@ static const struct sync_track * sync_get_trackf(struct sync_device *device, con  static til_module_context_t * rkt_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup)  { -	rkt_setup_t		*s = (rkt_setup_t *)setup; -	const til_module_t	*seq_module; -	rkt_context_t		*ctxt; +	rkt_setup_t	*s = (rkt_setup_t *)setup; +	rkt_context_t	*ctxt; -	seq_module = til_lookup_module(s->seq_module_name); -	if (!seq_module) -		return NULL; - -	ctxt = til_module_context_new(module, sizeof(rkt_context_t), stream, seed, ticks, n_cpus, setup); +	ctxt = til_module_context_new(module, sizeof(rkt_context_t) + s->n_scenes * sizeof(*ctxt->scenes), stream, seed, ticks, n_cpus, setup);  	if (!ctxt)  		return NULL; @@ -93,14 +98,18 @@ static til_module_context_t * rkt_create_context(const til_module_t *module, til  			return til_module_context_free(&ctxt->til_module_context);  	} -	ctxt->seq_module = seq_module; +	ctxt->scene_track = sync_get_trackf(ctxt->sync_device, "%s:scene", setup->path); +	if (!ctxt->scene_track) +		return til_module_context_free(&ctxt->til_module_context); -	{ +	for (size_t i = 0; i < s->n_scenes; i++) {  		til_setup_t	*module_setup = NULL; -		(void) til_module_setup_randomize(ctxt->seq_module, rand_r(&seed), &module_setup, NULL); +		ctxt->scenes[i].module = til_lookup_module(s->scenes[i].module_name); +		if (!ctxt->scenes[i].module) /* this isn't really expected since setup already does this */ +			return til_module_context_free(&ctxt->til_module_context); -		(void) til_module_create_context(ctxt->seq_module, stream, rand_r(&seed), ticks, 0, module_setup, &ctxt->seq_module_ctxt); +		(void) til_module_create_context(ctxt->scenes[i].module, stream, rand_r(&seed), ticks, 0, s->scenes[i].setup, &ctxt->scenes[i].module_ctxt);  		til_setup_free(module_setup);  	} @@ -117,7 +126,10 @@ static void rkt_destroy_context(til_module_context_t *context)  	if (ctxt->sync_device)  		sync_destroy_device(ctxt->sync_device); -	til_module_context_free(ctxt->seq_module_ctxt); + +	for (size_t i = 0; i < ((rkt_setup_t *)context->setup)->n_scenes; i++) +		til_module_context_free(ctxt->scenes[i].module_ctxt); +  	free(context);  } @@ -215,9 +227,9 @@ static const til_stream_hooks_t	rkt_stream_hooks = {  static int rkt_pipe_update(void *context, til_stream_pipe_t *pipe, const void *owner, const void *owner_foo, const til_tap_t *driving_tap)  { -	rkt_pipe_t		*rkt_pipe = (rkt_pipe_t *)owner_foo; +	rkt_pipe_t	*rkt_pipe = (rkt_pipe_t *)owner_foo;  	rkt_context_t	*ctxt = context; -	double			val; +	double		val;  	/* just ignore pipes we don't own (they're not types we can drive w/rocket) */  	if (owner != ctxt) @@ -271,45 +283,137 @@ static void rkt_render_fragment(til_module_context_t *context, til_stream_t *str  	/* this drives our per-rocket-track updates, with the tracks registered as owner_foo on the pipes, respectively */  	til_stream_for_each_pipe(stream, rkt_pipe_update, ctxt); -	til_module_render(ctxt->seq_module_ctxt, stream, ticks, fragment_ptr); +	{ +		unsigned	scene; + +		scene = (unsigned)sync_get_val(ctxt->scene_track, ctxt->rocket_row); +		if (scene < ((rkt_setup_t *)context->setup)->n_scenes) +			til_module_render(ctxt->scenes[scene].module_ctxt, stream, ticks, fragment_ptr); +		else { +			txt_t	*msg = txt_newf("%s: NO SCENE @ %u", context->setup->path, scene); + +			/* TODO: creating/destroying this every frame is dumb, but +			 * as this is a diagnostic it's not so important. +			 * +			 * Once this module deals with disconnects and transparently reconnects, it'll need +			 * to show some connection status information as well... when that gets added this will +			 * likely get reworked to become part of that status text. +			 */ +			til_fb_fragment_clear(*fragment_ptr); +			txt_render_fragment(msg, *fragment_ptr, 0xffffffff, +					    0, 0, +					    (txt_align_t){ +						.horiz = TXT_HALIGN_LEFT, +						.vert = TXT_VALIGN_TOP, +					   }); +			txt_free(msg); +		} +	} +} + + +static void rkt_setup_free(til_setup_t *setup) +{ +	rkt_setup_t	*s = (rkt_setup_t *)setup; + +	if (s) { +		for (size_t i = 0; i < s->n_scenes; i++) { +			free(s->scenes[i].module_name); +			til_setup_free(s->scenes[i].setup); +		} +		free((void *)s->base); +		free((void *)s->host); +		free(setup); +	}  }  static int rkt_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	*connect_values[] = { -				"off", -				"on", -				NULL -			}; -	const char	*seq_module; -	const char	*base; -	const char	*bpm; -	const char	*rpb; -	const char	*connect; -	const char	*host; -	const char	*port; -	int		r; - -	/* TODO: -	 * Instead of driving a single module, we could accept a list of module specifiers -	 * including settings for each (requiring the recursive settings support to land). -	 * Then just use a module selector track for switching between the modules... that -	 * might work for getting full-blown demos sequenced via rocket. +	const til_settings_t	*scenes_settings; +	const char		*connect_values[] = { +					"off", +					"on", +					NULL +				}; +	const char		*scenes; +	const char		*base; +	const char		*bpm; +	const char		*rpb; +	const char		*connect; +	const char		*host; +	const char		*port; +	int			r; + +	/* This is largely taken from compose::layers, but might just go away when I add tables to rocket, +	 * or maybe they can coexist.  	 */  	r = til_settings_get_and_describe_value(settings,  						&(til_setting_spec_t){ -							.name = "Module to sequence", -							.key = "seq_module", -							.preferred = "compose", +							.name = "Comma-separated list of modules for scenes to sequence", +							.key = "scenes", +							.preferred = "compose,compose,compose,compose",  							.annotations = NULL, +							.as_nested_settings = 1,  						}, -						&seq_module, +						&scenes,  						res_setting,  						res_desc);  	if (r)  		return r; +	assert(res_setting && *res_setting && (*res_setting)->value_as_nested_settings); +	scenes_settings = (*res_setting)->value_as_nested_settings; +	{ +		til_setting_t	*scene_setting; +		const char	*scene_module; + +		for (size_t i = 0; til_settings_get_value_by_idx(scenes_settings, i, &scene_setting); i++) { +			if (!scene_setting->value_as_nested_settings) { +				r = til_setting_desc_new(	scenes_settings, +								&(til_setting_spec_t){ +									.as_nested_settings = 1, +								}, res_desc); +				if (r < 0) +					return r; + +				*res_setting = scene_setting; + +				return 1; +			} +		} + +		for (size_t i = 0; til_settings_get_value_by_idx(scenes_settings, i, &scene_setting); i++) { +			til_setting_t		*scene_module_setting; +			const char		*scene_module_name = til_settings_get_value_by_idx(scene_setting->value_as_nested_settings, 0, &scene_module_setting); +			const til_module_t	*scene_module = til_lookup_module(scene_module_name); + +			if (!scene_module || !scene_module_setting) +				return -EINVAL; + +			if (!scene_module_setting->desc) { +				r = til_setting_desc_new(	scene_setting->value_as_nested_settings, +								&(til_setting_spec_t){ +									.name = "Scene module name", +									.preferred = "none", +									.as_label = 1, +								}, res_desc); +				if (r < 0) +					return r; + +				*res_setting = scene_module_setting; + +				return 1; +			} + +			if (scene_module->setup) { +				r = scene_module->setup(scene_setting->value_as_nested_settings, res_setting, res_desc, NULL); +				if (r) +					return r; +			} +		} +	} +  	r = til_settings_get_and_describe_value(settings,  						&(til_setting_spec_t){  							.name = "Rocket \"base\" label", @@ -395,29 +499,67 @@ static int rkt_setup(const til_settings_t *settings, til_setting_t **res_setting  	}  	if (res_setup) { -		const til_module_t	*til_seq_module; +		size_t			n_scenes = til_settings_get_count(scenes_settings); +		til_setting_t		*scene_setting;  		rkt_setup_t		*setup;  		unsigned		ibpm, irpb; -		if (!strcmp(seq_module, "rkt")) -			return -EINVAL; +		setup = til_setup_new(settings, sizeof(*setup) + n_scenes * sizeof(*setup->scenes), rkt_setup_free); +		if (!setup) +			return -ENOMEM; -		til_seq_module = til_lookup_module(seq_module); -		if (!til_seq_module) -			return -ENOENT; +		setup->n_scenes = n_scenes; + +		for (size_t i = 0; til_settings_get_value_by_idx(scenes_settings, i, &scene_setting); i++) { +			const char		*scene_module_name = til_settings_get_value_by_idx(scene_setting->value_as_nested_settings, 0, NULL); +			const til_module_t	*scene_module = til_lookup_module(scene_module_name); + +			if (!scene_module || !strcmp(scene_module_name, "rkt")) { +				til_setup_free(&setup->til_setup); + +				return -EINVAL; +			} + +			/* XXX If it's appropriate stow the resolved til_module_t* or the name is still unclear, since +			 * the module names will soon be able to address existing contexts in the stream at their path. +			 * So for now I'm just going to continue stowing the name, even though the lookup above prevents +			 * any sort of context address being used... +			 */ +			setup->scenes[i].module_name = strdup(scene_module_name); +			if (!setup->scenes[i].module_name) { +				til_setup_free(&setup->til_setup); + +				return -ENOMEM; +			} + +			r = til_module_setup_finalize(scene_module, scene_setting->value_as_nested_settings, &setup->scenes[i].setup); +			if (r < 0) { +				til_setup_free(&setup->til_setup); + +				return r; +			} +		} + +		setup->base = strdup(base); +		if (!setup->base) { +			til_setup_free(&setup->til_setup); -		/* TODO: we're going to need a custom setup_free to cleanup host+base etc. */ -		setup = til_setup_new(settings, sizeof(*setup), NULL); -		if (!setup)  			return -ENOMEM; +		} -		setup->seq_module_name = til_seq_module->name; -		setup->base = strdup(base); /* FIXME errors */  		if (!strcasecmp(connect, "on")) {  			setup->connect = 1; -			setup->host = strdup(host); /* FIXME errors */ + +			setup->host = strdup(host); +			if (!setup->host) { +				til_setup_free(&setup->til_setup); + +				return -ENOMEM; +			} +  			sscanf(port, "%hu", &setup->port); /* FIXME parse errors */  		} +  		sscanf(bpm, "%u", &ibpm);  		sscanf(rpb, "%u", &irpb);  		setup->rows_per_ms = ((double)(ibpm * irpb)) * (1.0 / (60.0 * 1000.0)); | 
