fix rules for optional plugins.
[galan.git] / src / event.c
blob0dd7d17c8adefdd98ffe9373cfdc232af1329d6b
1 /* gAlan - Graphical Audio Language
2 * Copyright (C) 1999 Tony Garnock-Jones
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
23 #include "global.h"
24 #include "generator.h"
26 typedef struct event_callback {
27 Generator *g;
28 AEvent_handler_t fn;
29 } event_callback;
31 typedef struct EventQ EventQ;
33 struct EventQ {
34 EventQ *next;
35 AEvent e;
38 PRIVATE EventQ *event_q = NULL; /* list of AEvents */
39 PRIVATE GList *rtfuncs = NULL; /* list of event_callbacks */
41 PRIVATE GAsyncQueue *event_queue;
42 PRIVATE GAsyncQueue *addrt_queue;
44 PUBLIC SAMPLETIME gen_current_sampletime = 0; /* current time */
47 PRIVATE void aevent_copy( AEvent *src, AEvent *dst ) {
49 if( dst && src ) {
51 *dst = *src;
52 switch( src->kind ) {
53 case AE_STRING:
54 dst->d.string = safe_string_dup( src->d.string );
55 break;
56 case AE_NUMARRAY:
57 dst->d.array.numbers = safe_malloc( sizeof(SAMPLE) * dst->d.array.len );
58 memcpy( dst->d.array.numbers, src->d.array.numbers, src->d.array.len * sizeof(SAMPLE) );
59 break;
60 case AE_DBLARRAY:
61 dst->d.darray.numbers = safe_malloc( sizeof(gdouble) * dst->d.darray.len );
62 memcpy( dst->d.darray.numbers, src->d.darray.numbers, src->d.darray.len * sizeof(gdouble) );
63 break;
64 default:
65 break;
71 PRIVATE void eventq_free( EventQ *evq ) {
73 if( evq ) {
74 switch( evq->e.kind ) {
75 case AE_STRING:
76 if( evq->e.d.string != NULL )
77 safe_free( evq->e.d.string );
78 break;
79 case AE_NUMARRAY:
80 if( evq->e.d.array.numbers != NULL )
81 safe_free( evq->e.d.array.numbers );
82 break;
83 case AE_DBLARRAY:
84 if( evq->e.d.darray.numbers != NULL )
85 safe_free( evq->e.d.darray.numbers );
86 break;
87 default:
88 break;
90 g_slice_free1( sizeof(EventQ), evq );
94 /**
95 * \brief Put an AEvent into the main event queue.
97 * \param e The Event which shall be copied into the EventQueue
99 * this would use an async queue to make this operation thread safe.
100 * the main event processor will pop all events from the queue and
101 * sort them into the main list.
103 * with this function threadsafe control_emit() gets threadsafe as well.
105 * i believe this is the problem XXX XXX
108 PUBLIC void gen_post_aevent(AEvent *e) {
109 EventQ *q = g_slice_alloc(sizeof(EventQ));
111 aevent_copy( e, &(q->e) );
113 g_async_queue_push( event_queue, q );
117 * \brief sort in all posted aevents
119 * XXX: ok... this has to be modified, to support for
120 * local event queues on the generators...
122 * if( g->has_local_queue )
123 * deliver_directly( e );
124 * else
125 * deliver normally( e );
127 * this seems thread safe... lets see if that
128 * brings us some advantage...
131 PRIVATE void gen_sortin_aevents(void) {
132 EventQ *q;
134 while( (q=g_async_queue_try_pop( event_queue )) != NULL )
136 EventQ *prev = NULL, *curr = event_q;
138 while (curr != NULL) {
139 if (q->e.time < curr->e.time)
140 break;
142 prev = curr;
143 curr = curr->next;
146 q->next = curr;
148 if (prev == NULL)
149 event_q = q;
150 else
151 prev->next = q;
155 * \brief Remove all events for Generator \a g from the global queue
157 * \param g The Generator
159 * To make this function threadsafe i need to add a command queue.
160 * The mainloop will execute all commands in the queue when its time.
162 * the event insertion queue should be the same as the command queue.
163 * i also need commands for inserting and removing Eventlinks.
165 * also a command for removing generators is needed because
166 * i dont know when the Removal of an EventLink occurs.
168 * At the Moment this function may only be called from the audiothread.
169 * This is ok for all current plugins.
173 PUBLIC void gen_purge_event_queue_refs(Generator *g) {
174 EventQ *prev = NULL, *curr = event_q;
176 while (curr != NULL) {
177 EventQ *next = curr->next;
179 if (curr->e.src == g || curr->e.dst == g) {
180 if (prev == NULL)
181 event_q = next;
182 else
183 prev->next = next;
185 //free(curr);
186 eventq_free( curr );
187 curr = next;
188 continue;
191 prev = curr;
192 curr = next;
196 PUBLIC void gen_purge_inputevent_queue_refs(Generator *g) {
197 EventQ *prev = NULL, *curr = event_q;
199 while (curr != NULL) {
200 EventQ *next = curr->next;
202 if (curr->e.dst == g) {
203 if (prev == NULL)
204 event_q = next;
205 else
206 prev->next = next;
208 //free(curr);
209 eventq_free( curr );
210 curr = next;
211 continue;
214 prev = curr;
215 curr = next;
220 * \brief insert a function into \a list
222 * \param list pointer to a GList *
223 * \param g The Generator which will be a paramter of \a func
225 * If this was threadsafe gen_register_realtime_fn() would be threadsafe
226 * also.
228 * i need a Mutex for the rtfuncs struct.
231 //PRIVATE void insert_fn(GList **lst, Generator *g, AEvent_handler_t func) {
232 // event_callback *ec = safe_malloc(sizeof(event_callback));
234 // ec->g = g;
235 // ec->fn = func;
237 // *lst = g_list_prepend(*lst, ec);
241 * \brief insert an event_callback into \a list
243 * \param list pointer to a GList *
244 * \param ec pointer to the eventcallback.
246 * If this was threadsafe gen_register_realtime_fn() would be threadsafe
247 * also.
249 * i need a Mutex for the rtfuncs struct.
251 * no ... make it a GSList.
254 PRIVATE void insert_fn_ec(GList **lst, event_callback *ec) {
256 *lst = g_list_prepend(*lst, ec);
258 PRIVATE gint event_callback_cmp(event_callback *a, event_callback *b) {
259 return !(a->g == b->g);
262 PRIVATE void remove_all_fns(GList **lst, Generator *g) {
263 event_callback ec;
264 GList *link;
266 ec.g = g;
267 link = g_list_find_custom(*lst, &ec, (GCompareFunc) event_callback_cmp);
269 if (link != NULL) {
270 free(link->data);
271 link->data = NULL;
272 *lst = g_list_remove_link(*lst, link);
277 * \brief Register a realtime function
279 * \param g The Genrator wishing to receive Realtime Events
280 * \param func The function which should be called on receive of a Realtime Event
282 * The Realtime functions are the entry points into the graph.
284 * this function is sometimes (scope, outputs) called by the init_instance()
285 * of a Generator to have it realtime_handler installed.
287 * This function must be threadsafe.
288 * an async queue is a good way to accomplish this.
290 * The deregister_realtime_fn function is changed to a noop.
291 * it gets removed during generator destruction.
295 PUBLIC void gen_register_realtime_fn(Generator *g, AEvent_handler_t func) {
296 event_callback *ec = safe_malloc( sizeof(event_callback) );
297 ec->g = g;
298 ec->fn = func;
300 g_async_queue_push( addrt_queue, ec );
304 * \brief deregister a realtime function
306 * \param g The Generator
307 * \param func The callback that should be removed
309 * i will make this a no-op.
310 * its only called in destructors and
311 * i will remove all functions for a generator in the RT stage of removal.
314 PUBLIC void gen_deregister_realtime_fn(Generator *g, AEvent_handler_t func) {
315 //remove_fn(&rtfuncs, g, func);
318 PUBLIC void gen_purge_realtime_fns( Generator *g )
320 remove_all_fns( &rtfuncs, g );
323 PRIVATE void sortin_rtevents(void) {
324 event_callback *ec;
326 while( (ec=g_async_queue_try_pop( addrt_queue )) != NULL )
327 insert_fn_ec( &rtfuncs, ec );
330 PRIVATE void send_rt_event(event_callback *ec, AEvent *rtevent) {
331 // why a local copy ? because the generator can modify an event passed.
332 // warning this only works for REALTIME events.
333 AEvent local_copy = *rtevent;
334 ec->fn(ec->g, &local_copy);
338 * \brief Call all Realtime functions which have registered themselves
339 * with gen_register_realtime_fn()
341 * \param e an AEvent of type AE_REALTIME
343 * this is called when the eventprocessing is done
344 * and the data must be computed.
346 * needs to insert realtime functions from the queue
347 * deletion of functions will be done from the audio thread so
348 * it does not need to be safe.
351 PUBLIC void gen_send_realtime_fns(AEvent *e) {
352 sortin_rtevents();
354 g_list_foreach(rtfuncs, (GFunc) send_rt_event, e);
358 * \brief process AEvents pending
360 * \return time until next event has to be processed
361 * (At Maximum MAXIMUM_REALTIME_STEP)
363 * This Functions inserts all new aevents and then processes all
364 * pending events from the queue.
365 * it also calls do_checks to make the changes to the connection graph.
368 PUBLIC gint gen_mainloop_once(void) {
369 int loopcheck_counter=0;
371 gen_sortin_aevents();
372 gen_mainloop_do_checks();
374 while (1) {
375 EventQ *e = event_q;
377 if (e == NULL || e->e.time > gen_get_sampletime()) {
378 SAMPLETIME delta = (e == NULL) ? MAXIMUM_REALTIME_STEP : e->e.time - gen_get_sampletime();
379 delta = MIN(delta, MAXIMUM_REALTIME_STEP);
381 /* Notice that the clock is *not* advanced here. That's up to the master-clock
382 routine - it should call gen_advance_clock() with the result of this routine. */
383 return delta;
386 event_q = e->next;
387 e->e.dst->klass->in_handlers[e->e.dst_q](e->e.dst, &e->e);
388 //free(e);
389 eventq_free( e );
390 gen_sortin_aevents();
391 loopcheck_counter += 1;
392 if( loopcheck_counter > 1000 ) {
393 // We processed 1000 events now.
394 // this seems to be an event loop.
395 // let break out and, let events processing
396 // lag behind.
397 return MAXIMUM_REALTIME_STEP;
402 PUBLIC void gen_advance_clock(gint delta) {
403 gen_current_sampletime += delta;
406 PUBLIC void init_event( void ) {
407 if (!g_thread_supported ()) g_thread_init (NULL);
408 event_queue = g_async_queue_new();
409 addrt_queue = g_async_queue_new();