njackspa: [bug] fix the fields' widths
[ng-jackspa.git] / control.c
blob022bf67c6331ce47f330b798e081d650b2257013
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 /* Interpret the given command to obtain a value depending of the control
93 * parameters.
94 * Return 0 if the value was set, 1 if the command was to skip, -1 otherwise
95 * (invalid command or error) */
96 int control_set_value(LADSPA_Data *val, char *cmd, control_t *control)
98 LADSPA_Data buf;
99 regex_t reg;
100 regmatch_t matches[1];
101 const char *percent_r="^%[0-9][0-9]$";
102 char *e;
103 int rc;
104 char err[30];
106 if (cmd == NULL || !strcmp(cmd, "")) /* skip */
107 return 1;
108 else if (!strcmp(cmd, "<")) /* min */
109 *val = control->min;
110 else if (!strcmp(cmd, ">")) /* max */
111 *val = control->max;
112 else if (cmd[0] == '%') { /* percentage */
113 if ((rc = regcomp(&reg, percent_r, 0)) ) {
114 regerror(rc, &reg, err, sizeof(err));
115 return (fprintf(stderr, "regex compilation failed: %s\n", err), -1);
117 if (regexec(&reg, cmd, 1, matches, 0))
118 return (regfree(&reg), -1);
119 *val = (LADSPA_Data)strtof(&cmd[1], NULL) / 100.0;
120 *val = control_rounding
121 (control, (1.0-*val) * control->min + *val * control->max);
122 regfree(&reg);
124 else if (!strcmp(cmd, "d")) { /* default */
125 if (control->def)
126 *val = *control->def;
127 else
128 return -1;
130 else if (!strcmp(cmd, "a")) /* active */
131 *val = *control->val;
132 else if (!strcmp(cmd, "s")) /* selected */
133 *val = control->sel;
134 else { /* float */
135 buf = (LADSPA_Data)strtof(cmd, &e);
136 if (e == cmd || *e != '\0')
137 return -1;
138 *val = buf;
141 return 0;
144 /* Find the initial config of the control at index ctrl */
145 int control_set_init(control_init_t *init,
146 unsigned long ctrl, control_t *control)
148 int ret = 0, rc;
150 rc = control_set_value(&init->min, glib_strv_index(2*ctrl, control_bounds), control);
151 init->with_min = rc ? 0 : 1;
152 if (rc < 0) ret = rc;
153 rc = control_set_value(&init->max, glib_strv_index(2*ctrl+1, control_bounds), control);
154 init->with_max = rc ? 0 : 1;
155 if (rc < 0) ret = rc;
157 rc = control_set_value(&init->ini, glib_strv_index(ctrl, control_inits), control);
158 init->with_ini = rc ? 0 : 1;
159 if (rc < 0) ret = rc;
161 rc = control_set_value(&init->def, glib_strv_index(ctrl, control_defaults), control);
162 init->with_def = rc ? 0 : 1;
163 if (rc < 0) ret = rc;
165 return ret;
168 int control_init(control_t *control, state_t *state, unsigned long port,
169 unsigned long ctrl)
171 control->port = port;
172 control->ctrl = ctrl;
173 control->desc = &state->descriptor->PortDescriptors[port];
174 control->hint = &state->descriptor->PortRangeHints[port];
175 LADSPA_PortRangeHintDescriptor descriptor = control->hint->HintDescriptor;
176 LADSPA_Data lower_bound = control->hint->LowerBound;
177 LADSPA_Data upper_bound = control->hint->UpperBound;
178 control_init_t init;
180 control->name = state->port_names[port];
181 control->val = &state->control_port_values[port];
183 /* control->min, control->max */
184 if (LADSPA_IS_HINT_SAMPLE_RATE(descriptor)) {
185 int sample_rate = jack_get_sample_rate(state->jack_client);
186 lower_bound *= sample_rate;
187 upper_bound *= sample_rate;
189 if ( LADSPA_IS_HINT_BOUNDED_BELOW(descriptor) &&
190 LADSPA_IS_HINT_BOUNDED_ABOVE(descriptor) )
192 control->min = lower_bound;
193 control->max = upper_bound;
195 else if (LADSPA_IS_HINT_BOUNDED_BELOW(descriptor)) {
196 control->min = lower_bound;
197 control->max = 1.0;
199 else if (LADSPA_IS_HINT_BOUNDED_ABOVE(descriptor)) {
200 control->min = 0.0;
201 control->max = upper_bound;
203 else {
204 control->min = -1.0;
205 control->max = 1.0;
208 /* control->def */
209 if (LADSPA_IS_HINT_HAS_DEFAULT(descriptor)) {
210 control->def = (LADSPA_Data *)malloc(sizeof(LADSPA_Data));
211 if (!control->def)
212 return (fprintf(stderr, "memory allocation error\n"), 1);
213 switch (descriptor & LADSPA_HINT_DEFAULT_MASK) {
214 case LADSPA_HINT_DEFAULT_MINIMUM:
215 *control->def = lower_bound;
216 break;
217 case LADSPA_HINT_DEFAULT_LOW:
218 *control->def = lower_bound * 0.75 + upper_bound * 0.25;
219 break;
220 case LADSPA_HINT_DEFAULT_MIDDLE:
221 *control->def = lower_bound * 0.5 + upper_bound * 0.5;
222 break;
223 case LADSPA_HINT_DEFAULT_HIGH:
224 *control->def = lower_bound * 0.25 + upper_bound * 0.75;
225 break;
226 case LADSPA_HINT_DEFAULT_MAXIMUM:
227 *control->def = upper_bound;
228 break;
229 case LADSPA_HINT_DEFAULT_0:
230 *control->def = 0.0;
231 break;
232 case LADSPA_HINT_DEFAULT_1:
233 *control->def = 1.0;
234 break;
235 case LADSPA_HINT_DEFAULT_100:
236 *control->def = 100.0;
237 break;
238 case LADSPA_HINT_DEFAULT_440:
239 *control->def = 440.0;
240 break;
241 default:
242 fprintf(stderr, "default not found\n");
243 free(control->def), control->def = NULL;
246 else
247 control->def = NULL;
249 /* Check the default */
250 if (control->def) {
251 if (*control->def < control->min) {
252 fprintf(stderr, "default smaller than the minimum\n");
253 *control->def = control->min;
255 if (*control->def > control->max) {
256 fprintf(stderr, "default greater than the maximum\n");
257 *control->def = control->max;
261 /* control->inc & Overrides */
262 if (LADSPA_IS_HINT_TOGGLED(descriptor)) {
263 control->min = 0.0;
264 control->max = 1.0;
265 control->inc.fine = 1.0;
266 control->inc.coarse = 1.0;
267 control->type = JACKSPA_TOGGLE;
268 if (control->def) *control->def = nearbyintf(*control->def);
270 else if (LADSPA_IS_HINT_INTEGER(descriptor)) {
271 control->min = nearbyintf(control->min);
272 control->max = nearbyintf(control->max);
273 control->inc.fine = 1.0;
274 control->inc.coarse = 1.0;
275 control->type = JACKSPA_INT;
276 if (control->def) *control->def = nearbyintf(*control->def);
278 else {
279 control->inc.fine = (control->max - control->min) / 500;
280 control->inc.coarse = (control->max - control->min) / 50;
281 control->type = JACKSPA_FLOAT;
284 /* Initial config */
285 if (control_set_init(&init, ctrl, control) < 0)
286 return (fprintf(stderr, "invalid initial value given\n"), 1);
287 if (init.with_min)
288 control->min = init.min;
289 if (init.with_max)
290 control->max = init.max;
291 if (init.with_def) {
292 if (!control->def) {
293 control->def = (LADSPA_Data *)malloc(sizeof(LADSPA_Data));
294 if (!control->def)
295 return (fprintf(stderr, "memory allocation error\n"), 1);
297 *control->def = init.def;
300 /* control->sel, control->val */
301 if (control->def)
302 control->sel = *control->def;
303 else
304 control->sel = control->min;
305 if (init.with_ini)
306 *control->val = init.ini;
307 else
308 *control->val = control->sel;
310 return 0;
313 int control_buildall(unsigned long *count, controls_t *controls, state_t *state)
315 int rc = 0;
316 unsigned long p, c; /* loop variables for ports */
318 *count = state->num_control_ports;
319 *controls = (controls_t)calloc(sizeof(control_t *), (size_t)*count);
320 if (!*controls)
321 return (fprintf(stderr, "memory allocation error\n"), 1);
323 for (p = 0, c = 0; p < state->descriptor->PortCount; p++)
324 if ( LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[p]) &&
325 LADSPA_IS_PORT_CONTROL(state->descriptor->PortDescriptors[p]) )
327 (*controls)[c] = (control_t *)malloc(sizeof(control_t));
328 if (!(*controls)[c])
329 return (fprintf(stderr, "memory allocation error\n"), 1);
330 if (control_init((*controls)[c], state, p, c))
331 rc = 1;
332 c++;
335 return rc;
338 void control_cleanupall(unsigned long count, controls_t *controls)
340 while (count) free((*controls)[--count]);
341 free(*controls);