blob: b343818dbb964ae3137b7e90c08284ffa03e92c6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Midi synth routines for the Emu8k/Emu10k1
3 *
4 * Copyright (C) 1999 Steve Ratcliffe
5 * Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de>
6 *
7 * Contains code based on awe_wave.c by Takashi Iwai
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include "emux_voice.h"
26#include <sound/asoundef.h>
27
28/*
29 * Prototypes
30 */
31
32/*
33 * Ensure a value is between two points
34 * macro evaluates its args more than once, so changed to upper-case.
35 */
36#define LIMITVALUE(x, a, b) do { if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b); } while (0)
37#define LIMITMAX(x, a) do {if ((x) > (a)) (x) = (a); } while (0)
38
Takashi Iwai03da3122005-11-17 14:24:47 +010039static int get_zone(struct snd_emux *emu, struct snd_emux_port *port,
40 int *notep, int vel, struct snd_midi_channel *chan,
41 struct snd_sf_zone **table);
42static int get_bank(struct snd_emux_port *port, struct snd_midi_channel *chan);
43static void terminate_note1(struct snd_emux *emu, int note,
44 struct snd_midi_channel *chan, int free);
45static void exclusive_note_off(struct snd_emux *emu, struct snd_emux_port *port,
46 int exclass);
47static void terminate_voice(struct snd_emux *emu, struct snd_emux_voice *vp, int free);
48static void update_voice(struct snd_emux *emu, struct snd_emux_voice *vp, int update);
49static void setup_voice(struct snd_emux_voice *vp);
50static int calc_pan(struct snd_emux_voice *vp);
51static int calc_volume(struct snd_emux_voice *vp);
52static int calc_pitch(struct snd_emux_voice *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54
55/*
56 * Start a note.
57 */
58void
Takashi Iwai03da3122005-11-17 14:24:47 +010059snd_emux_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060{
Takashi Iwai03da3122005-11-17 14:24:47 +010061 struct snd_emux *emu;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 int i, key, nvoices;
Takashi Iwai03da3122005-11-17 14:24:47 +010063 struct snd_emux_voice *vp;
64 struct snd_sf_zone *table[SNDRV_EMUX_MAX_MULTI_VOICES];
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 unsigned long flags;
Takashi Iwai03da3122005-11-17 14:24:47 +010066 struct snd_emux_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68 port = p;
69 snd_assert(port != NULL && chan != NULL, return);
70
71 emu = port->emu;
72 snd_assert(emu != NULL, return);
73 snd_assert(emu->ops.get_voice != NULL, return);
74 snd_assert(emu->ops.trigger != NULL, return);
75
76 key = note; /* remember the original note */
77 nvoices = get_zone(emu, port, &note, vel, chan, table);
78 if (! nvoices)
79 return;
80
81 /* exclusive note off */
82 for (i = 0; i < nvoices; i++) {
Takashi Iwai03da3122005-11-17 14:24:47 +010083 struct snd_sf_zone *zp = table[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 if (zp && zp->v.exclusiveClass)
85 exclusive_note_off(emu, port, zp->v.exclusiveClass);
86 }
87
88#if 0 // seems not necessary
89 /* Turn off the same note on the same channel. */
90 terminate_note1(emu, key, chan, 0);
91#endif
92
93 spin_lock_irqsave(&emu->voice_lock, flags);
94 for (i = 0; i < nvoices; i++) {
95
96 /* set up each voice parameter */
97 /* at this stage, we don't trigger the voice yet. */
98
99 if (table[i] == NULL)
100 continue;
101
102 vp = emu->ops.get_voice(emu, port);
103 if (vp == NULL || vp->ch < 0)
104 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 if (STATE_IS_PLAYING(vp->state))
106 emu->ops.terminate(vp);
107
108 vp->time = emu->use_time++;
109 vp->chan = chan;
110 vp->port = port;
111 vp->key = key;
112 vp->note = note;
113 vp->velocity = vel;
114 vp->zone = table[i];
115 if (vp->zone->sample)
116 vp->block = vp->zone->sample->block;
117 else
118 vp->block = NULL;
119
120 setup_voice(vp);
121
122 vp->state = SNDRV_EMUX_ST_STANDBY;
123 if (emu->ops.prepare) {
124 vp->state = SNDRV_EMUX_ST_OFF;
125 if (emu->ops.prepare(vp) >= 0)
126 vp->state = SNDRV_EMUX_ST_STANDBY;
127 }
128 }
129
130 /* start envelope now */
131 for (i = 0; i < emu->max_voices; i++) {
132 vp = &emu->voices[i];
133 if (vp->state == SNDRV_EMUX_ST_STANDBY &&
134 vp->chan == chan) {
135 emu->ops.trigger(vp);
136 vp->state = SNDRV_EMUX_ST_ON;
137 vp->ontime = jiffies; /* remember the trigger timing */
138 }
139 }
140 spin_unlock_irqrestore(&emu->voice_lock, flags);
141
142#ifdef SNDRV_EMUX_USE_RAW_EFFECT
143 if (port->port_mode == SNDRV_EMUX_PORT_MODE_OSS_SYNTH) {
144 /* clear voice position for the next note on this channel */
Takashi Iwai03da3122005-11-17 14:24:47 +0100145 struct snd_emux_effect_table *fx = chan->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 if (fx) {
147 fx->flag[EMUX_FX_SAMPLE_START] = 0;
148 fx->flag[EMUX_FX_COARSE_SAMPLE_START] = 0;
149 }
150 }
151#endif
152}
153
154/*
155 * Release a note in response to a midi note off.
156 */
157void
Takashi Iwai03da3122005-11-17 14:24:47 +0100158snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
160 int ch;
Takashi Iwai03da3122005-11-17 14:24:47 +0100161 struct snd_emux *emu;
162 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 unsigned long flags;
Takashi Iwai03da3122005-11-17 14:24:47 +0100164 struct snd_emux_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 port = p;
167 snd_assert(port != NULL && chan != NULL, return);
168
169 emu = port->emu;
170 snd_assert(emu != NULL, return);
171 snd_assert(emu->ops.release != NULL, return);
172
173 spin_lock_irqsave(&emu->voice_lock, flags);
174 for (ch = 0; ch < emu->max_voices; ch++) {
175 vp = &emu->voices[ch];
176 if (STATE_IS_PLAYING(vp->state) &&
177 vp->chan == chan && vp->key == note) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 vp->state = SNDRV_EMUX_ST_RELEASED;
179 if (vp->ontime == jiffies) {
180 /* if note-off is sent too shortly after
181 * note-on, emuX engine cannot produce the sound
182 * correctly. so we'll release this note
183 * a bit later via timer callback.
184 */
185 vp->state = SNDRV_EMUX_ST_PENDING;
186 if (! emu->timer_active) {
187 emu->tlist.expires = jiffies + 1;
188 add_timer(&emu->tlist);
189 emu->timer_active = 1;
190 }
191 } else
192 /* ok now release the note */
193 emu->ops.release(vp);
194 }
195 }
196 spin_unlock_irqrestore(&emu->voice_lock, flags);
197}
198
199/*
200 * timer callback
201 *
202 * release the pending note-offs
203 */
204void snd_emux_timer_callback(unsigned long data)
205{
Takashi Iwai03da3122005-11-17 14:24:47 +0100206 struct snd_emux *emu = (struct snd_emux *) data;
207 struct snd_emux_voice *vp;
Takashi Iwaib32425a2005-11-18 18:52:14 +0100208 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 int ch, do_again = 0;
210
Takashi Iwaib32425a2005-11-18 18:52:14 +0100211 spin_lock_irqsave(&emu->voice_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 for (ch = 0; ch < emu->max_voices; ch++) {
213 vp = &emu->voices[ch];
214 if (vp->state == SNDRV_EMUX_ST_PENDING) {
215 if (vp->ontime == jiffies)
216 do_again++; /* release this at the next interrupt */
217 else {
218 emu->ops.release(vp);
219 vp->state = SNDRV_EMUX_ST_RELEASED;
220 }
221 }
222 }
223 if (do_again) {
224 emu->tlist.expires = jiffies + 1;
225 add_timer(&emu->tlist);
226 emu->timer_active = 1;
227 } else
228 emu->timer_active = 0;
Takashi Iwaib32425a2005-11-18 18:52:14 +0100229 spin_unlock_irqrestore(&emu->voice_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
231
232/*
233 * key pressure change
234 */
235void
Takashi Iwai03da3122005-11-17 14:24:47 +0100236snd_emux_key_press(void *p, int note, int vel, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 int ch;
Takashi Iwai03da3122005-11-17 14:24:47 +0100239 struct snd_emux *emu;
240 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 unsigned long flags;
Takashi Iwai03da3122005-11-17 14:24:47 +0100242 struct snd_emux_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 port = p;
245 snd_assert(port != NULL && chan != NULL, return);
246
247 emu = port->emu;
248 snd_assert(emu != NULL, return);
249 snd_assert(emu->ops.update != NULL, return);
250
251 spin_lock_irqsave(&emu->voice_lock, flags);
252 for (ch = 0; ch < emu->max_voices; ch++) {
253 vp = &emu->voices[ch];
254 if (vp->state == SNDRV_EMUX_ST_ON &&
255 vp->chan == chan && vp->key == note) {
256 vp->velocity = vel;
257 update_voice(emu, vp, SNDRV_EMUX_UPDATE_VOLUME);
258 }
259 }
260 spin_unlock_irqrestore(&emu->voice_lock, flags);
261}
262
263
264/*
265 * Modulate the voices which belong to the channel
266 */
267void
Takashi Iwai03da3122005-11-17 14:24:47 +0100268snd_emux_update_channel(struct snd_emux_port *port, struct snd_midi_channel *chan, int update)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
Takashi Iwai03da3122005-11-17 14:24:47 +0100270 struct snd_emux *emu;
271 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 int i;
273 unsigned long flags;
274
275 if (! update)
276 return;
277
278 emu = port->emu;
279 snd_assert(emu != NULL, return);
280 snd_assert(emu->ops.update != NULL, return);
281
282 spin_lock_irqsave(&emu->voice_lock, flags);
283 for (i = 0; i < emu->max_voices; i++) {
284 vp = &emu->voices[i];
285 if (vp->chan == chan)
286 update_voice(emu, vp, update);
287 }
288 spin_unlock_irqrestore(&emu->voice_lock, flags);
289}
290
291/*
292 * Modulate all the voices which belong to the port.
293 */
294void
Takashi Iwai03da3122005-11-17 14:24:47 +0100295snd_emux_update_port(struct snd_emux_port *port, int update)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Takashi Iwai03da3122005-11-17 14:24:47 +0100297 struct snd_emux *emu;
298 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 int i;
300 unsigned long flags;
301
302 if (! update)
303 return;
304
305 emu = port->emu;
306 snd_assert(emu != NULL, return);
307 snd_assert(emu->ops.update != NULL, return);
308
309 spin_lock_irqsave(&emu->voice_lock, flags);
310 for (i = 0; i < emu->max_voices; i++) {
311 vp = &emu->voices[i];
312 if (vp->port == port)
313 update_voice(emu, vp, update);
314 }
315 spin_unlock_irqrestore(&emu->voice_lock, flags);
316}
317
318
319/*
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200320 * Deal with a controller type event. This includes all types of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 * control events, not just the midi controllers
322 */
323void
Takashi Iwai03da3122005-11-17 14:24:47 +0100324snd_emux_control(void *p, int type, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Takashi Iwai03da3122005-11-17 14:24:47 +0100326 struct snd_emux_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 port = p;
329 snd_assert(port != NULL && chan != NULL, return);
330
331 switch (type) {
332 case MIDI_CTL_MSB_MAIN_VOLUME:
333 case MIDI_CTL_MSB_EXPRESSION:
334 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_VOLUME);
335 break;
336
337 case MIDI_CTL_MSB_PAN:
338 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN);
339 break;
340
341 case MIDI_CTL_SOFT_PEDAL:
342#ifdef SNDRV_EMUX_USE_RAW_EFFECT
343 /* FIXME: this is an emulation */
maximilian attemsbf911412008-05-09 13:43:09 +0200344 if (chan->control[type] >= 64)
345 snd_emux_send_effect(port, chan, EMUX_FX_CUTOFF, -160,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 EMUX_FX_FLAG_ADD);
maximilian attemsbf911412008-05-09 13:43:09 +0200347 else
348 snd_emux_send_effect(port, chan, EMUX_FX_CUTOFF, 0,
349 EMUX_FX_FLAG_OFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350#endif
351 break;
352
353 case MIDI_CTL_PITCHBEND:
354 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PITCH);
355 break;
356
357 case MIDI_CTL_MSB_MODWHEEL:
358 case MIDI_CTL_CHAN_PRESSURE:
359 snd_emux_update_channel(port, chan,
360 SNDRV_EMUX_UPDATE_FMMOD |
361 SNDRV_EMUX_UPDATE_FM2FRQ2);
362 break;
363
364 }
365
366 if (port->chset.midi_mode == SNDRV_MIDI_MODE_XG) {
367 snd_emux_xg_control(port, chan, type);
368 }
369}
370
371
372/*
373 * terminate note - if free flag is true, free the terminated voice
374 */
375static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100376terminate_note1(struct snd_emux *emu, int note, struct snd_midi_channel *chan, int free)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378 int i;
Takashi Iwai03da3122005-11-17 14:24:47 +0100379 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 unsigned long flags;
381
382 spin_lock_irqsave(&emu->voice_lock, flags);
383 for (i = 0; i < emu->max_voices; i++) {
384 vp = &emu->voices[i];
385 if (STATE_IS_PLAYING(vp->state) && vp->chan == chan &&
386 vp->key == note)
387 terminate_voice(emu, vp, free);
388 }
389 spin_unlock_irqrestore(&emu->voice_lock, flags);
390}
391
392
393/*
394 * terminate note - exported for midi emulation
395 */
396void
Takashi Iwai03da3122005-11-17 14:24:47 +0100397snd_emux_terminate_note(void *p, int note, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
Takashi Iwai03da3122005-11-17 14:24:47 +0100399 struct snd_emux *emu;
400 struct snd_emux_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 port = p;
403 snd_assert(port != NULL && chan != NULL, return);
404
405 emu = port->emu;
406 snd_assert(emu != NULL, return);
407 snd_assert(emu->ops.terminate != NULL, return);
408
409 terminate_note1(emu, note, chan, 1);
410}
411
412
413/*
414 * Terminate all the notes
415 */
416void
Takashi Iwai03da3122005-11-17 14:24:47 +0100417snd_emux_terminate_all(struct snd_emux *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
419 int i;
Takashi Iwai03da3122005-11-17 14:24:47 +0100420 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 unsigned long flags;
422
423 spin_lock_irqsave(&emu->voice_lock, flags);
424 for (i = 0; i < emu->max_voices; i++) {
425 vp = &emu->voices[i];
426 if (STATE_IS_PLAYING(vp->state))
427 terminate_voice(emu, vp, 0);
428 if (vp->state == SNDRV_EMUX_ST_OFF) {
429 if (emu->ops.free_voice)
430 emu->ops.free_voice(vp);
431 if (emu->ops.reset)
432 emu->ops.reset(emu, i);
433 }
434 vp->time = 0;
435 }
436 /* initialize allocation time */
437 emu->use_time = 0;
438 spin_unlock_irqrestore(&emu->voice_lock, flags);
439}
440
Takashi Iwai95ff17562006-04-28 15:13:40 +0200441EXPORT_SYMBOL(snd_emux_terminate_all);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443/*
444 * Terminate all voices associated with the given port
445 */
446void
Takashi Iwai03da3122005-11-17 14:24:47 +0100447snd_emux_sounds_off_all(struct snd_emux_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 int i;
Takashi Iwai03da3122005-11-17 14:24:47 +0100450 struct snd_emux *emu;
451 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 unsigned long flags;
453
454 snd_assert(port != NULL, return);
455 emu = port->emu;
456 snd_assert(emu != NULL, return);
457 snd_assert(emu->ops.terminate != NULL, return);
458
459 spin_lock_irqsave(&emu->voice_lock, flags);
460 for (i = 0; i < emu->max_voices; i++) {
461 vp = &emu->voices[i];
462 if (STATE_IS_PLAYING(vp->state) &&
463 vp->port == port)
464 terminate_voice(emu, vp, 0);
465 if (vp->state == SNDRV_EMUX_ST_OFF) {
466 if (emu->ops.free_voice)
467 emu->ops.free_voice(vp);
468 if (emu->ops.reset)
469 emu->ops.reset(emu, i);
470 }
471 }
472 spin_unlock_irqrestore(&emu->voice_lock, flags);
473}
474
475
476/*
477 * Terminate all voices that have the same exclusive class. This
478 * is mainly for drums.
479 */
480static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100481exclusive_note_off(struct snd_emux *emu, struct snd_emux_port *port, int exclass)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Takashi Iwai03da3122005-11-17 14:24:47 +0100483 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 int i;
485 unsigned long flags;
486
487 spin_lock_irqsave(&emu->voice_lock, flags);
488 for (i = 0; i < emu->max_voices; i++) {
489 vp = &emu->voices[i];
490 if (STATE_IS_PLAYING(vp->state) && vp->port == port &&
491 vp->reg.exclusiveClass == exclass) {
492 terminate_voice(emu, vp, 0);
493 }
494 }
495 spin_unlock_irqrestore(&emu->voice_lock, flags);
496}
497
498/*
499 * terminate a voice
500 * if free flag is true, call free_voice after termination
501 */
502static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100503terminate_voice(struct snd_emux *emu, struct snd_emux_voice *vp, int free)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 emu->ops.terminate(vp);
506 vp->time = emu->use_time++;
507 vp->chan = NULL;
508 vp->port = NULL;
509 vp->zone = NULL;
510 vp->block = NULL;
511 vp->state = SNDRV_EMUX_ST_OFF;
512 if (free && emu->ops.free_voice)
513 emu->ops.free_voice(vp);
514}
515
516
517/*
518 * Modulate the voice
519 */
520static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100521update_voice(struct snd_emux *emu, struct snd_emux_voice *vp, int update)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522{
523 if (!STATE_IS_PLAYING(vp->state))
524 return;
525
526 if (vp->chan == NULL || vp->port == NULL)
527 return;
528 if (update & SNDRV_EMUX_UPDATE_VOLUME)
529 calc_volume(vp);
530 if (update & SNDRV_EMUX_UPDATE_PITCH)
531 calc_pitch(vp);
532 if (update & SNDRV_EMUX_UPDATE_PAN) {
533 if (! calc_pan(vp) && (update == SNDRV_EMUX_UPDATE_PAN))
534 return;
535 }
536 emu->ops.update(vp, update);
537}
538
539
540#if 0 // not used
541/* table for volume target calculation */
542static unsigned short voltarget[16] = {
543 0xEAC0, 0xE0C8, 0xD740, 0xCE20, 0xC560, 0xBD08, 0xB500, 0xAD58,
544 0xA5F8, 0x9EF0, 0x9830, 0x91C0, 0x8B90, 0x85A8, 0x8000, 0x7A90
545};
546#endif
547
548#define LO_BYTE(v) ((v) & 0xff)
549#define HI_BYTE(v) (((v) >> 8) & 0xff)
550
551/*
552 * Sets up the voice structure by calculating some values that
553 * will be needed later.
554 */
555static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100556setup_voice(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
Takashi Iwai03da3122005-11-17 14:24:47 +0100558 struct soundfont_voice_parm *parm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 int pitch;
560
561 /* copy the original register values */
562 vp->reg = vp->zone->v;
563
564#ifdef SNDRV_EMUX_USE_RAW_EFFECT
565 snd_emux_setup_effect(vp);
566#endif
567
568 /* reset status */
569 vp->apan = -1;
570 vp->avol = -1;
571 vp->apitch = -1;
572
573 calc_volume(vp);
574 calc_pitch(vp);
575 calc_pan(vp);
576
577 parm = &vp->reg.parm;
578
579 /* compute filter target and correct modulation parameters */
580 if (LO_BYTE(parm->modatkhld) >= 0x80 && parm->moddelay >= 0x8000) {
581 parm->moddelay = 0xbfff;
582 pitch = (HI_BYTE(parm->pefe) << 4) + vp->apitch;
583 if (pitch > 0xffff)
584 pitch = 0xffff;
585 /* calculate filter target */
586 vp->ftarget = parm->cutoff + LO_BYTE(parm->pefe);
587 LIMITVALUE(vp->ftarget, 0, 255);
588 vp->ftarget <<= 8;
589 } else {
590 vp->ftarget = parm->cutoff;
591 vp->ftarget <<= 8;
592 pitch = vp->apitch;
593 }
594
595 /* compute pitch target */
596 if (pitch != 0xffff) {
597 vp->ptarget = 1 << (pitch >> 12);
598 if (pitch & 0x800) vp->ptarget += (vp->ptarget*0x102e)/0x2710;
599 if (pitch & 0x400) vp->ptarget += (vp->ptarget*0x764)/0x2710;
600 if (pitch & 0x200) vp->ptarget += (vp->ptarget*0x389)/0x2710;
601 vp->ptarget += (vp->ptarget >> 1);
602 if (vp->ptarget > 0xffff) vp->ptarget = 0xffff;
603 } else
604 vp->ptarget = 0xffff;
605
606 if (LO_BYTE(parm->modatkhld) >= 0x80) {
607 parm->modatkhld &= ~0xff;
608 parm->modatkhld |= 0x7f;
609 }
610
611 /* compute volume target and correct volume parameters */
612 vp->vtarget = 0;
613#if 0 /* FIXME: this leads to some clicks.. */
614 if (LO_BYTE(parm->volatkhld) >= 0x80 && parm->voldelay >= 0x8000) {
615 parm->voldelay = 0xbfff;
616 vp->vtarget = voltarget[vp->avol % 0x10] >> (vp->avol >> 4);
617 }
618#endif
619
620 if (LO_BYTE(parm->volatkhld) >= 0x80) {
621 parm->volatkhld &= ~0xff;
622 parm->volatkhld |= 0x7f;
623 }
624}
625
626/*
627 * calculate pitch parameter
628 */
629static unsigned char pan_volumes[256] = {
6300x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x14,0x17,0x1a,0x1d,0x20,0x22,0x25,0x28,0x2a,
6310x2d,0x30,0x32,0x35,0x37,0x3a,0x3c,0x3f,0x41,0x44,0x46,0x49,0x4b,0x4d,0x50,0x52,
6320x54,0x57,0x59,0x5b,0x5d,0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6f,0x71,0x73,0x75,
6330x77,0x79,0x7b,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x89,0x8b,0x8d,0x8f,0x90,0x92,
6340x94,0x96,0x97,0x99,0x9a,0x9c,0x9e,0x9f,0xa1,0xa2,0xa4,0xa5,0xa7,0xa8,0xaa,0xab,
6350xad,0xae,0xaf,0xb1,0xb2,0xb3,0xb5,0xb6,0xb7,0xb9,0xba,0xbb,0xbc,0xbe,0xbf,0xc0,
6360xc1,0xc2,0xc3,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,
6370xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdc,0xdd,0xde,0xdf,
6380xdf,0xe0,0xe1,0xe2,0xe2,0xe3,0xe4,0xe4,0xe5,0xe6,0xe6,0xe7,0xe8,0xe8,0xe9,0xe9,
6390xea,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1,0xf1,0xf1,
6400xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf7,
6410xf7,0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,
6420xfb,0xfb,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,
6430xfd,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
6440xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
6450xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
646};
647
648static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100649calc_pan(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650{
Takashi Iwai03da3122005-11-17 14:24:47 +0100651 struct snd_midi_channel *chan = vp->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 int pan;
653
654 /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
655 if (vp->reg.fixpan > 0) /* 0-127 */
656 pan = 255 - (int)vp->reg.fixpan * 2;
657 else {
658 pan = chan->control[MIDI_CTL_MSB_PAN] - 64;
659 if (vp->reg.pan >= 0) /* 0-127 */
660 pan += vp->reg.pan - 64;
661 pan = 127 - (int)pan * 2;
662 }
663 LIMITVALUE(pan, 0, 255);
664
665 if (vp->emu->linear_panning) {
666 /* assuming linear volume */
667 if (pan != vp->apan) {
668 vp->apan = pan;
669 if (pan == 0)
670 vp->aaux = 0xff;
671 else
672 vp->aaux = (-pan) & 0xff;
673 return 1;
674 } else
675 return 0;
676 } else {
677 /* using volume table */
678 if (vp->apan != (int)pan_volumes[pan]) {
679 vp->apan = pan_volumes[pan];
680 vp->aaux = pan_volumes[255 - pan];
681 return 1;
682 }
683 return 0;
684 }
685}
686
687
688/*
689 * calculate volume attenuation
690 *
691 * Voice volume is controlled by volume attenuation parameter.
692 * So volume becomes maximum when avol is 0 (no attenuation), and
693 * minimum when 255 (-96dB or silence).
694 */
695
696/* tables for volume->attenuation calculation */
697static unsigned char voltab1[128] = {
698 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
699 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
700 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
701 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
702 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
703 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
704 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
705 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
706 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
707 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
708 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
709 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
710 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
711};
712
713static unsigned char voltab2[128] = {
714 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
715 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
716 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
717 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
718 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
719 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
720 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
721 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
722 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
723 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
724 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
725 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
726 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
727};
728
729static unsigned char expressiontab[128] = {
730 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
731 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
732 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
733 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
734 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
735 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
736 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
737 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
738 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
739 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
740 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
741 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
742 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
743};
744
745/*
746 * Magic to calculate the volume (actually attenuation) from all the
747 * voice and channels parameters.
748 */
749static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100750calc_volume(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
752 int vol;
753 int main_vol, expression_vol, master_vol;
Takashi Iwai03da3122005-11-17 14:24:47 +0100754 struct snd_midi_channel *chan = vp->chan;
755 struct snd_emux_port *port = vp->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757 expression_vol = chan->control[MIDI_CTL_MSB_EXPRESSION];
758 LIMITMAX(vp->velocity, 127);
759 LIMITVALUE(expression_vol, 0, 127);
760 if (port->port_mode == SNDRV_EMUX_PORT_MODE_OSS_SYNTH) {
761 /* 0 - 127 */
762 main_vol = chan->control[MIDI_CTL_MSB_MAIN_VOLUME];
763 vol = (vp->velocity * main_vol * expression_vol) / (127*127);
764 vol = vol * vp->reg.amplitude / 127;
765
766 LIMITVALUE(vol, 0, 127);
767
768 /* calc to attenuation */
769 vol = snd_sf_vol_table[vol];
770
771 } else {
772 main_vol = chan->control[MIDI_CTL_MSB_MAIN_VOLUME] * vp->reg.amplitude / 127;
773 LIMITVALUE(main_vol, 0, 127);
774
775 vol = voltab1[main_vol] + voltab2[vp->velocity];
776 vol = (vol * 8) / 3;
777 vol += vp->reg.attenuation;
778 vol += ((0x100 - vol) * expressiontab[expression_vol])/128;
779 }
780
781 master_vol = port->chset.gs_master_volume;
782 LIMITVALUE(master_vol, 0, 127);
783 vol += snd_sf_vol_table[master_vol];
784 vol += port->volume_atten;
785
786#ifdef SNDRV_EMUX_USE_RAW_EFFECT
787 if (chan->private) {
Takashi Iwai03da3122005-11-17 14:24:47 +0100788 struct snd_emux_effect_table *fx = chan->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 vol += fx->val[EMUX_FX_ATTEN];
790 }
791#endif
792
793 LIMITVALUE(vol, 0, 255);
794 if (vp->avol == vol)
795 return 0; /* value unchanged */
796
797 vp->avol = vol;
798 if (!SF_IS_DRUM_BANK(get_bank(port, chan))
799 && LO_BYTE(vp->reg.parm.volatkhld) < 0x7d) {
800 int atten;
801 if (vp->velocity < 70)
802 atten = 70;
803 else
804 atten = vp->velocity;
805 vp->acutoff = (atten * vp->reg.parm.cutoff + 0xa0) >> 7;
806 } else {
807 vp->acutoff = vp->reg.parm.cutoff;
808 }
809
810 return 1; /* value changed */
811}
812
813/*
814 * calculate pitch offset
815 *
816 * 0xE000 is no pitch offset at 44100Hz sample.
817 * Every 4096 is one octave.
818 */
819
820static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100821calc_pitch(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
Takashi Iwai03da3122005-11-17 14:24:47 +0100823 struct snd_midi_channel *chan = vp->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 int offset;
825
826 /* calculate offset */
827 if (vp->reg.fixkey >= 0) {
828 offset = (vp->reg.fixkey - vp->reg.root) * 4096 / 12;
829 } else {
830 offset = (vp->note - vp->reg.root) * 4096 / 12;
831 }
832 offset = (offset * vp->reg.scaleTuning) / 100;
833 offset += vp->reg.tune * 4096 / 1200;
834 if (chan->midi_pitchbend != 0) {
835 /* (128 * 8192: 1 semitone) ==> (4096: 12 semitones) */
836 offset += chan->midi_pitchbend * chan->gm_rpn_pitch_bend_range / 3072;
837 }
838
839 /* tuning via RPN:
840 * coarse = -8192 to 8192 (100 cent per 128)
841 * fine = -8192 to 8192 (max=100cent)
842 */
843 /* 4096 = 1200 cents in emu8000 parameter */
844 offset += chan->gm_rpn_coarse_tuning * 4096 / (12 * 128);
845 offset += chan->gm_rpn_fine_tuning / 24;
846
847#ifdef SNDRV_EMUX_USE_RAW_EFFECT
848 /* add initial pitch correction */
849 if (chan->private) {
Takashi Iwai03da3122005-11-17 14:24:47 +0100850 struct snd_emux_effect_table *fx = chan->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (fx->flag[EMUX_FX_INIT_PITCH])
852 offset += fx->val[EMUX_FX_INIT_PITCH];
853 }
854#endif
855
856 /* 0xe000: root pitch */
857 offset += 0xe000 + vp->reg.rate_offset;
858 offset += vp->emu->pitch_shift;
859 LIMITVALUE(offset, 0, 0xffff);
860 if (offset == vp->apitch)
861 return 0; /* unchanged */
862 vp->apitch = offset;
863 return 1; /* value changed */
864}
865
866/*
867 * Get the bank number assigned to the channel
868 */
869static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100870get_bank(struct snd_emux_port *port, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
872 int val;
873
874 switch (port->chset.midi_mode) {
875 case SNDRV_MIDI_MODE_XG:
876 val = chan->control[MIDI_CTL_MSB_BANK];
877 if (val == 127)
878 return 128; /* return drum bank */
879 return chan->control[MIDI_CTL_LSB_BANK];
880
881 case SNDRV_MIDI_MODE_GS:
882 if (chan->drum_channel)
883 return 128;
884 /* ignore LSB (bank map) */
885 return chan->control[MIDI_CTL_MSB_BANK];
886
887 default:
888 if (chan->drum_channel)
889 return 128;
890 return chan->control[MIDI_CTL_MSB_BANK];
891 }
892}
893
894
895/* Look for the zones matching with the given note and velocity.
896 * The resultant zones are stored on table.
897 */
898static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100899get_zone(struct snd_emux *emu, struct snd_emux_port *port,
900 int *notep, int vel, struct snd_midi_channel *chan,
901 struct snd_sf_zone **table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902{
903 int preset, bank, def_preset, def_bank;
904
905 bank = get_bank(port, chan);
906 preset = chan->midi_program;
907
908 if (SF_IS_DRUM_BANK(bank)) {
909 def_preset = port->ctrls[EMUX_MD_DEF_DRUM];
910 def_bank = bank;
911 } else {
912 def_preset = preset;
913 def_bank = port->ctrls[EMUX_MD_DEF_BANK];
914 }
915
916 return snd_soundfont_search_zone(emu->sflist, notep, vel, preset, bank,
917 def_preset, def_bank,
918 table, SNDRV_EMUX_MAX_MULTI_VOICES);
919}
920
921/*
922 */
923void
Takashi Iwai03da3122005-11-17 14:24:47 +0100924snd_emux_init_voices(struct snd_emux *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Takashi Iwai03da3122005-11-17 14:24:47 +0100926 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 int i;
928 unsigned long flags;
929
930 spin_lock_irqsave(&emu->voice_lock, flags);
931 for (i = 0; i < emu->max_voices; i++) {
932 vp = &emu->voices[i];
933 vp->ch = -1; /* not used */
934 vp->state = SNDRV_EMUX_ST_OFF;
935 vp->chan = NULL;
936 vp->port = NULL;
937 vp->time = 0;
938 vp->emu = emu;
939 vp->hw = emu->hw;
940 }
941 spin_unlock_irqrestore(&emu->voice_lock, flags);
942}
943
944/*
945 */
Takashi Iwai03da3122005-11-17 14:24:47 +0100946void snd_emux_lock_voice(struct snd_emux *emu, int voice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
948 unsigned long flags;
949
950 spin_lock_irqsave(&emu->voice_lock, flags);
951 if (emu->voices[voice].state == SNDRV_EMUX_ST_OFF)
952 emu->voices[voice].state = SNDRV_EMUX_ST_LOCKED;
953 else
954 snd_printk("invalid voice for lock %d (state = %x)\n",
955 voice, emu->voices[voice].state);
956 spin_unlock_irqrestore(&emu->voice_lock, flags);
957}
958
Takashi Iwai95ff17562006-04-28 15:13:40 +0200959EXPORT_SYMBOL(snd_emux_lock_voice);
960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961/*
962 */
Takashi Iwai03da3122005-11-17 14:24:47 +0100963void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
965 unsigned long flags;
966
967 spin_lock_irqsave(&emu->voice_lock, flags);
968 if (emu->voices[voice].state == SNDRV_EMUX_ST_LOCKED)
969 emu->voices[voice].state = SNDRV_EMUX_ST_OFF;
970 else
971 snd_printk("invalid voice for unlock %d (state = %x)\n",
972 voice, emu->voices[voice].state);
973 spin_unlock_irqrestore(&emu->voice_lock, flags);
974}
Takashi Iwai95ff17562006-04-28 15:13:40 +0200975
976EXPORT_SYMBOL(snd_emux_unlock_voice);