source: roaraudio/roard/light.c

tip
Last change on this file was 6052:d48765b2475e, checked in by phi, 9 years ago

updated copyright headers

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