1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 a_events.c - Internal Event System
4 ---------------------------------------------------------------------------
5 * Copyright (C) 2002, David Olofson
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #define EVDBG(x)
23
24 #include <stdlib.h>
25
26 #include "kobolog.h"
27 #include "a_events.h"
28
29 #define EVENTS_PER_BLOCK 256
30
31 /*----------------------------------------------------------
32 The global event timestamp time base
33 ----------------------------------------------------------*/
34 Uint16 aev_timer = 0;
35
36
37 /*----------------------------------------------------------
38 Event pool management
39 ----------------------------------------------------------*/
40
41 aev_event_t *aev_event_pool = NULL;
42
43 #ifdef AEV_TRACKING
44 int aev_event_counter = 0;
45 int aev_event_counter_max = 0;
46 const char *aev_current_client = "Unknown";
47 #endif
48
49
50 typedef struct evblock_t
51 {
52 struct evblock_t *next;
53 aev_event_t events[EVENTS_PER_BLOCK];
54 } evblock_t;
55
56 static evblock_t *blocks = NULL;
57
58
_aev_refill_pool(void)59 int _aev_refill_pool(void)
60 {
61 /*
62 * We can't refill in real time context on some
63 * platforms - and it would be a bad idea anyway...
64 */
65 log_printf(ELOG, "Audio event pool exhausted!\n");
66 return -1;
67 }
68
69
70 /*
71 * A job for a future butler thread. For now, we only use
72 * this during initialization.
73 */
refill_pool(void)74 static int refill_pool(void)
75 {
76 int i;
77 evblock_t *eb = calloc(1, sizeof(evblock_t));
78 if(!eb)
79 return -1;
80
81 /* Add to block list */
82 eb->next = blocks;
83 blocks = eb;
84
85 /* Add the events to the pool */
86 for(i = 0; i < EVENTS_PER_BLOCK; ++i)
87 {
88 eb->events[i].type = AEV_ET_FREE;
89 aev_free(&eb->events[i]);
90 }
91
92 return 0;
93 }
94
95
96 /*----------------------------------------------------------
97 Event Input Port
98 ----------------------------------------------------------*/
aev_insert(aev_port_t * evp,aev_event_t * ev)99 void aev_insert(aev_port_t *evp, aev_event_t *ev)
100 {
101 EVDBG(log_printf(D2LOG, "aev_insert:\n");)
102 if(!evp->first)
103 {
104 EVDBG(log_printf(D2LOG, " empty list\n");)
105 ev->next = NULL;
106 evp->first = evp->last = ev;
107 }
108 else if((Sint16)(evp->last->frame - ev->frame) <= 0)
109 {
110 EVDBG(log_printf(D2LOG, " last\n");)
111 ev->next = NULL;
112 evp->last->next = ev;
113 evp->last = ev;
114 }
115 else
116 {
117 aev_event_t *e_prev = NULL;
118 aev_event_t *e = evp->first;
119 EVDBG(log_printf(D2LOG, " scanning...\n");)
120 while((Sint16)(e->frame - ev->frame) <= 0)
121 {
122 EVDBG(log_printf(D2LOG, "e->frame = %d, ev->frame = %d\n", e->frame, ev->frame);)
123 e_prev = e;
124 e = e->next;
125 }
126 ev->next = e;
127 if(e_prev)
128 {
129 EVDBG(log_printf(D2LOG, " insert\n");)
130 e_prev->next = ev;
131 }
132 else
133 {
134 EVDBG(log_printf(D2LOG, " first\n");)
135 evp->first = ev;
136 }
137 }
138 #ifdef AEV_TRACKING
139 ev->port = evp;
140 #endif
141 }
142
143
144 /*----------------------------------------------------------
145 Open/Close
146 ----------------------------------------------------------*/
147
aev_open(int pool_size)148 int aev_open(int pool_size)
149 {
150 while(pool_size > 0)
151 {
152 if(refill_pool() < 0)
153 {
154 aev_close();
155 return -1; /* OOM! */
156 }
157 pool_size -= EVENTS_PER_BLOCK;
158 }
159 #if 0
160 {
161 aev_evport_t port;
162 int i;
163 aev_evport_init(&port, "testport");
164 aev_timer = 0;
165 aev_event_client(42);
166 for(i = 0; i < 5; ++i)
167 aev_put0(&port, 20+i*20, 42);
168 for(i = 0; i < 5; ++i)
169 aev_put0(&port, 100-i*20, 43);
170 i = 0;
171 aev_timer = 0;
172 while(i < 200)
173 {
174 unsigned int frames;
175 log_printf(D2LOG, "aev_timer = %d\n", aev_timer);
176 while(!(frames = aev_next(&port, 0)))
177 {
178 aev_event_t *ev = aev_read(&port);
179 log_printf(D2LOG, " event.frame = %d, type = %d\n",
180 ev->frame, ev->type);
181 aev_free(ev);
182 }
183 if(frames > 5)
184 frames = 5;
185 aev_timer += frames;
186 i += frames;
187 }
188 }
189 #endif
190 #ifdef AEV_TRACKING
191 aev_event_counter = 0;
192 aev_event_counter_max = 0;
193 #endif
194 return 0;
195 }
196
197
aev_close(void)198 void aev_close(void)
199 {
200 log_printf(DLOG, "aev_close(): max events used: %d\n",
201 aev_event_counter_max);
202 #ifdef AEV_TRACKING
203 if(aev_event_counter)
204 {
205 evblock_t *eb = blocks;
206 log_printf(ELOG, "INTERNAL ERROR: Closing audio event system"
207 " system with %d events in use!"
208 " (Memory leaked.)\n",
209 aev_event_counter);
210 while(eb)
211 {
212 int i;
213 for(i = 0; i < EVENTS_PER_BLOCK; ++i)
214 {
215 if(eb->events[i].type == AEV_ET_FREE)
216 continue;
217 log_printf(ELOG, " Event %p, "
218 "sent from client \"%s\", "
219 "to port \"%s\".\n",
220 eb->events + i,
221 eb->events[i].client,
222 eb->events[i].port->name );
223 }
224 eb = eb->next;
225 }
226 }
227 else
228 #endif
229 while(blocks)
230 {
231 evblock_t *eb = blocks;
232 blocks = eb->next;
233 free(eb);
234 }
235
236 blocks = NULL;
237 aev_event_pool = NULL;
238 #ifdef AEV_TRACKING
239 aev_event_counter = 0;
240 aev_event_counter_max = 0;
241 #endif
242 }
243