source: roaraudio/roard/light.c @ 5982:c38f275b38ae

Last change on this file since 5982:c38f275b38ae was 5982:c38f275b38ae, checked in by phi, 10 years ago

Added support to load light control filters into roard.

File size: 9.3 KB
RevLine 
[1816]1//light.c:
2
3/*
[5961]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2014
[1816]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[1816]23 *
24 */
25
26#include "roard.h"
27
[2495]28#ifndef ROAR_WITHOUT_DCOMP_LIGHT
29
[5194]30// declared 'extern'
31struct light_state g_light_state;
32struct light_mixer g_light_mixer;
33// //
34
[5916]35static inline void __set_channel(size_t index, uint8_t val) {
[5706]36 g_light_state.changes[index] |= g_light_state.state[index] ^ val;
37 g_light_state.state[index]    =                              val;
38}
39
[5210]40int light_init  (uint32_t channels) {
[2959]41 struct roar_stream_server * ss;
[3215]42 int i;
[1818]43
[1819]44 g_light_state.channels = 0;
45
[5210]46 if ( channels == 0 || channels > ((uint32_t)512UL*(uint32_t)512UL) ) /* unrealstic values */
[1922]47  return -1;
48
[4957]49 if ( (g_light_state.state = roar_mm_malloc(channels)) == NULL ) {
[1818]50  return -1;
51 }
52
[4957]53 if ( (g_light_state.changes = roar_mm_malloc(channels)) == NULL ) {
54  roar_mm_free(g_light_state.state);
[1966]55  return -1;
56 }
57
[5980]58 if ( (g_light_state.output = roar_mm_malloc(channels)) == NULL ) {
59  roar_mm_free(g_light_state.state);
60  roar_mm_free(g_light_state.changes);
61  return -1;
62 }
63
64 if ( (g_light_state.outputchanges = roar_mm_malloc(channels)) == NULL ) {
65  roar_mm_free(g_light_state.state);
66  roar_mm_free(g_light_state.changes);
67  roar_mm_free(g_light_state.output);
68  return -1;
69 }
70
[1818]71 g_light_state.channels = channels;
[5982]72 g_light_state.filter   = NULL;
[1818]73
[2959]74 if ( (g_light_mixer.stream = add_mixer(ROAR_SUBSYS_LIGHT, _MIXER_NAME("Light Control"), &ss)) == -1 ) {
[4957]75  roar_mm_free(g_light_state.state);
[2944]76  return -1;
77 }
78
[2959]79 ROAR_STREAM(ss)->info.codec = ROAR_CODEC_DMX512;
80 ROAR_STREAM(ss)->info.bits  = ROAR_LIGHT_BITS;
81 ROAR_STREAM(ss)->info.rate  = ROAR_OUTPUT_CFREQ;
82
[3215]83 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
84  if ( g_streams[i] != NULL ) {
85   if ( streams_get_subsys(i) == ROAR_SUBSYS_LIGHT ) {
86    streams_set_mixer_stream(i, g_light_mixer.stream);
87   }
88  }
89 }
90
[1818]91 return light_reset();
92}
93
94int light_free  (void) {
[5982]95 if ( g_light_state.filter != NULL ) {
96  roar_slfi_unref(g_light_state.filter);
97 }
98
[1818]99 if ( g_light_state.state != NULL ) {
[4957]100  roar_mm_free(g_light_state.state);
[1818]101 }
102
[1966]103 if ( g_light_state.changes != NULL ) {
[4957]104  roar_mm_free(g_light_state.changes);
[1966]105 }
106
[5980]107 if ( g_light_state.output != NULL ) {
[5981]108  roar_mm_free(g_light_state.output);
[5980]109 }
110
111 if ( g_light_state.outputchanges != NULL ) {
[5981]112  roar_mm_free(g_light_state.outputchanges);
[5980]113 }
114
[1818]115 g_light_state.channels = 0;
116
117 return 0;
118}
119
120int light_reset (void) {
121 if ( g_light_state.channels == 0 )
122  return 0;
123
124 if ( g_light_state.state == NULL )
125  return -1;
126
[1966]127 if ( g_light_state.changes == NULL )
128  return -1;
129
[5980]130 memset(g_light_state.state,         0, g_light_state.channels);
131 memset(g_light_state.changes,       0, g_light_state.channels);
132 memset(g_light_state.output,        0, g_light_state.channels);
133 memset(g_light_state.outputchanges, 0, g_light_state.channels);
134 memset(g_light_state.events,        0, sizeof(g_light_state.events));
[5920]135
136 g_light_state.eventsqueuelen = 0;
[1966]137
138 return 0;
139}
140
[5980]141// called at end of mainloop.
[1966]142int light_reinit(void) {
143 if ( g_light_state.changes == NULL )
144  return -1;
145
146 memset(g_light_state.changes, 0, g_light_state.channels);
[5920]147 memset(g_light_state.events,  0, sizeof(g_light_state.events));
148
149 g_light_state.eventsqueuelen = 0;
[1818]150
151 return 0;
152}
153
[5980]154// called at mid of mainloop.
[1818]155int light_update(void) {
[5980]156 uint8_t * tmp;
157 unsigned int c;
158
159 // swap buffers:
160 // after that step we have the old values in outputchanges and output is a fresh buffer.
161 tmp = g_light_state.outputchanges;
162 g_light_state.outputchanges = g_light_state.output;
163 g_light_state.output = tmp;
164
165 // copy data for filters:
166 memcpy(g_light_state.output, g_light_state.state, g_light_state.channels);
167
168 // TODO: next run filters
[5982]169 if ( g_light_state.filter != NULL ) {
170  if ( roar_slfi_update(g_light_state.filter,
171                        g_light_state.output, g_light_state.channels,
172                        ((int32_t)1000000LU)/(int32_t)ROAR_OUTPUT_CFREQ,
173                        g_light_state.events, g_light_state.eventsqueuelen) == -1 ) {
174   ROAR_WARN("light_update(void): Can not run SLFI filter: %s", roar_errorstring);
175  }
176 }
[5980]177
178 // calculate diffrence:
179 // after this step we have only teh changes in the outputchanges array.
180 for (c = 0; c < g_light_state.channels; c++)
181  g_light_state.outputchanges[c] ^= g_light_state.output[c];
182
[1818]183 return 0;
184}
185
[1821]186int light_check_stream  (int id) {
[1822]187 struct roar_stream        *   s;
188 struct roar_stream_server *  ss;
[1823]189 char buf[512];
[5917]190 int i;
[1822]191
192 if ( g_streams[id] == NULL )
193  return -1;
194
195 ROAR_DBG("light_check_stream(id=%i) = ?", id);
196
197 s = ROAR_STREAM(ss = g_streams[id]);
198
[1823]199 switch (s->info.codec) {
200  case ROAR_CODEC_DMX512:
201    if ( stream_vio_s_read(ss, buf, 512) != 512 ) {
202     streams_delete(id);
203     return -1;
204    }
205
[1967]206    for (i = 0; i < (g_light_state.channels < 512 ? g_light_state.channels : 512); i++) {
[5706]207     __set_channel(i, buf[i]);
[1967]208    }
209//    memcpy(g_light_state.state, buf, g_light_state.channels < 512 ? g_light_state.channels : 512);
[1823]210
[2509]211    s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, 1);
212
[1823]213    return 0;
214   break;
[1965]215  case ROAR_CODEC_ROARDMX:
[2055]216    ROAR_DBG("light_check_stream(id=%i): Codec: RoarDMX", id);
[5917]217    if ( cf_light_roardmx_read(id, ss) == -1 ) {
218     streams_delete(id); // simply drop the client on error.
[1965]219     return -1;
220    }
221   break;
[1823]222  default:
223    streams_delete(id);
224    return -1;
225 }
226
[1821]227 return 0;
228}
229
[5917]230static inline int light_send_stream_dmx512  (int id, struct roar_stream * s, struct roar_stream_server * ss) {
[5918]231 size_t chans = g_light_state.channels;
[5917]232 uint8_t buf[512];
233 register uint8_t * bufptr;
234
235 if ( chans > 512 )
236  chans = 512;
237
238 if ( chans == 512 ) {
[5980]239  bufptr = g_light_state.output;
[5917]240 } else {
241  memset(buf, 0, 512);
[5980]242  memcpy(buf, g_light_state.output, chans);
[5917]243  bufptr = buf;
244 }
245
246 if ( stream_vio_s_write(ss, bufptr, 512) != 512 ) {
247  streams_delete(id);
248  return -1;
249 }
250
251 s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, 1);
252
253 return 0;
254}
255
[1821]256int light_send_stream   (int id) {
[1822]257 struct roar_stream        *   s;
258 struct roar_stream_server *  ss;
259
260 if ( g_streams[id] == NULL )
261  return -1;
262
[1823]263 ROAR_DBG("light_send_stream(id=%i) = ?", id);
[1822]264
265 s = ROAR_STREAM(ss = g_streams[id]);
266
267 switch (s->info.codec) {
268  case ROAR_CODEC_DMX512:
[5917]269    return light_send_stream_dmx512(id, s, ss);
[1822]270   break;
[1968]271  case ROAR_CODEC_ROARDMX:
[5917]272    return cf_light_roardmx_write(id, ss);
[1968]273   break;
[1822]274  default:
275    streams_delete(id);
276    return -1;
277 }
278
[1821]279 return 0;
280}
281
[5982]282int light_filter_load(int primary, const char * name, int autoload, const struct roar_keyval * para, ssize_t paralen) {
283 struct roar_slfi_inst * filter;
284 int ret;
285 int err;
286
287 if ( primary && g_light_state.filter != NULL ) {
288  roar_err_set(ROAR_ERROR_ALREADY);
289  return -1;
290 } else if ( !primary && g_light_state.filter == NULL ) {
291  roar_err_set(ROAR_ERROR_BADSTATE);
292  return -1;
293 }
294
295 filter = roar_slfi_new(name, autoload, para, paralen);
296 if ( filter == NULL )
297  return -1;
298
299 if ( primary ) {
300  g_light_state.filter = filter;
301  return 0;
302 }
303
304 ret = roar_slfi_ctl(g_light_state.filter, ROAR_SLFI_CMD_PUSH, filter);
305 err = roar_error;
306
307 roar_slfi_unref(filter);
308
309 roar_err_set(err);
310 return ret;
311}
312
[5706]313int light_dmxchannel_get(size_t index) {
314 if ( (size_t)g_light_state.channels <= index ) {
315  roar_err_set(ROAR_ERROR_NOENT);
316  return -1;
317 }
318
[5916]319 return (int)(unsigned int)(uint8_t)g_light_state.state[index];
[5706]320}
321
[5916]322int light_dmxchannel_set(size_t index, uint8_t val) {
[5706]323 if ( (size_t)g_light_state.channels <= index ) {
324  roar_err_set(ROAR_ERROR_NOENT);
325  return -1;
326 }
327
328 __set_channel(index, val);
329 return 0;
330}
331
[5935]332ssize_t light_dmxchannel_num(void) {
333 if ( g_light_state.state == NULL ) {
334  roar_err_set(ROAR_ERROR_BADSTATE);
335  return -1;
336 }
337
338 return g_light_state.channels;
339}
340
341int     light_dmxchannel_swap_universe(uint8_t * universe, size_t len) {
342 uint8_t c;
343 size_t i;
344
345 if ( g_light_state.state == NULL ) {
346  roar_err_set(ROAR_ERROR_BADSTATE);
347  return -1;
348 }
349
350 if ( g_light_state.channels != len ) {
351  roar_err_set(ROAR_ERROR_FAULT);
352  return -1;
353 }
354
355 for (i = 0; i < len; i++) {
356  c = g_light_state.state[i];
357  __set_channel(i, universe[i]);
358  universe[i] = c;
359 }
360
361 return 0;
362}
363
[5920]364int light_dmxevent_add(const uint8_t * events, size_t len) {
365 size_t i;
366
367 if ( events == NULL ) {
368  roar_err_set(ROAR_ERROR_FAULT);
369  return -1;
370 }
371
372 if ( len > (sizeof(g_light_state.events) - g_light_state.eventsqueuelen) ) {
373  roar_err_set(ROAR_ERROR_NOSPC);
374  return -1;
375 }
376
377 for (i = 0; i < len; i++) {
378  g_light_state.events[g_light_state.eventsqueuelen++] = events[i];
379  roar_notify_core_emit_simple(ROAR_DATA_DMX512_EVENT, -1, g_light_mixer.stream, ROAR_OT_STREAM, events[i], -1, NULL, -1);
380 }
381
382 return 0;
383}
384
385int light_dmxevent_read(const uint8_t ** events, size_t * len) {
386 if ( events == NULL || len == NULL ) {
387  roar_err_set(ROAR_ERROR_FAULT);
388  return -1;
389 }
390
391 *events = g_light_state.events;
392 *len    = g_light_state.eventsqueuelen;
393
394 return 0;
395}
396
[2495]397#endif
398
[1816]399//ll
Note: See TracBrowser for help on using the repository browser.