1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 	a_patch.c - Audio Engine "instrument" definitions
4 ---------------------------------------------------------------------------
5  * Copyright (C) 2001-2003, 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 <string.h>
23 
24 #include "kobolog.h"
25 #include "a_struct.h"
26 #include "a_patch.h"
27 #include "a_sequencer.h"
28 
29 #define	EDBG(x)
30 #define	EGDBG(x)
31 
32 static int _is_open = 0;
33 #define	CHECKINIT	if(!_is_open) audio_patch_open();
34 
35 /*
36  * Common tools for mono and poly...
37  */
38 
__calc_randpitch(audio_patch_t * p,int pitch)39 static inline int __calc_randpitch(audio_patch_t *p, int pitch)
40 {
41 	static int rnd = 16576;
42 	int rp = p->param[APP_RANDPITCH];
43 	if(rp)
44 	{
45 		rnd *= 1566083941UL;
46 		rnd++;
47 		rnd &= 0xffffffffUL;
48 		pitch += (rnd % rp) - rp/2;
49 	}
50 	return pitch;
51 }
52 
53 
__get_wave(audio_patch_t * p)54 static inline int __get_wave(audio_patch_t *p)
55 {
56 	int wave = p->param[APP_WAVE];
57 	if((wave < 0) || (wave >= AUDIO_MAX_WAVES))
58 		return -1;
59 
60 	if(AF_MIDI == wavetab[wave].format)
61 		return -1;
62 
63 	return wave;
64 }
65 
66 
67 /* Update base vol/send levels after control change. */
__env_control_recalc(audio_patch_t * p,audio_channel_t * c,audio_voice_t * v)68 static inline void __env_control_recalc(audio_patch_t *p, audio_channel_t *c,
69 		audio_voice_t *v)
70 {
71 	patch_closure_t *clos = &v->closure;
72 
73 	clos->lvol = clos->rvol = clos->velvol;
74 	clos->lvol *= 64 - (c->ctl[ACC_PAN] >> 10);
75 	clos->rvol *= 64 + (c->ctl[ACC_PAN] >> 10);
76 	clos->lvol >>= 6;
77 	clos->rvol >>= 6;
78 
79 	clos->lsend = c->ctl[ACC_SEND] >> (16-VOL_BITS);
80 	clos->lsend *= clos->velvol;
81 	clos->lsend >>= 16;
82 	clos->rsend = clos->lsend;
83 	clos->lsend *= 64 - (c->ctl[ACC_PAN] >> 10);
84 	clos->rsend *= 64 + (c->ctl[ACC_PAN] >> 10);
85 	clos->lsend >>= 6;
86 	clos->rsend >>= 6;
87 }
88 
89 
90 /* Initialize envelope to PES_START. */
__env_start(audio_patch_t * p,audio_channel_t * c,audio_voice_t * v)91 static inline void __env_start(audio_patch_t *p, audio_channel_t *c,
92 		audio_voice_t *v)
93 {
94 	patch_closure_t *clos = &v->closure;
95 	clos->env_state = PES_START;
96 	clos->env_next = aev_timer;
97 }
98 
99 
__env_stop(audio_patch_t * p,audio_channel_t * c,audio_voice_t * v)100 static inline void __env_stop(audio_patch_t *p, audio_channel_t *c,
101 		audio_voice_t *v)
102 {
103 	patch_closure_t *clos = &v->closure;
104 	if(p->param[APP_ENV_T3] >= 0)
105 		return;
106 
107 EGDBG(log_printf(D3LOG, "stop!\n");)
108 	switch (clos->env_state)
109 	{
110 	  case PES_START:
111 	  case PES_START2:
112 	  case PES_DELAY:
113 	  case PES_ATTACK:
114 	  case PES_HOLD:
115 	  case PES_DECAY:
116 		clos->queued_stop = 1;
117 		if(p->param[APP_ENV_SKIP])
118 		{
119 			clos->env_next = aev_timer;
120 			clos->env_state = PES_SUSTAIN;
121 		}
122 		break;
123 	  case PES_SUSTAIN:	/* No interactive sustain! */
124 	  case PES_RELEASE:	/* Release already active... */
125 	  case PES_DEAD:
126 		break;
127 	  case PES_WAIT:
128 		clos->env_next = aev_timer;
129 		clos->env_state = PES_SUSTAIN;
130 		break;
131 	}
132 }
133 
134 /*
135 FIXME: Support longer times than 65535 timestamp units.
136 FIXME: When that's done, this will need fixing as well...
137 */
138 #define	S2S(x)	((((x)>>2) * a_settings.samplerate) >> 14)
__env_run(audio_patch_t * p,audio_channel_t * c,audio_voice_t * v,unsigned frames)139 static inline void __env_run(audio_patch_t *p, audio_channel_t *c,
140 		audio_voice_t *v, unsigned frames)
141 {
142 	patch_closure_t *clos = &v->closure;
143 	int lvol, rvol, lsend, rsend;
144 	aev_timestamp_t t;
145 
146 	while((t = (unsigned)((clos->env_next - aev_timer) &
147 			AEV_TIMESTAMP_MASK)) < frames)
148 	{
149 		int duration;
150 		int target = 0;
151 		aev_timestamp_t timestamp = (aev_timestamp_t)
152 				(clos->env_next - aev_timer) &
153 				AEV_TIMESTAMP_MASK;
154 EGDBG(log_printf(D3LOG, "%d: ", clos->env_next);)
155 		switch(clos->env_state)
156 		{
157 		  case PES_START:
158 			duration = 0;
159 			target = p->param[APP_ENV_L0];
160 			clos->env_state = PES_START2;
161 			clos->queued_stop = 0;
162 			break;
163 		  case PES_START2:
164 			duration = S2S(p->param[APP_ENV_DELAY]);
165 			target = p->param[APP_ENV_L0];
166 			clos->env_state = PES_DELAY;
167 			clos->queued_stop = 0;
168 			break;
169 		  case PES_DELAY:
170 			duration = S2S(p->param[APP_ENV_T1]);
171 			target = p->param[APP_ENV_L1];
172 			clos->env_state = PES_ATTACK;
173 			break;
174 		  case PES_ATTACK:
175 			duration = S2S(p->param[APP_ENV_HOLD]);
176 			target = p->param[APP_ENV_L1];
177 			clos->env_state = PES_HOLD;
178 			break;
179 		  case PES_HOLD:
180 			duration = S2S(p->param[APP_ENV_T2]);
181 			target = p->param[APP_ENV_L2];
182 			clos->env_state = PES_DECAY;
183 			break;
184 		  case PES_DECAY:
185 			if(p->param[APP_ENV_T3] >= 0)
186 			{
187 				/* Timed sustain or no sustain */
188 				target = p->param[APP_ENV_L2];
189 				duration = S2S(p->param[APP_ENV_T3]);
190 				clos->env_state = PES_SUSTAIN;
191 				break;
192 			}
193 			else if(!clos->queued_stop)
194 			{
195 				/* Interactive sustain */
196 				target = p->param[APP_ENV_L2];
197 				duration = 30000;
198 				clos->env_state = PES_WAIT;
199 				break;
200 			}
201 			/* Fall though if interactive and stopped! */
202 		  case PES_SUSTAIN:
203 			duration = S2S(p->param[APP_ENV_T4]);
204 			target = 0;
205 			clos->env_state = PES_RELEASE;
206 			break;
207 		  case PES_WAIT:
208 			/* Interactive sustain */
209 			target = p->param[APP_ENV_L2];
210 			duration = 30000;
211 			break;
212 		  case PES_RELEASE:
213 			(void)aev_send0(&v->port, timestamp, VE_STOP);
214 			--c->playing;
215 		  case PES_DEAD:
216 			clos->env_next += 30000;
217 		  default:	/* Warning supressor */
218 			continue;
219 		}
220 
221 EGDBG(log_printf(D3LOG, " (duration: %d, target: %d)\n", duration, target);)
222 
223 		lvol = (clos->lvol >> 1) * target >> 15;
224 		rvol = (clos->rvol >> 1) * target >> 15;
225 		lsend = (clos->lsend >> 1) * target >> 15;
226 		rsend = (clos->rsend >> 1) * target >> 15;
227 		(void)aev_sendi2(&v->port, t, VE_IRAMP,
228 				VIC_LVOL, lvol, duration);
229 		(void)aev_sendi2(&v->port, t, VE_IRAMP,
230 				VIC_RVOL, rvol, duration);
231 		if(v->use_double)
232 		{
233 			(void)aev_sendi2(&v->port, t, VE_IRAMP,
234 					VIC_LSEND, lsend, duration);
235 			(void)aev_sendi2(&v->port, t, VE_IRAMP,
236 					VIC_RSEND, rsend, duration);
237 		}
238 		clos->env_next += duration;
239 	}
240 }
241 
242 
_env_run_all(audio_patch_t * p,audio_channel_t * c,unsigned frames)243 static void _env_run_all(audio_patch_t *p, audio_channel_t *c, unsigned frames)
244 {
245 	audio_voice_t *v = chan_get_first_voice(c);
246 	while(v)
247 	{
248 		__env_run(p, c, v, frames);
249 		v = chan_get_next_voice(v);
250 	}
251 }
252 
253 
__start_voice(audio_patch_t * p,audio_channel_t * c,audio_voice_t * v,int wave,int pitch,int velocity)254 static inline void __start_voice(audio_patch_t *p, audio_channel_t *c,
255 		audio_voice_t *v, int wave, int pitch, int velocity)
256 {
257 	patch_closure_t *clos = &v->closure;
258 
259 	/* Apply random pitch */
260 	pitch = __calc_randpitch(p, pitch);
261 
262 	/* Store base pitch and vel to closure */
263  	clos->pitch = pitch;
264 	clos->velocity = velocity;
265 
266 	/* Transform to get actual pitch */
267 	pitch += c->ctl[ACC_PITCH];
268 	pitch -= 60<<16;
269 
270 	/* Start voice! */
271 	(void)aev_sendi1(&v->port, 0, VE_SET, VC_PRIM_BUS,
272 			c->ctl[ACC_PRIM_BUS]);
273 	(void)aev_sendi1(&v->port, 0, VE_SET, VC_SEND_BUS,
274 			c->ctl[ACC_SEND_BUS]);
275 	(void)aev_send1(&v->port, 0, VE_START, wave);
276 	(void)aev_sendi1(&v->port, 0, VE_SET, VC_PITCH, pitch);
277 
278 	/* Calculate "base volume" for envelope */
279 	clos->velvol = c->ctl[ACC_VOLUME] >> (16-VOL_BITS);
280 	clos->velvol *= velocity;
281 	clos->velvol >>= 16;
282 	__env_control_recalc(p, c, v);
283 
284 	/* Initialize and start envelope */
285 	__env_start(p, c, v);
286 
287 	++c->playing;
288 }
289 
290 
291 /*----------------------------------------------------------
292 	Default patches for polyphonic wave playback
293 ----------------------------------------------------------*/
294 
poly_start(audio_patch_t * p,audio_channel_t * c,int tag,int pitch,int velocity)295 static inline void poly_start(audio_patch_t *p, audio_channel_t *c, int tag,
296 		int pitch, int velocity)
297 {
298 	int voice;
299 	int wave = __get_wave(p);
300 	if(wave < 0)
301 		return;
302 
303 	voice = voice_alloc(c);
304 	if(voice < 0)
305 		return;
306 
307 	__start_voice(p, c, voicetab + voice, wave, pitch, velocity);
308 	voicetab[voice].tag = tag;
309 }
310 
311 
poly_stop(audio_patch_t * p,audio_channel_t * c,int tag,int velocity)312 static inline void poly_stop(audio_patch_t *p, audio_channel_t *c, int tag, int velocity)
313 {
314 	if(tag < 0)
315 	{
316 		audio_voice_t *v = chan_get_first_voice(c);
317 		while(v)
318 		{
319 			__env_stop(p, c, v);
320 			v = chan_get_next_voice(v);
321 		}
322 	}
323 	else
324 	{
325 		audio_voice_t *v = chan_get_first_voice(c);
326 		while(v)
327 		{
328 			if(v->tag == tag)
329 			{
330 				__env_stop(p, c, v);
331 				return;
332 			}
333 			v = chan_get_next_voice(v);
334 		}
335 	}
336 }
337 
338 
poly_control(audio_patch_t * p,audio_channel_t * c,int tag,int ctl,int arg)339 static inline void poly_control(audio_patch_t *p, audio_channel_t *c, int tag,
340 		int ctl, int arg)
341 {
342 	int mask;
343 	if(AVT_ALL == tag)
344 		mask = tag = 0;
345 	else
346 		mask = -1;
347 
348 	switch(ctl)
349 	{
350 	  case ACC_GROUP:
351 	  case ACC_PRIORITY:
352 	  case ACC_PATCH:
353 		break;
354 	  case ACC_PRIM_BUS:
355 	  {
356 		audio_voice_t *v = chan_get_first_voice(c);
357 		while(v)
358 		{
359 			if((v->tag & mask) == tag)
360 				v->c[VC_PRIM_BUS] = arg;
361 			v = chan_get_next_voice(v);
362 		}
363 		break;
364 	  }
365 	  case ACC_SEND_BUS:
366 	  {
367 		audio_voice_t *v = chan_get_first_voice(c);
368 		while(v)
369 		{
370 			if((v->tag & mask) == tag)
371 				v->c[VC_SEND_BUS] = arg;
372 			v = chan_get_next_voice(v);
373 		}
374 		break;
375 	  }
376 	  case ACC_PITCH:
377 	  {
378 		audio_voice_t *v = chan_get_first_voice(c);
379 		while(v)
380 		{
381 			int pitch;
382 			if((v->tag & mask) == tag)
383 			{
384 				pitch = c->ctl[ACC_PITCH];
385 				pitch += v->closure.pitch;
386 				pitch -= 60<<16;
387 				(void)aev_sendi1(&v->port, 0, VE_SET,
388 						VC_PITCH, pitch);
389 			}
390 			v = chan_get_next_voice(v);
391 		}
392 		break;
393 	  }
394 	  case ACC_PAN:
395 	  case ACC_VOLUME:
396 	  case ACC_SEND:
397 	  {
398 		audio_voice_t *v = chan_get_first_voice(c);
399 		while(v)
400 		{
401 			if((v->tag & mask) == tag)
402 			{
403 /*
404 TODO:	Ramping...
405 */
406 				__env_control_recalc(p, c, v);
407 			}
408 			v = chan_get_next_voice(v);
409 		}
410 		break;
411 	  }
412 	}
413 }
414 
415 
poly_process(audio_patch_t * p,audio_channel_t * c,unsigned frames)416 static void poly_process(audio_patch_t *p, audio_channel_t *c, unsigned frames)
417 {
418 	unsigned eframes = frames ? frames : 1;
419 	while(aev_next(&c->port, 0) < eframes)
420 	{
421 		aev_event_t *ev = aev_read(&c->port);
422 		switch(ev->type)
423 		{
424 		  case CE_START:
425 EDBG(log_printf(DLOG, "poly: CE_START %d\n", p->param[APP_WAVE]);)
426 			poly_start(p, c, ev->arg1, ev->arg2, ev->arg3);
427 			break;
428 		  case CE_STOP:
429 EDBG(log_printf(DLOG, "poly: CE_STOP\n");)
430 			poly_stop(p, c, ev->arg1, ev->arg2);
431 			break;
432 		  case CE_CONTROL:
433 EDBG(log_printf(DLOG, "poly: CE_CONTROL %d = %d\n", ev->index, ev->arg2);)
434 			c->ctl[ev->index] = ev->arg2;
435 			if(AVT_FUTURE != ev->arg1)
436 				poly_control(p, c, ev->arg1, ev->index, ev->arg2);
437 			break;
438 		}
439 		aev_free(ev);
440 	}
441 /*
442 FIXME: We need to split buffers or something for control
443 FIXME: events that affect the envelope generators!
444 */
445 	if(frames)
446 		_env_run_all(p, c, frames);
447 }
448 
449 
450 /*----------------------------------------------------------
451 	Default patches for monophonic wave playback
452 ----------------------------------------------------------*/
453 
mono_start(audio_patch_t * p,audio_channel_t * c,int tag,int pitch,int velocity)454 static void mono_start(audio_patch_t *p, audio_channel_t *c, int tag,
455 		int pitch, int velocity)
456 {
457 	int wave = __get_wave(p);
458 	if(wave < 0)
459 		return;
460 
461 	if(voice_alloc(c) < 0)
462 		return;
463 
464 	__start_voice(p, c, c->voices, wave, pitch, velocity);
465 	c->voices->tag = tag;
466 	c->playing = 1;
467 }
468 
469 
mono_stop(audio_patch_t * p,audio_channel_t * c,int tag,int velocity)470 static void mono_stop(audio_patch_t *p, audio_channel_t *c, int tag, int velocity)
471 {
472 	if(!c->voices)
473 		return;
474 	if(c->voices->channel != c)
475 		return;
476 	__env_stop(p, c, c->voices);
477 	c->playing = 0;
478 }
479 
480 
mono_control(audio_patch_t * p,audio_channel_t * c,int tag,int ctl,int arg)481 static void mono_control(audio_patch_t * p, audio_channel_t *c, int tag,
482 		int ctl, int arg)
483 {
484 	audio_voice_t *v = c->voices;
485 	if(!v)
486 		return;
487 	if(v->channel != c)
488 		return;
489 
490 	switch (ctl)
491 	{
492 	  case ACC_GROUP:	/* We don't care. */
493 	  case ACC_PRIORITY:	/* Only for *new* voices. */
494 	  case ACC_PATCH:	/* We just got selected. And? :-) */
495 		break;
496 	  case ACC_PRIM_BUS:
497 		(void)aev_sendi1(&v->port, 0, VE_SET, VC_PRIM_BUS, arg);
498 		break;
499 	  case ACC_SEND_BUS:
500 		(void)aev_sendi1(&v->port, 0, VE_SET, VC_SEND_BUS, arg);
501 		break;
502 	  case ACC_PITCH:
503 		(void)aev_sendi1(&v->port, 0, VE_SET, VC_PITCH, arg);
504 		break;
505 	  case ACC_PAN:
506 	  case ACC_VOLUME:
507 	  case ACC_SEND:
508 		__env_control_recalc(p, c, v);
509 		break;
510 	}
511 }
512 
513 
mono_process(audio_patch_t * p,audio_channel_t * c,unsigned frames)514 static void mono_process(audio_patch_t *p, audio_channel_t *c, unsigned frames)
515 {
516 	unsigned eframes = frames ? frames : 1;
517 	while(aev_next(&c->port, 0) < eframes)
518 	{
519 		aev_event_t *ev = aev_read(&c->port);
520 		switch(ev->type)
521 		{
522 		  case CE_START:
523 EDBG(log_printf(DLOG, "mono: CE_START %d\n", p->param[APP_WAVE]);)
524 			mono_start(p, c, ev->arg1, ev->arg2, ev->arg3);
525 			break;
526 		  case CE_STOP:
527 EDBG(log_printf(DLOG, "mono: CE_STOP\n");)
528 			mono_stop(p, c, ev->arg1, ev->arg2);
529 			break;
530 		  case CE_CONTROL:
531 EDBG(log_printf(DLOG, "mono: CE_CONTROL %d = %d\n", ev->index, ev->arg2);)
532 			c->ctl[ev->index] = ev->arg2;
533 			if(ACC_PATCH == ev->index)
534 				p = patchtab + c->ctl[ACC_PATCH];
535 			if(AVT_FUTURE != ev->arg1)
536 				mono_control(p, c, ev->arg1, ev->index, ev->arg2);
537 			break;
538 		}
539 		aev_free(ev);
540 	}
541 	if(frames)
542 		_env_run_all(p, c, frames);
543 }
544 
545 
546 /*----------------------------------------------------------
547 	Default patch for MIDI playback
548 ----------------------------------------------------------*/
549 
midi_start(audio_patch_t * p,audio_channel_t * c,int tag,int pitch,int velocity)550 static void midi_start(audio_patch_t *p, audio_channel_t *c, int tag,
551 		int pitch, int velocity)
552 {
553 	int wave = p->param[APP_WAVE];
554 	if((wave < 0) || (wave >= AUDIO_MAX_WAVES))
555 		return;
556 
557 	if(AF_MIDI != wavetab[wave].format)
558 		return;		/* Can't play this! */
559 
560 	pitch = __calc_randpitch(p, pitch);
561 	pitch += c->ctl[ACC_PITCH];
562 	pitch -= 60<<16;
563 	if(pitch < 0)
564 		pitch = 0;
565 	else if(pitch > 128<<16)
566 		pitch = 128<<16;
567 	if(sequencer_play(wavetab[wave].data.midi, tag, pitch, velocity) < 0)
568 		return;
569 
570 	++c->playing;
571 }
572 
573 
midi_process(audio_patch_t * p,audio_channel_t * c,unsigned frames)574 static void midi_process(audio_patch_t *p, audio_channel_t *c, unsigned frames)
575 {
576 	unsigned eframes = frames ? frames : 1;
577 	while(aev_next(&c->port, 0) < eframes)
578 	{
579 		aev_event_t *ev = aev_read(&c->port);
580 		switch(ev->type)
581 		{
582 		  case CE_START:
583 EDBG(log_printf(DLOG, "midi: CE_START %d\n", p->param[APP_WAVE]);)
584 			midi_start(p, c, ev->arg1, ev->arg2, ev->arg3);
585 			break;
586 		  case CE_STOP:
587 EDBG(log_printf(DLOG, "midi: CE_STOP\n");)
588 /*
589 FIXME:	Handle cid == -1 correctly!
590 */
591 			c->playing = 0;
592 			sequencer_stop(ev->arg1);
593 			break;
594 		  case CE_CONTROL:
595 EDBG(log_printf(DLOG, "midi: CE_CONTROL %d = %d\n", ev->index, ev->arg2);)
596 			c->ctl[ev->index] = ev->arg2;
597 			break;
598 		}
599 		aev_free(ev);
600 	}
601 
602 	/* This is where to run the sequencer. */
603 }
604 
605 
606 /*----------------------------------------------------------
607 	User EEL Patch Driver
608 ----------------------------------------------------------*/
609 
eel_process(audio_patch_t * p,audio_channel_t * c,unsigned frames)610 static void eel_process(audio_patch_t *p, audio_channel_t *c, unsigned frames)
611 {
612 	unsigned eframes = frames ? frames : 1;
613 	while(aev_next(&c->port, 0) < eframes)
614 	{
615 		aev_event_t *ev = aev_read(&c->port);
616 		switch(ev->type)
617 		{
618 		  case CE_START:
619 EDBG(log_printf(DLOG, "eel: CE_START %d\n", p->param[APP_WAVE]);)
620 			break;
621 		  case CE_STOP:
622 EDBG(log_printf(DLOG, "eel: CE_STOP\n");)
623 			break;
624 		  case CE_CONTROL:
625 EDBG(log_printf(DLOG, "eel: CE_CONTROL %d = %d\n", ev->index, ev->arg2);)
626 			c->ctl[ev->index] = ev->arg2;
627 			break;
628 		}
629 		aev_free(ev);
630 	}
631 
632 	/* Run timer driven EEL code here. */
633 }
634 
635 
636 /*----------------------------------------------------------
637 	Dummy Patch Driver
638 ----------------------------------------------------------*/
639 
dummy_process(audio_patch_t * p,audio_channel_t * c,unsigned frames)640 static void dummy_process(audio_patch_t *p, audio_channel_t *c, unsigned frames)
641 {
642 	unsigned eframes = frames ? frames : 1;
643 	while(aev_next(&c->port, 0) < eframes)
644 	{
645 		aev_event_t *ev = aev_read(&c->port);
646 		switch(ev->type)
647 		{
648 		  case CE_START:
649 EDBG(log_printf(DLOG, "dummy: CE_START %d\n", p->param[APP_WAVE]);)
650 			break;
651 		  case CE_STOP:
652 EDBG(log_printf(DLOG, "dummy: CE_STOP\n");)
653 			break;
654 		  case CE_CONTROL:
655 EDBG(log_printf(DLOG, "dummy: CE_CONTROL %d = %d\n", ev->index, ev->arg2);)
656 			c->ctl[ev->index] = ev->arg2;
657 			break;
658 		}
659 		aev_free(ev);
660 	}
661 }
662 
663 
664 /*----------------------------------------------------------
665 	Patch programming API
666 ----------------------------------------------------------*/
667 
668 /* Set parameter for a patch */
audio_patch_param(int pid,int pparam,int value)669 void audio_patch_param(int pid, int pparam, int value)
670 {
671 	CHECKINIT
672 
673 	if(pid < 0)
674 		return;
675 	if(pid >= AUDIO_MAX_PATCHES)
676 		return;
677 
678 	if(pparam < 0)
679 		return;
680 	if(pparam > APP_LAST)
681 		return;
682 
683 	if(APP_DRIVER == pparam)
684 	{
685 		switch(value)
686 		{
687 		  case PD_MONO:
688 			patchtab[pid].process = mono_process;
689 			break;
690 		  case PD_POLY:
691 			patchtab[pid].process = poly_process;
692 			break;
693 		  case PD_MIDI:
694 			patchtab[pid].process = midi_process;
695 			break;
696 		  case PD_EEL:
697 			patchtab[pid].process = eel_process;
698 			break;
699 		  default:
700 			patchtab[pid].process = dummy_process;
701 			log_printf(ELOG, "a_patch.c: Illegal patch"
702 					" driver selected!\n");
703 			break;
704 		}
705 	}
706 
707 	patchtab[pid].param[pparam] = value;
708 }
709 
710 
711 /*----------------------------------------------------------
712 	Global init
713 ----------------------------------------------------------*/
714 
audio_patch_open(void)715 void audio_patch_open(void)
716 {
717 	int i;
718 	if(_is_open)
719 		return;
720 
721 	memset(patchtab, 0, sizeof(patchtab));
722 	for(i = 0; i < AUDIO_MAX_PATCHES; ++i)
723 	{
724 /*
725 		patchtab[i].param[APP_DRIVER] = PD_NONE;
726 		patchtab[i].process = dummy_process;
727 */
728 /*
729 FIXME: This hack is just until the EEL<->patch binding is sorted out.
730 */
731 		patchtab[i].param[APP_DRIVER] = PD_POLY;
732 		patchtab[i].process = poly_process;
733 
734 		patchtab[i].param[APP_WAVE] = i;
735 		patchtab[i].param[APP_ENV_L0] = 1<<16;
736 		patchtab[i].param[APP_ENV_L1] = 1<<16;
737 		patchtab[i].param[APP_ENV_L2] = 1<<16;
738 		patchtab[i].param[APP_ENV_T3] = -1;
739 		patchtab[i].param[APP_ENV_T4] = (1<<16) / 100;
740 		patchtab[i].param[APP_ENV2VOL] = 1<<16;
741 	}
742 	_is_open = 1;
743 }
744 
745 
audio_patch_close(void)746 void audio_patch_close(void)
747 {
748 	if(!_is_open)
749 		return;
750 
751 	memset(patchtab, 0, sizeof(patchtab));
752 	_is_open = 0;
753 }
754