Makefile: install-doc: install manpage links for each command
[ng-jackspa.git] / control.c
blobd1fffd2f359169dea19f930158c77088559e2b7b
1 /* control.c - interface to the controls of a jackspa plugin instance
2 * Copyright © 2013 Géraud Meyer <graud@gmx.com>
4 * This file is part of ng-jackspa.
6 * ng-jackspa is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License version 2 as published by the
8 * Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along
16 * with ng-jackspa. If not, see <http://www.gnu.org/licenses/>.
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <math.h>
22 #include <string.h>
23 #include <regex.h>
24 #include "control.h"
25 #include "interface.h"
27 LADSPA_Data control_rounding(const control_t *control, LADSPA_Data val)
29 if (control->type == JACKSPA_INT || control->type == JACKSPA_TOGGLE)
30 return nearbyintf(val);
31 return val;
34 void control_exchange(control_t *control)
36 LADSPA_Data buf;
37 buf = *control->val;
38 *control->val = control->sel;
39 control->sel = buf;
42 /* Initial config (command line switches) */
43 gchar **control_bounds = NULL;
44 gchar **control_inits = NULL;
45 gchar **control_defaults = NULL;
46 gboolean parse_bounds(const gchar *opt, const gchar *arg,
47 gpointer data, GError **error)
49 g_strfreev(control_bounds); /* discard a possible previous option */
50 control_bounds = g_strsplit(arg, ":", -1);
51 return TRUE;
53 gboolean parse_inits(const gchar *opt, const gchar *arg,
54 gpointer data, GError **error)
56 g_strfreev(control_inits); /* discard a possible previous option */
57 control_inits = g_strsplit(arg, ":", -1);
58 return TRUE;
60 gboolean parse_defaults(const gchar *opt, const gchar *arg,
61 gpointer data, GError **error)
63 g_strfreev(control_defaults); /* discard a possible previous option */
64 control_defaults = g_strsplit(arg, ":", -1);
65 return TRUE;
68 const GOptionEntry control_entries[] =
70 /* long, short, flags, arg_type, arg_data, description, arg_description */
71 { "bounds", 'b', 0, G_OPTION_ARG_CALLBACK, parse_bounds,
72 "Colon separated list of multiplexed min/max values", "bound_values" },
73 { "inits", 'i', 0, G_OPTION_ARG_CALLBACK, parse_inits,
74 "Colon separated list of initial values", "init_values" },
75 { "defaults", 'd', 0, G_OPTION_ARG_CALLBACK, parse_defaults,
76 "Colon separated list of default values", "default_values" },
77 { 0 }
81 typedef struct {
82 char with_ini;
83 LADSPA_Data ini;
84 char with_def;
85 LADSPA_Data def;
86 char with_min;
87 LADSPA_Data min;
88 char with_max;
89 LADSPA_Data max;
90 } control_init_t;
92 /* see the interface .h file */
93 int control_set_value(LADSPA_Data *val, char *cmd, control_t *control)
95 LADSPA_Data buf;
96 regex_t reg;
97 regmatch_t matches[1];
98 const char *percent_r="^%[0-9][0-9]$";
99 char *e;
100 int rc;
101 char err[30];
103 if (cmd == NULL || !strcmp(cmd, "")) /* skip */
104 return 1;
105 else if (!strcmp(cmd, "<")) /* min */
106 *val = control->min;
107 else if (!strcmp(cmd, ">")) /* max */
108 *val = control->max;
109 else if (cmd[0] == '%') { /* percentage */
110 if ((rc = regcomp(&reg, percent_r, 0)) ) {
111 regerror(rc, &reg, err, sizeof(err));
112 return (fprintf(stderr, "regex compilation failed: %s\n", err), -1);
114 if (regexec(&reg, cmd, 1, matches, 0))
115 return (regfree(&reg), -1);
116 *val = (LADSPA_Data)strtof(&cmd[1], NULL) / 100.0;
117 *val = control_rounding
118 (control, (1.0-*val) * control->min + *val * control->max);
119 regfree(&reg);
121 else if (!strcmp(cmd, "d")) { /* default */
122 if (control->def)
123 *val = *control->def;
124 else
125 return -1;
127 else if (!strcmp(cmd, "a")) /* active */
128 *val = *control->val;
129 else if (!strcmp(cmd, "s")) /* selected */
130 *val = control->sel;
131 else { /* float */
132 buf = (LADSPA_Data)strtof(cmd, &e);
133 if (e == cmd || *e != '\0')
134 return -1;
135 *val = buf;
138 return 0;
141 /* Find the initial config of the control at index ctrl */
142 int control_set_init(control_init_t *init,
143 unsigned long ctrl, control_t *control)
145 int ret = 0, rc;
147 rc = control_set_value(&init->min, glib_strv_index(2*ctrl, control_bounds), control);
148 init->with_min = rc ? 0 : 1;
149 if (rc < 0) ret = rc;
150 rc = control_set_value(&init->max, glib_strv_index(2*ctrl+1, control_bounds), control);
151 init->with_max = rc ? 0 : 1;
152 if (rc < 0) ret = rc;
154 rc = control_set_value(&init->ini, glib_strv_index(ctrl, control_inits), control);
155 init->with_ini = rc ? 0 : 1;
156 if (rc < 0) ret = rc;
158 rc = control_set_value(&init->def, glib_strv_index(ctrl, control_defaults), control);
159 init->with_def = rc ? 0 : 1;
160 if (rc < 0) ret = rc;
162 return ret;
165 int control_init(control_t *control, state_t *state, unsigned long port,
166 unsigned long ctrl)
168 control->port = port;
169 control->ctrl = ctrl;
170 control->desc = &state->descriptor->PortDescriptors[port];
171 control->hint = &state->descriptor->PortRangeHints[port];
172 LADSPA_PortRangeHintDescriptor descriptor = control->hint->HintDescriptor;
173 LADSPA_Data lower_bound = control->hint->LowerBound;
174 LADSPA_Data upper_bound = control->hint->UpperBound;
175 control_init_t init;
177 control->name = state->port_names[port];
178 control->val = &state->control_port_values[port];
180 /* control->min, control->max */
181 if (LADSPA_IS_HINT_SAMPLE_RATE(descriptor)) {
182 int sample_rate = jack_get_sample_rate(state->jack_client);
183 lower_bound *= sample_rate;
184 upper_bound *= sample_rate;
186 if ( LADSPA_IS_HINT_BOUNDED_BELOW(descriptor) &&
187 LADSPA_IS_HINT_BOUNDED_ABOVE(descriptor) )
189 control->min = lower_bound;
190 control->max = upper_bound;
192 else if (LADSPA_IS_HINT_BOUNDED_BELOW(descriptor)) {
193 control->min = lower_bound;
194 control->max = 1.0;
196 else if (LADSPA_IS_HINT_BOUNDED_ABOVE(descriptor)) {
197 control->min = 0.0;
198 control->max = upper_bound;
200 else {
201 control->min = -1.0;
202 control->max = 1.0;
205 /* control->def */
206 if (LADSPA_IS_HINT_HAS_DEFAULT(descriptor)) {
207 control->def = (LADSPA_Data *)malloc(sizeof(LADSPA_Data));
208 if (!control->def)
209 return (fprintf(stderr, "memory allocation error\n"), 1);
210 switch (descriptor & LADSPA_HINT_DEFAULT_MASK) {
211 case LADSPA_HINT_DEFAULT_MINIMUM:
212 *control->def = lower_bound;
213 break;
214 case LADSPA_HINT_DEFAULT_LOW:
215 *control->def = lower_bound * 0.75 + upper_bound * 0.25;
216 break;
217 case LADSPA_HINT_DEFAULT_MIDDLE:
218 *control->def = lower_bound * 0.5 + upper_bound * 0.5;
219 break;
220 case LADSPA_HINT_DEFAULT_HIGH:
221 *control->def = lower_bound * 0.25 + upper_bound * 0.75;
222 break;
223 case LADSPA_HINT_DEFAULT_MAXIMUM:
224 *control->def = upper_bound;
225 break;
226 case LADSPA_HINT_DEFAULT_0:
227 *control->def = 0.0;
228 break;
229 case LADSPA_HINT_DEFAULT_1:
230 *control->def = 1.0;
231 break;
232 case LADSPA_HINT_DEFAULT_100:
233 *control->def = 100.0;
234 break;
235 case LADSPA_HINT_DEFAULT_440:
236 *control->def = 440.0;
237 break;
238 default:
239 fprintf(stderr, "default not found\n");
240 free(control->def), control->def = NULL;
243 else
244 control->def = NULL;
246 /* Check the default */
247 if (control->def) {
248 if (*control->def < control->min) {
249 fprintf(stderr, "default smaller than the minimum\n");
250 *control->def = control->min;
252 if (*control->def > control->max) {
253 fprintf(stderr, "default greater than the maximum\n");
254 *control->def = control->max;
258 /* control->inc & Overrides */
259 if (LADSPA_IS_HINT_TOGGLED(descriptor)) {
260 control->min = 0.0;
261 control->max = 1.0;
262 control->inc.fine = 1.0;
263 control->inc.coarse = 1.0;
264 control->type = JACKSPA_TOGGLE;
265 if (control->def) *control->def = nearbyintf(*control->def);
267 else if (LADSPA_IS_HINT_INTEGER(descriptor)) {
268 control->min = nearbyintf(control->min);
269 control->max = nearbyintf(control->max);
270 control->inc.fine = 1.0;
271 control->inc.coarse = 1.0;
272 control->type = JACKSPA_INT;
273 if (control->def) *control->def = nearbyintf(*control->def);
275 else {
276 control->inc.fine = (control->max - control->min) / 500;
277 control->inc.coarse = (control->max - control->min) / 50;
278 control->type = JACKSPA_FLOAT;
281 /* Initial config */
282 if (control_set_init(&init, ctrl, control) < 0)
283 return (fprintf(stderr, "invalid initial value given\n"), 1);
284 if (init.with_min)
285 control->min = init.min;
286 if (init.with_max)
287 control->max = init.max;
288 if (init.with_def) {
289 if (!control->def) {
290 control->def = (LADSPA_Data *)malloc(sizeof(LADSPA_Data));
291 if (!control->def)
292 return (fprintf(stderr, "memory allocation error\n"), 1);
294 *control->def = init.def;
297 /* control->sel, control->val */
298 if (control->def)
299 control->sel = *control->def;
300 else
301 control->sel = control->min;
302 if (init.with_ini)
303 *control->val = init.ini;
304 else
305 *control->val = control->sel;
307 return 0;
310 void control_fini(control_t *control)
312 free(control->def), control->def = NULL;
315 int control_buildall(unsigned long *count, controls_t *controls, state_t *state)
317 int rc = 0;
318 unsigned long p, c; /* loop variables for ports */
320 *count = state->num_control_ports;
321 *controls = (controls_t)calloc(sizeof(control_t *), (size_t)*count);
322 if (!*controls)
323 return (fprintf(stderr, "memory allocation error\n"), 1);
325 for (p = 0, c = 0; p < state->descriptor->PortCount; p++)
326 if ( LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[p]) &&
327 LADSPA_IS_PORT_CONTROL(state->descriptor->PortDescriptors[p]) )
329 (*controls)[c] = (control_t *)malloc(sizeof(control_t));
330 if (!(*controls)[c])
331 return (fprintf(stderr, "memory allocation error\n"), 1);
332 if (control_init((*controls)[c], state, p, c))
333 rc = 1;
334 c++;
337 return rc;
340 void control_cleanupall(unsigned long count, controls_t *controls)
342 while (count) {
343 control_fini((*controls)[--count]);
344 free((*controls)[count]);
346 free(*controls);