Index: plugins/universal/Makefile
===================================================================
--- plugins/universal/Makefile	(revision 5996)
+++ plugins/universal/Makefile	(revision 6004)
@@ -3,5 +3,5 @@
 
 TARGETS_PROTO=echo daytime discard http
-TARGETS_SLFI=helloworld chain alternative static file2filter channel2event trigger
+TARGETS_SLFI=helloworld chain alternative static file2filter channel2event trigger map
 TARGETS_SERVICE=about
 TARGETS_MISC=plugin-info helloworld debug-notify tic-tac-toe
Index: plugins/universal/filter-slfi-map.c
===================================================================
--- plugins/universal/filter-slfi-map.c	(revision 6004)
+++ plugins/universal/filter-slfi-map.c	(revision 6004)
@@ -0,0 +1,248 @@
+//filter-slfi-map.c:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012-2014
+ *
+ *  This file is part of roard a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  RoarAudio is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <roaraudio.h>
+#include <libroarlight/libroarlight.h>
+
+#define MAX_EVENTS 8
+#define MAX_MAPS   16
+
+enum slfi_maptype {
+ // copy=start-end:dest
+ MT_COPY,
+ // swap=start:dest
+ MT_SWAP,
+ // inverse=start
+ MT_INVERSE
+};
+
+struct slfi_map {
+ enum slfi_maptype mt;
+ ssize_t src_start;
+ ssize_t src_end;
+ ssize_t dst_start;
+};
+
+struct slfi_mapinst {
+ uint8_t event[MAX_EVENTS][2];
+ size_t event_len;
+ struct slfi_map map[MAX_MAPS];
+ size_t map_len;
+};
+
+static struct slfi_map __parse_map(const char * type, const char * str) {
+ struct slfi_map map = {MT_COPY, -1, -1, -1};
+ char * buf = roar_mm_strdup(str);
+ char * value;
+ char * end;
+
+ if ( buf == NULL ) {
+  ROAR_ERR("__parse_map(*): Can not allocate memory. Bad.");
+  return map;
+ }
+
+ if ( !strcmp(type, "copy") || !strcmp(type, "move") || !strcmp(type, "mov") ) {
+  map.mt = MT_COPY;
+ } else if ( !strcmp(type, "swap") ) {
+  map.mt = MT_SWAP;
+ } else if ( !strcmp(type, "inverse") || !strcmp(type, "inv") ) {
+  map.mt = MT_INVERSE;
+ } else {
+  ROAR_ERR("__parse_map(*): Unknown map type: %s", type);
+  return map;
+ }
+
+ value = strstr(buf, ":");
+ if ( value != NULL ) {
+  *value = 0;
+  value++;
+  map.dst_start = atoi(value);
+  if ( map.dst_start < 0 )
+   map.dst_start = 0;
+ }
+
+ end = strstr(buf, "-");
+ if ( end != NULL ) {
+  *end = 0;
+  end++;
+ }
+
+ map.src_start = atoi(buf);
+ if ( map.src_start < 0 )
+  map.src_start = 0;
+
+ if ( end != NULL ) {
+  map.src_end = atoi(end);
+  if ( map.src_end < map.src_start )
+   map.src_end = map.src_start;
+ }
+
+ roar_mm_free(buf);
+
+ if ( map.mt == MT_COPY && map.src_end == -1 )
+  map.src_end = map.src_start;
+
+ if ( map.mt != MT_INVERSE && map.dst_start == -1 ) {
+  ROAR_ERR("__parse_map(*): Bad mapping: no destination channel(s) given.");
+  map.src_start = -1;
+  return map;
+ }
+
+ return map;
+}
+
+static int __init(struct roar_slfi_inst * inst, const struct roar_keyval * para, ssize_t paralen) {
+ struct slfi_mapinst * self = roar_mm_malloc(sizeof(struct slfi_mapinst));
+ const struct roar_keyval * kv;
+ ssize_t i;
+
+ if ( self == NULL )
+  return -1;
+
+ memset(self, 0, sizeof(*self));
+ inst->userdata = self;
+
+ for (i = 0; i < paralen; i++) {
+  kv = &(para[i]);
+  if ( kv->key == NULL || kv->value == NULL )
+   continue;
+
+  if ( !strcmp(kv->key, "event") ) {
+   ROAR_WARN("__init(*): Can not add event: Not Supported");
+/*
+   if ( self->event_len == MAX_EVENTS ) {
+    ROAR_WARN("__init(*): Can not add (list is full) event: %s", kv->value);
+    continue;
+   }
+   self->event[self->event_len++] = roar_roardmx_str2event(kv->value);
+*/
+  } else if ( !strcmp(kv->key, "copy") || !strcmp(kv->key, "move") || !strcmp(kv->key, "mov") ||
+              !strcmp(kv->key, "swap") ||
+              !strcmp(kv->key, "inverse") || !strcmp(kv->key, "inv") ) {
+   if ( self->map_len == MAX_MAPS ) {
+    ROAR_WARN("__init(*): Can not add (list is full) map: %s=%s", kv->key, kv->value);
+    continue;
+   }
+   self->map[self->map_len++] = __parse_map(kv->key, kv->value);
+  } else {
+   ROAR_WARN("__init(*): Unknown parameter: %s", kv->key);
+  }
+ }
+
+ return 0;
+}
+
+static 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) {
+ struct slfi_mapinst * self = inst->userdata;
+ const struct slfi_map * map;
+ size_t i;
+ ssize_t j;
+ uint8_t tmp;
+
+ (void)inst, (void)usecspassed, (void)event, (void)eventlen;
+
+ for (i = 0; i < self->event_len; i++) {
+  for (j = 0; j < (ssize_t)eventlen; j++) {
+   if ( self->event[i][0] == event[j] ) {
+    roar_slfi_event_add(inst, self->event[i][1]);
+   }
+  }
+ }
+
+ for (i = 0; i < self->map_len; i++) {
+  map = &(self->map[i]);
+
+  if ( map->src_start >= size_of_universe || map->src_end >= size_of_universe || map->dst_start >= size_of_universe ) {
+   ROAR_WARN("__update(*): Universe too small for filter.");
+   return 0;
+  }
+
+  if ( map->src_end != -1 && (map->dst_start + map->src_end - map->src_start) >= size_of_universe ) {
+   ROAR_WARN("__update(*): Universe too small for filter.");
+   return 0;
+  }
+
+  switch (map->mt) {
+   case MT_COPY:
+     memcpy(&(universe[map->dst_start]), &(universe[map->src_start]), map->src_end - map->src_start + 1);
+    break;
+   case MT_SWAP:
+     tmp = universe[map->src_start];
+     universe[map->src_start] = universe[map->dst_start];
+     universe[map->dst_start] = tmp;
+    break;
+   case MT_INVERSE:
+     for (j = map->dst_start; j <= map->src_end; j++)
+      universe[j] = 255 - universe[j];
+    break;
+  }
+ }
+
+ return 0;
+}
+
+static const struct roar_slfi_filter filter[1] = {
+ {
+  .name = "map",
+  .description = "Map SLFI filter",
+  .flags = ROAR_SLFI_FLAG_ON_UPDATE,
+  .init = __init,
+  .uninit = NULL,
+  .update = __update,
+  .ctl = NULL
+ }
+};
+
+ROAR_DL_PLUGIN_REG_SLFI(filter);
+
+// This is the plugin control block.
+ROAR_DL_PLUGIN_START(filter_slfi_map) {
+ // Here we set the name and vendor of our plugin.
+ // If you have no Vendor ID you need to use ROAR_DL_PLUGIN_META_PRODUCT_NV().
+ ROAR_DL_PLUGIN_META_PRODUCT_NIV("filter-slfi-map", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
+
+ // This sets the version of your plugin.
+ ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
+
+ // This sets the license of your plugin.
+ // If there is no tag for the license you use you can just
+ // use ROAR_DL_PLUGIN_META_LICENSE().
+ ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
+
+ // This sets the author and contact infos.
+ // There are several other macros to do this with other parameters.
+ // See ROAR_DL_PLUGIN_META_CONTACT*() in the header or documentation.
+ ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
+
+ // This sets the description for your plugin.
+ ROAR_DL_PLUGIN_META_DESC("This plugin maps values between channels.");
+
+ // Load filters.
+ ROAR_DL_PLUGIN_REG_FNFUNC(ROAR_DL_FN_FILTER);
+
+// This is the end of the control block.
+} ROAR_DL_PLUGIN_END
+
+//ll
