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