1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 	a_bus.c - Audio Engine bus
4 ---------------------------------------------------------------------------
5  * Copyright (C) 2001, 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 #include <stdlib.h>
23 #include <string.h>
24 #include "a_bus.h"
25 #include "a_struct.h"
26 #include "a_delay.h"
27 #include "a_tools.h"
28 
29 #define	BDBG(x)
30 
31 
__bus_run_fx(int bus,int slot,int * busses[],unsigned frames)32 static inline int __bus_run_fx(int bus, int slot, int *busses[], unsigned frames)
33 {
34 	audio_bus_t *b = &bustab[bus];
35 	--slot;	/* No IFX on slot 0! */
36 	switch(b->insert[slot].current_state)
37 	{
38 	  case FX_STATE_RUNNING:
39 	  case FX_STATE_SILENT:
40 	  case FX_STATE_RESTING:
41 		if(b->in_use)	/* Do we have input? */
42 			b->insert[slot].process(&b->insert[slot],
43 					busses[bus], frames);
44 		else
45 		{
46 			b->insert[slot].process_r(&b->insert[slot],
47 					NULL, busses[bus], frames);
48 			b->in_use = 1;
49 		}
50 		/* Check if the plugin actually produced valid output! */
51 		return (FX_STATE_RUNNING == b->insert[slot].current_state);
52 	  default:
53 		/* No plugin, or plugin not running. */
54 		return 0;
55 	}
56 }
57 
58 
__bus_process(int bus,int * busses[],int * master,unsigned frames)59 static inline void __bus_process(int bus, int *busses[], int *master, unsigned frames)
60 {
61 	audio_bus_t *b = &bustab[bus];
62 	int i, s;
63 
64 	/* Tail detection hack for the DC supression filter... */
65 	if(!b->in_use)
66 		if(!dcf6s_silent(&b->dcfilter))
67 		{
68 			b->in_use = 1;
69 			s32clear(busses[bus], frames);
70 		}
71 
72 	if(b->in_use)	/* Only if we actually have input! */
73 	{
74 		/* DC suppression filter */
75 		dcf6s_process(&b->dcfilter, busses[bus], frames);
76 
77 		/* Mix pre-insert sends */
78 		s32mix(busses[bus], master, b->bctl[0][ABC_SEND_MASTER], frames);
79 		for(i = bus + 1; i < AUDIO_MAX_BUSSES; ++i)
80 			if(s32mix(busses[bus], busses[i],
81 					b->bctl[0][ABC_SEND_BUS_0 + i],
82 					frames))
83 				bustab[i].in_use = 1;
84 	}
85 
86 	/* Mix post-insert sends */
87 	for(s = 1; s <= AUDIO_MAX_INSERTS; ++s)
88 	{
89 		/* Run the insert */
90 		if(!__bus_run_fx(bus, s, busses, frames))
91 			continue;	/* No output, no sends! */
92 
93 		s32mix(busses[bus], master, b->bctl[s][ABC_SEND_MASTER], frames);
94 		for(i = bus + 1; i < AUDIO_MAX_BUSSES; ++i)
95 			if(s32mix(busses[bus], busses[i],
96 					b->bctl[s][ABC_SEND_BUS_0 + i],
97 					frames))
98 				bustab[i].in_use = 1;
99 	}
100 
101 	/* Prepare for the next engine cycle */
102 	if(b->in_use)
103 	{
104 		s32clear(busses[bus], frames);
105 		b->in_use = 0;
106 	}
107 }
108 
109 
bus_process_all(int * bufs[],int * master,unsigned frames)110 void bus_process_all(int *bufs[], int *master, unsigned frames)
111 {
112 	int i;
113 	for(i = 0; i < AUDIO_MAX_BUSSES; ++i)
114 		__bus_process(i, bufs, master, frames);
115 }
116 
117 
__remove_insert(unsigned bus,unsigned insert)118 static void __remove_insert(unsigned bus, unsigned insert)
119 {
120 	audio_bus_t *b = &bustab[bus];
121 	audio_plugin_close(&b->insert[insert]);
122 }
123 
124 
__change_insert(unsigned bus,unsigned insert,int fx)125 static void __change_insert(unsigned bus, unsigned insert, int fx)
126 {
127 	int reopen = 0;
128 	audio_bus_t *b = &bustab[bus];
129 	audio_plugin_t *ins;
130 	if(bus < 1)
131 		return;
132 
133 	__remove_insert(bus, insert);
134 	ins = &b->insert[insert-1];
135 
136 	switch(fx)
137 	{
138 	  case AFX_NONE:
139 		break;
140 	  case AFX_DELAY:
141 		break;
142 	  case AFX_ECHO:
143 		break;
144 	  case AFX_REVERB:
145 		delay_init(ins);
146 		reopen = 1;
147 		break;
148 	  case AFX_CHORUS:
149 		break;
150 	  case AFX_FLANGER:
151 		break;
152 	  case AFX_FILTER:
153 		break;
154 	  case AFX_DIST:
155 		break;
156 	  case AFX_WAH:
157 		break;
158 	  case AFX_EQ:
159 		break;
160 	  case AFX_ENHANCER:
161 		break;
162 	  case AFX_COMPRESSOR:
163 		break;
164 	  case AFX_MAXIMIZER:
165 		break;
166 	}
167 
168 	if(!reopen)
169 		return;
170 
171 	if(audio_plugin_open(ins, a_settings.buffersize,
172 			a_settings.samplerate, a_settings.quality) < 0)
173 		return;
174 
175 /* FIXME: This should be done in a butler thread... */
176 	if(audio_plugin_state(ins, FX_STATE_RUNNING) < 0)
177 	{
178 		audio_plugin_close(ins);
179 		return;
180 	}
181 /* /FIXME */
182 
183 /*
184 FIXME:	We rely on plugins loading their defaults. Plugins should
185 FIXME:	probably be able to export their default settings instead.
186 */
187 #if 0
188 	for(i = 0; i < 5; ++i)
189 		ins->control(ins, FXC_PARAM_1 + i,
190 				b->bctl[insert][ABC_FX1_PARAM_1 + i]);
191 #endif
192 
193 	b->bctl[insert][ABC_FX_TYPE] = fx;
194 }
195 
196 
bus_ctl_set(unsigned bus,unsigned slot,unsigned ctl,int arg)197 void bus_ctl_set(unsigned bus, unsigned slot, unsigned ctl, int arg)
198 {
199 	if(0 BDBG(+ 1))
200 	{
201 		const char *ctls[] = {
202 			"ABC_FX_TYPE",
203 			"ABC_FX_PARAM_1",
204 			"ABC_FX_PARAM_2",
205 			"ABC_FX_PARAM_3",
206 			"ABC_FX_PARAM_4",
207 			"ABC_FX_PARAM_5",
208 			"ABC_FX_PARAM_6",
209 
210 			"ABC_SEND_MASTER",
211 
212 			"ABC_SEND_BUS_0",
213 			"ABC_SEND_BUS_1",
214 			"ABC_SEND_BUS_2",
215 			"ABC_SEND_BUS_3",
216 			"ABC_SEND_BUS_4",
217 			"ABC_SEND_BUS_5",
218 			"ABC_SEND_BUS_6",
219 			"ABC_SEND_BUS_7",
220 			"<ILLEGAL!>"
221 		};
222 		unsigned c = ctl;
223 		if(ctl < ABC_FIRST || ctl > ABC_LAST)
224 			c = (unsigned)(ABC_LAST + 1);
225 		log_printf(DLOG, "Bus %u, slot %u %s set to %d\n", bus, slot, ctls[c], arg);
226 	}
227 
228 	switch(ctl)
229 	{
230 	  case ABC_FX_TYPE:
231 		if(arg != bustab[bus].bctl[slot][ctl])
232 			__change_insert(bus, slot, arg);
233 		break;
234 	  case ABC_FX_PARAM_1:
235 	  case ABC_FX_PARAM_2:
236 	  case ABC_FX_PARAM_3:
237 	  case ABC_FX_PARAM_4:
238 	  case ABC_FX_PARAM_5:
239 	  case ABC_FX_PARAM_6:
240 		if(slot < 1)
241 			break;
242 		if(bustab[bus].insert[slot].current_state < FX_STATE_READY)
243 			break;
244 		bustab[bus].insert[slot].control(&bustab[bus].insert[slot],
245 				ctl - ABC_FX_PARAM_1 + FXC_PARAM_1,
246 				arg);
247 		bustab[bus].bctl[slot][ctl] = arg;
248 		break;
249 	  default:
250 		if(slot >= AUDIO_MAX_INSERTS)
251 			break;
252 		if(ctl > ABC_LAST)
253 			break;
254 		bustab[bus].bctl[slot][ctl] = arg;
255 		break;
256 	}
257 	/*
258 	 * This is where the "connection table" would be
259 	 * updated in a more optimized implementation.
260 	 */
261 }
262 
263 
264 static int _is_open = 0;
265 
audio_bus_open(void)266 void audio_bus_open(void)
267 {
268 	int i, s;
269 	if(_is_open)
270 		return;
271 
272 	memset(bustab, 0, sizeof(bustab));
273 	for(i = 0; i < AUDIO_MAX_BUSSES; ++i)
274 	{
275 		for(s = 0; s < AUDIO_MAX_INSERTS; ++s)
276 			memcpy(bustab[i].bctl[s], a_bus_def_ctl,
277 					sizeof(a_bus_def_ctl));
278 		dcf6s_init(&bustab[i].dcfilter, a_settings.samplerate);
279 		dcf6s_set_f(&bustab[i].dcfilter, 10);
280 		bustab[i].in_use = 0;
281 	}
282 	_is_open = 1;
283 }
284 
285 
audio_bus_close(void)286 void audio_bus_close(void)
287 {
288 	unsigned i, j;
289 	if(!_is_open)
290 		return;
291 
292 	for(i = 0; i < AUDIO_MAX_BUSSES; ++i)
293 		for(j = 0; j < AUDIO_MAX_INSERTS; ++j)
294 			__change_insert(i, j, AFX_NONE);
295 	memset(bustab, 0, sizeof(bustab));
296 	_is_open = 0;
297 }
298