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