source: roaraudio/plugins/universal/filter-slfi-calc.c @ 6019:24c5f5131366

Last change on this file since 6019:24c5f5131366 was 6019:24c5f5131366, checked in by phi, 10 years ago

added SLFI filter 'calc'

File size: 9.7 KB
Line 
1//filter-slfi-calc.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012-2014
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include <roaraudio.h>
27#include <libroarlight/libroarlight.h>
28
29#define MAX_CHANNELS_IN 8
30
31enum slfi_calctype {
32 CT_NULL = 0,
33 CT_ADD,
34 CT_SUB,
35 CT_MUL,
36 CT_DIV,
37 CT_MOD,
38 CT_LOG,
39 CT_EXP,
40 CT_SQRT,
41 CT_POW,
42 CT_SUM,  // sum of all samples
43 CT_DXDT  // dx/dt.
44};
45
46enum slfi_numbersystem {
47 NS_AUTO = 0,
48 NS_CLIP,
49 NS_SCALE
50};
51
52// flags:
53#define CF_NONE              0x00000000U
54#define CF_I                 0x00000001U
55#define CF_ABS               0x00000002U
56
57struct slfi_calc {
58 enum slfi_calctype ct;
59 enum slfi_numbersystem ns;
60 uint32_t flags;
61 int_least32_t i; // i-flag register
62 int_least32_t c; // register to store inter-interval values.
63 ssize_t channel_out;
64 ssize_t channel_in[MAX_CHANNELS_IN];
65 ssize_t channel_in_num;
66};
67
68static inline void __init_calc(struct slfi_calc * calc) {
69 size_t i;
70
71 memset(calc, 0, sizeof(*calc));
72
73 calc->ct = CT_NULL;
74 calc->ns = NS_AUTO;
75 calc->flags = CF_NONE;
76 calc->i = 0;
77 calc->c = 0;
78 calc->channel_out = -1;
79 calc->channel_in_num = 0;
80
81 for (i = 0; i < MAX_CHANNELS_IN; i++)
82  calc->channel_in[i] = -1;
83}
84
85static int __push_calc(const struct slfi_calc * calc, struct slfi_calc ** array, size_t * arraylen, size_t * arrayptr) {
86 struct slfi_calc * new;
87 int err;
88 size_t i;
89
90 if ( *arrayptr == *arraylen ) {
91  new = roar_mm_realloc(*array, sizeof(struct slfi_calc)*(*arraylen + 8));
92  err = roar_error;
93  if ( new == NULL ) {
94   roar_mm_free(array);
95   roar_err_set(err);
96   *array = NULL;
97   *arraylen = 0;
98   *arrayptr = 0;
99   return -1;
100  }
101  for (i = *arrayptr + 1; i < (*arrayptr + 8); i++)
102   __init_calc(&(new[i]));
103  *array = new;
104  *arraylen += 8;
105 }
106
107 (*array)[*arrayptr] = *calc;
108 (*arrayptr)++;
109 return 0;
110}
111
112static inline enum slfi_calctype __parse_calc_ct(const char * str, const char ** flags) {
113 const struct {
114  const char * name;
115  const enum slfi_calctype ct;
116 } *p, __table[] = {
117  {"NULL", CT_NULL},
118  {"add", CT_ADD},
119  {"sub", CT_SUB},
120  {"mul", CT_MUL},
121  {"div", CT_DIV},
122  {"mod", CT_MOD},
123  {"log", CT_LOG},
124  {"exp", CT_EXP},
125  {"sqrt", CT_SQRT},
126  {"pow", CT_POW},
127  {"sum", CT_SUM},
128  {"dxdt", CT_DXDT},
129  {NULL, CT_NULL} // list terminator.
130 };
131 ssize_t len;
132
133 for (p = __table; p->name != NULL; p++) {
134  len = roar_mm_strlen(p->name);
135  if ( !strncasecmp(str, p->name, len) ) {
136   *flags = str+len;
137   return p->ct;
138  }
139 }
140 *flags = NULL;
141 return CT_NULL;
142}
143
144static inline const struct slfi_calc * __parse_calc(const char * key, const char * value) {
145 static struct slfi_calc calc;
146 const char * flags;
147 char * valbuf, * cur, * saveptr;
148 size_t i;
149 int found_error = 0;
150
151 if ( !*value )
152  return NULL;
153
154 __init_calc(&calc);
155
156/*
157 calc->i = 0;
158 calc->channel_out = -1;
159*/
160
161 calc.ct = __parse_calc_ct(key, &flags);
162 if ( calc.ct == CT_NULL )
163  return NULL;
164
165 if ( flags != NULL ) {
166  for (; *flags; flags++) {
167   switch (*flags) {
168    // normal flags:
169    case 'i': calc.flags |= CF_I; break;
170    case 'a': calc.flags |= CF_ABS; break;
171
172    // system:
173    case 's': calc.ns = NS_SCALE; break;
174    case 'c': calc.ns = NS_CLIP; break;
175    default:
176     ROAR_ERR("__parse_calc(key='%s', value='%s'): Unknown flag: %c", key, value, *flags);
177     return NULL;
178   }
179  }
180 }
181
182 valbuf = roar_mm_strdup(value);
183 if ( valbuf == NULL )
184  return NULL;
185 
186 cur = roar_mm_strtok_r(valbuf, ":", &saveptr);
187
188 calc.channel_out = atoi(cur);
189
190 i = 0;
191 while ((cur = roar_mm_strtok_r(NULL, ":", &saveptr)) != NULL) {
192  calc.channel_in[i] = atoi(cur);
193  calc.channel_in_num++;
194  if ( calc.channel_in[i] < 0 || (i+1) == MAX_CHANNELS_IN ) {
195   found_error = 1;
196   break;
197  }
198  i++;
199 }
200
201 roar_mm_free(valbuf);
202
203 if ( found_error )
204  return NULL;
205
206 if ( calc.flags & CF_I ) {
207  for (i = 1; i < MAX_CHANNELS_IN; i++) {
208   if ( calc.channel_in[i] == -1 ) {
209    calc.i = calc.channel_in[i-1];
210    calc.channel_in[i-1] = -1;
211    calc.channel_in_num--;
212    break;
213   }
214  }
215 }
216
217 if ( calc.ct == CT_NULL || calc.ns == NS_AUTO || calc.channel_out < 0 )
218  return NULL;
219 return &calc;
220}
221
222static int __init(struct roar_slfi_inst * inst, const struct roar_keyval * para, ssize_t paralen) {
223 const struct slfi_calc * calc;
224 struct slfi_calc * array = NULL;
225 size_t arraylen = 0;
226 size_t arrayptr = 0;
227 const struct roar_keyval * kv;
228 ssize_t i;
229
230 for (i = 0; i < paralen; i++) {
231  kv = &(para[i]);
232  if ( kv->key == NULL || kv->value == NULL )
233   continue;
234
235  if ( (calc = __parse_calc(kv->key, kv->value)) != NULL ) {
236   if ( __push_calc(calc, &array, &arraylen, &arrayptr) == -1 ) {
237    ROAR_ERR("__init(*): Can not add more calculations: %s", roar_errorstring);
238    return -1;
239   }
240//  } else if ( !strcmp(kv->key, "") ) {
241  } else {
242   ROAR_WARN("__init(*): Unknown parameter: %s", kv->key);
243  }
244 }
245
246 inst->userdata = array;
247 return 0;
248}
249
250static inline int_least32_t __calc_step(int_least32_t val, uint8_t in, enum slfi_calctype ct, enum slfi_numbersystem ns) {
251 switch (ct) {
252  case CT_SUM:
253  case CT_ADD: val += in; break;
254  case CT_SUB: val -= in; break;
255  case CT_MUL: val *= in; break;
256  case CT_DIV: val /= in; break;
257  case CT_MOD: val %= in; break;
258  default:
259    roar_panic(ROAR_FATAL_ERROR_CPU_FAILURE, NULL); // we should never reach this point at all.
260   break;
261 }
262
263 switch (ns) {
264  case NS_AUTO: break;
265  case NS_CLIP:
266    if ( val > 255 ) {
267     val = 255;
268    } else if ( val < 0 ) {
269     val = 0;
270    }
271   break;
272  case NS_SCALE:
273    switch (ct) {
274     case CT_MUL:
275       val /= 255;
276      break;
277     default: /* NOOPs */; break;
278    }
279   break;
280 }
281
282 return val;
283}
284
285static inline void __calc(struct slfi_calc * calc, uint8_t * universe, ssize_t size_of_universe, int32_t usecspassed) {
286 int_least32_t val = 0;
287 ssize_t i;
288
289 (void)usecspassed; // needed for CT_DXDT.
290
291 if ( calc->channel_out >= size_of_universe ) {
292  ROAR_WARN("__calc(*): Output channel outside universe!");
293  return;
294 }
295
296 if ( calc->channel_in_num ) {
297  if ( calc->channel_in[0] >= size_of_universe ) {
298   ROAR_WARN("__calc(*): Initial Input channel outside universe!");
299   return;
300  }
301  val = universe[calc->channel_in[0]];
302 } else if ( calc->flags & CF_I ) {
303  val = calc->i;
304 }
305
306 switch (calc->ct) {
307  case CT_NULL: return; break;
308  case CT_LOG:
309  case CT_SQRT:
310  case CT_POW:
311  case CT_DXDT:
312    ROAR_ERR("__calc(*): Operation not supported");
313    return;
314   break;
315  case CT_SUM:
316    val += calc->c;
317  case CT_ADD:
318  case CT_SUB:
319  case CT_MUL:
320  case CT_DIV:
321  case CT_MOD:
322  case CT_EXP:
323    for (i = 1; i < calc->channel_in_num; i++) {
324     if ( calc->channel_in[i] >= size_of_universe ) {
325      ROAR_WARN("__calc(*): Input channel outside universe!");
326      return;
327     }
328     val = __calc_step(val, universe[calc->channel_in[i]], calc->ct, calc->ns);
329    }
330
331    if ( calc->channel_in_num && calc->flags & CF_I ) {
332     ROAR_DBG("__calc(*): calc->channel_in_num=%i, calc->i=%i", (int)calc->channel_in_num, (int)calc->i);
333     val = __calc_step(val, calc->i, calc->ct, calc->ns);
334    }
335   break;
336 }
337
338 switch (calc->ct) {
339  case CT_NULL: break;
340  case CT_SUM:
341    calc->c = val;
342   break;
343  case CT_ADD:
344  case CT_SUB:
345    if ( calc->ns == NS_SCALE )
346     val /= calc->channel_in_num + (calc->flags & CF_I ? 1 : 0);
347   break;
348  // NOOPs:
349  case CT_MUL:
350  case CT_DIV:
351  case CT_MOD:
352  case CT_EXP:
353   break;
354  default:
355    ROAR_ERR("__calc(*): Operation not supported");
356   break;
357 }
358
359 if ( calc->flags & CF_ABS )
360  val = abs(val);
361
362 universe[calc->channel_out] = val;
363}
364
365static int __update(struct roar_slfi_inst * inst, uint8_t * universe, ssize_t size_of_universe, int32_t usecspassed, const uint8_t * event, size_t eventlen) {
366 struct slfi_calc * self = inst->userdata;
367
368 (void)event, (void)eventlen;
369
370 while (self->channel_out != -1) {
371  __calc(self, universe, size_of_universe, usecspassed);
372  self++;
373 }
374
375 return 0;
376}
377
378static const struct roar_slfi_filter filter[1] = {
379 {
380  .name = "calc",
381  .description = "Calc SLFI filter",
382  .flags = ROAR_SLFI_FLAG_ON_UPDATE,
383  .init = __init,
384  .uninit = NULL,
385  .update = __update,
386  .ctl = NULL
387 }
388};
389
390ROAR_DL_PLUGIN_REG_SLFI(filter);
391
392// This is the plugin control block.
393ROAR_DL_PLUGIN_START(filter_slfi_calc) {
394 // Here we set the name and vendor of our plugin.
395 // If you have no Vendor ID you need to use ROAR_DL_PLUGIN_META_PRODUCT_NV().
396 ROAR_DL_PLUGIN_META_PRODUCT_NIV("filter-slfi-calc", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
397
398 // This sets the version of your plugin.
399 ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
400
401 // This sets the license of your plugin.
402 // If there is no tag for the license you use you can just
403 // use ROAR_DL_PLUGIN_META_LICENSE().
404 ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
405
406 // This sets the author and contact infos.
407 // There are several other macros to do this with other parameters.
408 // See ROAR_DL_PLUGIN_META_CONTACT*() in the header or documentation.
409 ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
410
411 // This sets the description for your plugin.
412 ROAR_DL_PLUGIN_META_DESC("This plugin calculates values of channels.");
413
414 // Load filters.
415 ROAR_DL_PLUGIN_REG_FNFUNC(ROAR_DL_FN_FILTER);
416
417// This is the end of the control block.
418} ROAR_DL_PLUGIN_END
419
420//ll
Note: See TracBrowser for help on using the repository browser.