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
Line 
1//light.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-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 "roard.h"
27
28#ifndef ROAR_WITHOUT_DCOMP_LIGHT
29
30// declared 'extern'
31struct light_state g_light_state;
32struct light_mixer g_light_mixer;
33// //
34
35static inline void __set_channel(size_t index, uint8_t val) {
36 g_light_state.changes[index] |= g_light_state.state[index] ^ val;
37 g_light_state.state[index]    =                              val;
38}
39
40int light_init  (uint32_t channels) {
41 struct roar_stream_server * ss;
42 int i;
43
44 g_light_state.channels = 0;
45
46 if ( channels == 0 || channels > ((uint32_t)512UL*(uint32_t)512UL) ) /* unrealstic values */
47  return -1;
48
49 if ( (g_light_state.state = roar_mm_malloc(channels)) == NULL ) {
50  return -1;
51 }
52
53 if ( (g_light_state.changes = roar_mm_malloc(channels)) == NULL ) {
54  roar_mm_free(g_light_state.state);
55  return -1;
56 }
57
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
71 g_light_state.channels = channels;
72 g_light_state.filter   = NULL;
73
74 if ( (g_light_mixer.stream = add_mixer(ROAR_SUBSYS_LIGHT, _MIXER_NAME("Light Control"), &ss)) == -1 ) {
75  roar_mm_free(g_light_state.state);
76  return -1;
77 }
78
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
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
91 return light_reset();
92}
93
94int light_free  (void) {
95 if ( g_light_state.filter != NULL ) {
96  roar_slfi_unref(g_light_state.filter);
97 }
98
99 if ( g_light_state.state != NULL ) {
100  roar_mm_free(g_light_state.state);
101 }
102
103 if ( g_light_state.changes != NULL ) {
104  roar_mm_free(g_light_state.changes);
105 }
106
107 if ( g_light_state.output != NULL ) {
108  roar_mm_free(g_light_state.output);
109 }
110
111 if ( g_light_state.outputchanges != NULL ) {
112  roar_mm_free(g_light_state.outputchanges);
113 }
114
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
127 if ( g_light_state.changes == NULL )
128  return -1;
129
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));
135
136 g_light_state.eventsqueuelen = 0;
137
138 return 0;
139}
140
141// called at end of mainloop.
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);
147 memset(g_light_state.events,  0, sizeof(g_light_state.events));
148
149 g_light_state.eventsqueuelen = 0;
150
151 return 0;
152}
153
154// called at mid of mainloop.
155int light_update(void) {
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
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 }
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
183 return 0;
184}
185
186int light_check_stream  (int id) {
187 struct roar_stream        *   s;
188 struct roar_stream_server *  ss;
189 char buf[512];
190 int i;
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
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
206    for (i = 0; i < (g_light_state.channels < 512 ? g_light_state.channels : 512); i++) {
207     __set_channel(i, buf[i]);
208    }
209//    memcpy(g_light_state.state, buf, g_light_state.channels < 512 ? g_light_state.channels : 512);
210
211    s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, 1);
212
213    return 0;
214   break;
215  case ROAR_CODEC_ROARDMX:
216    ROAR_DBG("light_check_stream(id=%i): Codec: RoarDMX", id);
217    if ( cf_light_roardmx_read(id, ss) == -1 ) {
218     streams_delete(id); // simply drop the client on error.
219     return -1;
220    }
221   break;
222  default:
223    streams_delete(id);
224    return -1;
225 }
226
227 return 0;
228}
229
230static inline int light_send_stream_dmx512  (int id, struct roar_stream * s, struct roar_stream_server * ss) {
231 size_t chans = g_light_state.channels;
232 uint8_t buf[512];
233 register uint8_t * bufptr;
234
235 if ( chans > 512 )
236  chans = 512;
237
238 if ( chans == 512 ) {
239  bufptr = g_light_state.output;
240 } else {
241  memset(buf, 0, 512);
242  memcpy(buf, g_light_state.output, chans);
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
256int light_send_stream   (int id) {
257 struct roar_stream        *   s;
258 struct roar_stream_server *  ss;
259
260 if ( g_streams[id] == NULL )
261  return -1;
262
263 ROAR_DBG("light_send_stream(id=%i) = ?", id);
264
265 s = ROAR_STREAM(ss = g_streams[id]);
266
267 switch (s->info.codec) {
268  case ROAR_CODEC_DMX512:
269    return light_send_stream_dmx512(id, s, ss);
270   break;
271  case ROAR_CODEC_ROARDMX:
272    return cf_light_roardmx_write(id, ss);
273   break;
274  default:
275    streams_delete(id);
276    return -1;
277 }
278
279 return 0;
280}
281
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
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
319 return (int)(unsigned int)(uint8_t)g_light_state.state[index];
320}
321
322int light_dmxchannel_set(size_t index, uint8_t val) {
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
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
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
397#endif
398
399//ll
Note: See TracBrowser for help on using the repository browser.