1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 a_channel.c - Audio Engine high level control abstraction
4 ---------------------------------------------------------------------------
5 * Copyright (C) 2001, 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 #include <stdlib.h>
23
24 #include "kobolog.h"
25 #include "a_globals.h"
26 #include "a_struct.h"
27 #include "a_control.h"
28 #include "a_sequencer.h"
29 #include "a_tools.h"
30
31 #define SDBG(x)
32
channel_stop_all(void)33 void channel_stop_all(void)
34 {
35 int i;
36 for(i = 0; i < AUDIO_MAX_VOICES; ++i)
37 voice_kill(voicetab + i);
38 for(i = 0; i < AUDIO_MAX_CHANNELS; ++i)
39 channeltab[i].playing = 0; /* Reset "voice" count */
40 sequencer_stop(-1);
41 }
42
43
44 /*
45 FIXME: What if there are sounds playing when an ACC_PATCH comes in!?
46 FIXME: Maybe patch plugins should have a "detach + release" feature?
47 FIXME:
48 FIXME: Another alternative would be some way of forwarding events to
49 FIXME: "unknown" tags (easy now that the controller must provide the
50 FIXME: tags!) on to whatever patch they were started by. That is, an
51 FIXME: actively managed, per channel "patch history". "Affect all"
52 FIXME: events (-1 tags) would have to be processed *and* forwarded.
53 FIXME:
54 FIXME: Patch plugins could just pass events for unknown tags to some
55 FIXME: "forward to previous patch" event port, that the engine checks
56 FIXME: after running a patch plugin. Of course, this would require
57 FIXME: that all patches actually remember tags, even if they don't
58 FIXME: really care about them... In fact, it would be a problem even
59 FIXME: for patches that *do* use tags, as those will generally
60 FIXME: "remember" only tags that actually get the required resources.
61 FIXME: (That is, if a poly patch runs out of voices, it'll start
62 FIXME: forgetting tags...)
63 FIXME:
64 FIXME: A much simpler solution would be to just keep patches running
65 FIXME: until they say they have no more "contexts" active. Events
66 FIXME: would have to be duplicated - or we could have all plugins
67 FIXME: just pass events on to a "garbage port", that actually becomes
68 FIXME: a forwarding port when needed. In the normal case, the engine
69 FIXME: would just flush this port when appropriate.
70 */
71 /*
72 FIXME: Maybe we actually want to pass ACC_PATCH change events
73 FIXME: on to patch drivers? If so, should they be sent to
74 FIXME: the old or new patch, or both? That question alone
75 FIXME: seems to suggest that ACC_PATCH should die here, but
76 FIXME: then again, some drivers might need these events...
77 */
78
channel_process(audio_channel_t * c,unsigned frames)79 static inline void channel_process(audio_channel_t *c, unsigned frames)
80 {
81 aev_event_t *first_ev = c->port.first;
82 unsigned split_frames = frames;
83
84 /*
85 * This one's rather ugly... Better ideas, anyone?
86 */
87 aev_timestamp_t timer_save = aev_timer;
88
89 while(1)
90 {
91 aev_event_t *ev = c->port.first;
92 aev_event_t *prev_ev = NULL;
93 aev_event_t *rerun_ev = NULL;
94 while(ev && (AEV_TIME(ev->frame, 0) < split_frames))
95 {
96 if(ev->type != CE_CONTROL)
97 {
98 prev_ev = ev;
99 ev = ev->next;
100 continue;
101 }
102
103 c->rctl[ev->index] = ev->arg2;
104 switch(ev->index)
105 {
106 /* case_ACC_NOTRANSFORM:*/
107 case ACC_GROUP:
108 case ACC_PRIORITY:
109 break;
110 case ACC_PATCH:
111 {
112 aev_event_t *del_ev = ev;
113 SDBG(log_printf(D3LOG, "(patch) ");)
114 if(c->ctl[ACC_PATCH] == c->rctl[ACC_PATCH])
115 {
116 SDBG(log_printf(D3LOG, "[IGNORE]\n");)
117 ev = ev->next;
118 if(prev_ev)
119 prev_ev->next = ev;
120 else
121 c->port.first = ev;
122 }
123 else if(ev == first_ev)
124 {
125 SDBG(log_printf(D3LOG, "[FIRST]\n");)
126 c->ctl[ACC_PATCH] = c->rctl[ACC_PATCH];
127 ev = ev->next;
128 c->port.first = ev;
129 first_ev = NULL;
130 }
131 else
132 {
133 SDBG(log_printf(D3LOG, "[SPLIT]\n");)
134 split_frames = AEV_TIME(ev->frame, 0);
135 rerun_ev = ev->next;
136 /*
137 * Note that we really must break the list!
138 * Going by the timestams is insufficient,
139 * as there may be more events for the same
140 * frame.
141 */
142 if(prev_ev)
143 prev_ev->next = NULL;
144 else
145 c->port.first = NULL;
146 ev = NULL;
147 }
148 aev_free(del_ev);
149 continue;
150 }
151 case ACC_PRIM_BUS:
152 case ACC_SEND_BUS:
153 break;
154 case_ACC_ADDTRANSFORM:
155 {
156 audio_group_t *g;
157 int min, max;
158 g = grouptab + c->rctl[ACC_GROUP];
159 min = addtrans_min[ev->index -
160 ACC_ADDTRANSFORM_FIRST];
161 max = addtrans_max[ev->index -
162 ACC_ADDTRANSFORM_FIRST];
163 ev->arg2 += g->ctl[ev->index];
164 ev->arg2 -= addtrans_bias[ev->index -
165 ACC_ADDTRANSFORM_FIRST];
166 if(ev->arg2 < min)
167 ev->arg2 = min;
168 else if(ev->arg2 > max)
169 ev->arg2 = max;
170 break;
171 }
172 case_ACC_MULTRANSFORM:
173 {
174 audio_group_t *g;
175 g = grouptab + c->rctl[ACC_GROUP];
176 ev->arg2 = fixmul(ev->arg2, g->ctl[ev->index]);
177 break;
178 }
179 }
180 prev_ev = ev;
181 ev = ev->next;
182 }
183
184 /* Run the patch plugin! */
185 /* if(c->ctl[ACC_PATCH] < AUDIO_MAX_PATCHES)*/
186 {
187 audio_patch_t *p = patchtab + c->ctl[ACC_PATCH];
188 p->process(p, c, split_frames);
189 }
190
191 /* Apply last patch change, if any */
192 c->ctl[ACC_PATCH] = c->rctl[ACC_PATCH];
193
194 frames -= split_frames;
195 if(!frames)
196 break; /* Done! */
197
198 SDBG(log_printf(D3LOG, "split!\n");)
199 /* Set up event port and timing for next fragment */
200 aev_advance_timer(split_frames);
201 split_frames = frames;
202 c->port.first = rerun_ev;
203 }
204 aev_timer = timer_save;
205 }
206
207
channel_process_all(unsigned frames)208 void channel_process_all(unsigned frames)
209 {
210 int i;
211 for(i = 0; i < AUDIO_MAX_CHANNELS; ++i)
212 channel_process(channeltab + i, frames);
213 }
214
215
216 static int _wasinit = 0;
217
audio_channel_open(void)218 void audio_channel_open(void)
219 {
220 int i;
221 if(_wasinit)
222 return;
223
224 memset(channeltab, 0, sizeof(channeltab));
225 for(i = 0; i < AUDIO_MAX_CHANNELS; ++i)
226 {
227 char *buf = malloc(64);
228 snprintf(buf, 64, "Audio Channel %d", i);
229 aev_port_init(&channeltab[i].port, buf);
230 acc_copya(&channeltab[i].rctl, &a_channel_def_ctl);
231 acc_copya(&channeltab[i].ctl, &a_channel_def_ctl);
232 channeltab[i].voices = NULL;
233 }
234 _wasinit = 1;
235 }
236
237
audio_channel_close(void)238 void audio_channel_close(void)
239 {
240 int i;
241 if(!_wasinit)
242 return;
243 for(i = 0; i < AUDIO_MAX_CHANNELS; ++i)
244 {
245 aev_flush(&channeltab[i].port);
246 free((char *)channeltab[i].port.name);
247 }
248 memset(channeltab, 0, sizeof(channeltab));
249 _wasinit = 0;
250 }
251