Index: plugins/roard/Makefile
===================================================================
--- plugins/roard/Makefile	(revision 5709)
+++ plugins/roard/Makefile	(revision 5711)
@@ -2,5 +2,5 @@
 include ../../Makefile.inc
 
-TARGETS=protocol-irc$(SHARED_SUFFIX) listenpty$(SHARED_SUFFIX) dmx-random$(SHARED_SUFFIX)
+TARGETS=protocol-irc$(SHARED_SUFFIX) listenpty$(SHARED_SUFFIX) dmx-random$(SHARED_SUFFIX) dmx-waveform$(SHARED_SUFFIX)
 
 #DEFINES        = -DDEBUG
Index: plugins/roard/dmx-waveform.c
===================================================================
--- plugins/roard/dmx-waveform.c	(revision 5711)
+++ plugins/roard/dmx-waveform.c	(revision 5711)
@@ -0,0 +1,209 @@
+//dmx-waveform.c:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2012
+ *
+ *  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 <roard/include/roard.h>
+
+#define SAMPLES_PER_TICK 2
+
+struct state {
+ size_t startaddr;
+ size_t len;
+ int stream;
+ struct roar_stream_server * ss;
+};
+
+static struct state * g_state;
+static struct state   g_state_init = {
+ .startaddr =  0,
+ .len       =  4,
+ .stream    = -1,
+ .ss        = NULL
+};
+
+static int16_t __get_chanval(struct state * self, size_t c, int pos) {
+ int16_t ret = 0;
+
+ if ( pos ) {
+  ret = light_dmxchannel_get(self->startaddr + c);
+ } else {
+  if ( self->len & 1 ) {
+   ret = light_dmxchannel_get(self->startaddr + self->len - 1);
+  } else {
+   ret = light_dmxchannel_get(self->startaddr + self->len/2 + c);
+  }
+ }
+
+ if ( !pos )
+  ret *= -1;
+
+ ret *= 127;
+
+ ROAR_DBG("__get_chanval(self=%p, c=%lu, pos=%i) = %i", self, (long unsigned int)c, pos, (int)ret);
+ return ret;
+}
+
+static ssize_t _vio_read   (struct roar_vio_calls * vio, void *buf, size_t count) {
+ struct state * self = vio->inst;
+ ssize_t samplesize = roar_info2samplesize(&(ROAR_STREAM(self->ss)->info)) / 8;
+ ssize_t framesize = roar_info2framesize(&(ROAR_STREAM(self->ss)->info)) / 8;
+ size_t i, c;
+ int16_t * samp = buf;
+ size_t zeros = 0;
+
+ ROAR_DBG("_vio_read(vio=%p, buf=%p, count=%lu) = ?", vio, buf, (long unsigned int)count);
+
+ if ( count % framesize ) {
+  roar_err_set(ROAR_ERROR_RANGE);
+  return -1;
+ }
+
+ framesize *= 2;
+
+ if ( count % framesize ) {
+  zeros = count % framesize;
+  count -= zeros;
+  memset(buf+count, 0, zeros);
+ }
+
+ ROAR_DBG("_vio_read(vio=%p, buf=%p, count=%lu) = ?", vio, buf, (long unsigned int)count);
+
+ for (i = 0; i < count/samplesize;) {
+  for (c = 0; c < ROAR_STREAM(self->ss)->info.channels; c++, i++)
+   samp[i] = __get_chanval(self, c, 1);
+  for (c = 0; c < ROAR_STREAM(self->ss)->info.channels; c++, i++)
+   samp[i] = __get_chanval(self, c, 0);
+ }
+
+ ROAR_DBG("_vio_read(vio=%p, buf=%p, count=%lu) = %lu", vio, buf, (long unsigned int)count, (long unsigned int)count);
+
+ return count + zeros;
+}
+
+static int     _vio_ctl     (struct roar_vio_calls * vio, roar_vio_ctl_t cmd, void * data) {
+ (void)vio, (void)data;
+
+ if ( cmd == ROAR_VIO_CTL_NONBLOCK )
+  return 0;
+
+ roar_err_set(ROAR_ERROR_BADRQC);
+ return -1;
+}
+
+static int     _vio_close   (struct roar_vio_calls * vio) {
+ struct state * self = vio->inst;
+ self->stream = -1;
+ self->ss     = NULL;
+ return 0;
+}
+
+static int _init  (struct roar_dl_librarypara * para) {
+ struct roar_keyval * p;
+
+ p = roar_keyval_lookup(para->argv, "startaddr", para->argc, 1);
+ if ( p != NULL && p->value != NULL )
+  g_state->startaddr = atoi(p->value);
+
+ p = roar_keyval_lookup(para->argv, "len", para->argc, 1);
+ if ( p != NULL && p->value != NULL )
+  g_state->len = atoi(p->value);
+
+ if ((g_state->stream = streams_new()) == -1 )
+  return -1;
+
+ if ( streams_get(g_state->stream, &(g_state->ss)) == -1 ) {
+  streams_delete(g_state->stream);
+  return -1;
+ }
+
+ if ( streams_set_dir(g_state->stream, ROAR_DIR_PLAY, 1) == -1 ) {
+  streams_delete(g_state->stream);
+  return -1;
+ }
+
+ if ( streams_set_name(g_state->stream, "DMX to Waveform bridge") == -1 ) {
+  streams_delete(g_state->stream);
+  return -1;
+ }
+
+ ROAR_STREAM(g_state->ss)->info = *g_sa;
+ if ( g_state->len & 1 ) {
+  ROAR_STREAM(g_state->ss)->info.channels = g_state->len - 1;
+ } else {
+  ROAR_STREAM(g_state->ss)->info.channels = g_state->len / 2;
+ }
+ ROAR_STREAM(g_state->ss)->info.bits = 16;
+
+ roar_vio_clear_calls(&(g_state->ss->vio));
+ g_state->ss->vio.inst  = g_state;
+ g_state->ss->vio.read  = _vio_read;
+ g_state->ss->vio.ctl   = _vio_ctl;
+ g_state->ss->vio.close = _vio_close;
+
+ streams_set_fh(g_state->stream, -2);
+
+ client_stream_add(g_self_client, g_state->stream);
+
+ return 0;
+}
+
+static int _free  (struct roar_dl_librarypara * para) {
+ (void)para;
+
+ if ( g_state->stream == -1 )
+  return 0;
+
+ if ( streams_reset_flag(g_state->stream, ROAR_FLAG_IMMUTABLE) == -1 )
+  return -1;
+
+ if ( streams_delete(g_state->stream) == -1 )
+  return -1;
+
+ g_state->stream = -1;
+
+ return 0;
+}
+
+static struct roar_dl_appsched sched = {
+ .init   = _init,
+ .free   = _free,
+ .update = NULL,
+ .tick   = NULL,
+ .wait   = NULL
+};
+
+ROAR_DL_PLUGIN_START(dmx_waveform) {
+ ROARD_DL_CHECK_VERSIONS();
+
+ ROAR_DL_PLUGIN_META_PRODUCT_NIV("dmx-waveform", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
+ ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
+ ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
+ ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
+ ROAR_DL_PLUGIN_META_DESC("This renders DMX channels as waveform signals. This is helpful to drive LEDs with cheap PWM based sound devices.");
+
+ ROAR_DL_PLUGIN_REG_GLOBAL_DATA(g_state, g_state_init);
+ ROAR_DL_PLUGIN_REG_APPSCHED(&sched); 
+} ROAR_DL_PLUGIN_END
+
+//ll
