blob: 478369bb38c34118701f08966c0cf2b96f2beab4 [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 */
344 snd_emux_send_effect(port, chan, EMUX_FX_CUTOFF, -160,
345 EMUX_FX_FLAG_ADD);
346#endif
347 break;
348
349 case MIDI_CTL_PITCHBEND:
350 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PITCH);
351 break;
352
353 case MIDI_CTL_MSB_MODWHEEL:
354 case MIDI_CTL_CHAN_PRESSURE:
355 snd_emux_update_channel(port, chan,
356 SNDRV_EMUX_UPDATE_FMMOD |
357 SNDRV_EMUX_UPDATE_FM2FRQ2);
358 break;
359
360 }
361
362 if (port->chset.midi_mode == SNDRV_MIDI_MODE_XG) {
363 snd_emux_xg_control(port, chan, type);
364 }
365}
366
367
368/*
369 * terminate note - if free flag is true, free the terminated voice
370 */
371static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100372terminate_note1(struct snd_emux *emu, int note, struct snd_midi_channel *chan, int free)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 int i;
Takashi Iwai03da3122005-11-17 14:24:47 +0100375 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 unsigned long flags;
377
378 spin_lock_irqsave(&emu->voice_lock, flags);
379 for (i = 0; i < emu->max_voices; i++) {
380 vp = &emu->voices[i];
381 if (STATE_IS_PLAYING(vp->state) && vp->chan == chan &&
382 vp->key == note)
383 terminate_voice(emu, vp, free);
384 }
385 spin_unlock_irqrestore(&emu->voice_lock, flags);
386}
387
388
389/*
390 * terminate note - exported for midi emulation
391 */
392void
Takashi Iwai03da3122005-11-17 14:24:47 +0100393snd_emux_terminate_note(void *p, int note, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
Takashi Iwai03da3122005-11-17 14:24:47 +0100395 struct snd_emux *emu;
396 struct snd_emux_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 port = p;
399 snd_assert(port != NULL && chan != NULL, return);
400
401 emu = port->emu;
402 snd_assert(emu != NULL, return);
403 snd_assert(emu->ops.terminate != NULL, return);
404
405 terminate_note1(emu, note, chan, 1);
406}
407
408
409/*
410 * Terminate all the notes
411 */
412void
Takashi Iwai03da3122005-11-17 14:24:47 +0100413snd_emux_terminate_all(struct snd_emux *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
415 int i;
Takashi Iwai03da3122005-11-17 14:24:47 +0100416 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 unsigned long flags;
418
419 spin_lock_irqsave(&emu->voice_lock, flags);
420 for (i = 0; i < emu->max_voices; i++) {
421 vp = &emu->voices[i];
422 if (STATE_IS_PLAYING(vp->state))
423 terminate_voice(emu, vp, 0);
424 if (vp->state == SNDRV_EMUX_ST_OFF) {
425 if (emu->ops.free_voice)
426 emu->ops.free_voice(vp);
427 if (emu->ops.reset)
428 emu->ops.reset(emu, i);
429 }
430 vp->time = 0;
431 }
432 /* initialize allocation time */
433 emu->use_time = 0;
434 spin_unlock_irqrestore(&emu->voice_lock, flags);
435}
436
Takashi Iwai95ff17562006-04-28 15:13:40 +0200437EXPORT_SYMBOL(snd_emux_terminate_all);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
439/*
440 * Terminate all voices associated with the given port
441 */
442void
Takashi Iwai03da3122005-11-17 14:24:47 +0100443snd_emux_sounds_off_all(struct snd_emux_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
445 int i;
Takashi Iwai03da3122005-11-17 14:24:47 +0100446 struct snd_emux *emu;
447 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 unsigned long flags;
449
450 snd_assert(port != NULL, return);
451 emu = port->emu;
452 snd_assert(emu != NULL, return);
453 snd_assert(emu->ops.terminate != NULL, return);
454
455 spin_lock_irqsave(&emu->voice_lock, flags);
456 for (i = 0; i < emu->max_voices; i++) {
457 vp = &emu->voices[i];
458 if (STATE_IS_PLAYING(vp->state) &&
459 vp->port == port)
460 terminate_voice(emu, vp, 0);
461 if (vp->state == SNDRV_EMUX_ST_OFF) {
462 if (emu->ops.free_voice)
463 emu->ops.free_voice(vp);
464 if (emu->ops.reset)
465 emu->ops.reset(emu, i);
466 }
467 }
468 spin_unlock_irqrestore(&emu->voice_lock, flags);
469}
470
471
472/*
473 * Terminate all voices that have the same exclusive class. This
474 * is mainly for drums.
475 */
476static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100477exclusive_note_off(struct snd_emux *emu, struct snd_emux_port *port, int exclass)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
Takashi Iwai03da3122005-11-17 14:24:47 +0100479 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 int i;
481 unsigned long flags;
482
483 spin_lock_irqsave(&emu->voice_lock, flags);
484 for (i = 0; i < emu->max_voices; i++) {
485 vp = &emu->voices[i];
486 if (STATE_IS_PLAYING(vp->state) && vp->port == port &&
487 vp->reg.exclusiveClass == exclass) {
488 terminate_voice(emu, vp, 0);
489 }
490 }
491 spin_unlock_irqrestore(&emu->voice_lock, flags);
492}
493
494/*
495 * terminate a voice
496 * if free flag is true, call free_voice after termination
497 */
498static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100499terminate_voice(struct snd_emux *emu, struct snd_emux_voice *vp, int free)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 emu->ops.terminate(vp);
502 vp->time = emu->use_time++;
503 vp->chan = NULL;
504 vp->port = NULL;
505 vp->zone = NULL;
506 vp->block = NULL;
507 vp->state = SNDRV_EMUX_ST_OFF;
508 if (free && emu->ops.free_voice)
509 emu->ops.free_voice(vp);
510}
511
512
513/*
514 * Modulate the voice
515 */
516static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100517update_voice(struct snd_emux *emu, struct snd_emux_voice *vp, int update)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 if (!STATE_IS_PLAYING(vp->state))
520 return;
521
522 if (vp->chan == NULL || vp->port == NULL)
523 return;
524 if (update & SNDRV_EMUX_UPDATE_VOLUME)
525 calc_volume(vp);
526 if (update & SNDRV_EMUX_UPDATE_PITCH)
527 calc_pitch(vp);
528 if (update & SNDRV_EMUX_UPDATE_PAN) {
529 if (! calc_pan(vp) && (update == SNDRV_EMUX_UPDATE_PAN))
530 return;
531 }
532 emu->ops.update(vp, update);
533}
534
535
536#if 0 // not used
537/* table for volume target calculation */
538static unsigned short voltarget[16] = {
539 0xEAC0, 0xE0C8, 0xD740, 0xCE20, 0xC560, 0xBD08, 0xB500, 0xAD58,
540 0xA5F8, 0x9EF0, 0x9830, 0x91C0, 0x8B90, 0x85A8, 0x8000, 0x7A90
541};
542#endif
543
544#define LO_BYTE(v) ((v) & 0xff)
545#define HI_BYTE(v) (((v) >> 8) & 0xff)
546
547/*
548 * Sets up the voice structure by calculating some values that
549 * will be needed later.
550 */
551static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100552setup_voice(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
Takashi Iwai03da3122005-11-17 14:24:47 +0100554 struct soundfont_voice_parm *parm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 int pitch;
556
557 /* copy the original register values */
558 vp->reg = vp->zone->v;
559
560#ifdef SNDRV_EMUX_USE_RAW_EFFECT
561 snd_emux_setup_effect(vp);
562#endif
563
564 /* reset status */
565 vp->apan = -1;
566 vp->avol = -1;
567 vp->apitch = -1;
568
569 calc_volume(vp);
570 calc_pitch(vp);
571 calc_pan(vp);
572
573 parm = &vp->reg.parm;
574
575 /* compute filter target and correct modulation parameters */
576 if (LO_BYTE(parm->modatkhld) >= 0x80 && parm->moddelay >= 0x8000) {
577 parm->moddelay = 0xbfff;
578 pitch = (HI_BYTE(parm->pefe) << 4) + vp->apitch;
579 if (pitch > 0xffff)
580 pitch = 0xffff;
581 /* calculate filter target */
582 vp->ftarget = parm->cutoff + LO_BYTE(parm->pefe);
583 LIMITVALUE(vp->ftarget, 0, 255);
584 vp->ftarget <<= 8;
585 } else {
586 vp->ftarget = parm->cutoff;
587 vp->ftarget <<= 8;
588 pitch = vp->apitch;
589 }
590
591 /* compute pitch target */
592 if (pitch != 0xffff) {
593 vp->ptarget = 1 << (pitch >> 12);
594 if (pitch & 0x800) vp->ptarget += (vp->ptarget*0x102e)/0x2710;
595 if (pitch & 0x400) vp->ptarget += (vp->ptarget*0x764)/0x2710;
596 if (pitch & 0x200) vp->ptarget += (vp->ptarget*0x389)/0x2710;
597 vp->ptarget += (vp->ptarget >> 1);
598 if (vp->ptarget > 0xffff) vp->ptarget = 0xffff;
599 } else
600 vp->ptarget = 0xffff;
601
602 if (LO_BYTE(parm->modatkhld) >= 0x80) {
603 parm->modatkhld &= ~0xff;
604 parm->modatkhld |= 0x7f;
605 }
606
607 /* compute volume target and correct volume parameters */
608 vp->vtarget = 0;
609#if 0 /* FIXME: this leads to some clicks.. */
610 if (LO_BYTE(parm->volatkhld) >= 0x80 && parm->voldelay >= 0x8000) {
611 parm->voldelay = 0xbfff;
612 vp->vtarget = voltarget[vp->avol % 0x10] >> (vp->avol >> 4);
613 }
614#endif
615
616 if (LO_BYTE(parm->volatkhld) >= 0x80) {
617 parm->volatkhld &= ~0xff;
618 parm->volatkhld |= 0x7f;
619 }
620}
621
622/*
623 * calculate pitch parameter
624 */
625static unsigned char pan_volumes[256] = {
6260x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x14,0x17,0x1a,0x1d,0x20,0x22,0x25,0x28,0x2a,
6270x2d,0x30,0x32,0x35,0x37,0x3a,0x3c,0x3f,0x41,0x44,0x46,0x49,0x4b,0x4d,0x50,0x52,
6280x54,0x57,0x59,0x5b,0x5d,0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6f,0x71,0x73,0x75,
6290x77,0x79,0x7b,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x89,0x8b,0x8d,0x8f,0x90,0x92,
6300x94,0x96,0x97,0x99,0x9a,0x9c,0x9e,0x9f,0xa1,0xa2,0xa4,0xa5,0xa7,0xa8,0xaa,0xab,
6310xad,0xae,0xaf,0xb1,0xb2,0xb3,0xb5,0xb6,0xb7,0xb9,0xba,0xbb,0xbc,0xbe,0xbf,0xc0,
6320xc1,0xc2,0xc3,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,
6330xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdc,0xdd,0xde,0xdf,
6340xdf,0xe0,0xe1,0xe2,0xe2,0xe3,0xe4,0xe4,0xe5,0xe6,0xe6,0xe7,0xe8,0xe8,0xe9,0xe9,
6350xea,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1,0xf1,0xf1,
6360xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf7,
6370xf7,0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,
6380xfb,0xfb,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,
6390xfd,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
6400xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
6410xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
642};
643
644static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100645calc_pan(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Takashi Iwai03da3122005-11-17 14:24:47 +0100647 struct snd_midi_channel *chan = vp->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 int pan;
649
650 /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
651 if (vp->reg.fixpan > 0) /* 0-127 */
652 pan = 255 - (int)vp->reg.fixpan * 2;
653 else {
654 pan = chan->control[MIDI_CTL_MSB_PAN] - 64;
655 if (vp->reg.pan >= 0) /* 0-127 */
656 pan += vp->reg.pan - 64;
657 pan = 127 - (int)pan * 2;
658 }
659 LIMITVALUE(pan, 0, 255);
660
661 if (vp->emu->linear_panning) {
662 /* assuming linear volume */
663 if (pan != vp->apan) {
664 vp->apan = pan;
665 if (pan == 0)
666 vp->aaux = 0xff;
667 else
668 vp->aaux = (-pan) & 0xff;
669 return 1;
670 } else
671 return 0;
672 } else {
673 /* using volume table */
674 if (vp->apan != (int)pan_volumes[pan]) {
675 vp->apan = pan_volumes[pan];
676 vp->aaux = pan_volumes[255 - pan];
677 return 1;
678 }
679 return 0;
680 }
681}
682
683
684/*
685 * calculate volume attenuation
686 *
687 * Voice volume is controlled by volume attenuation parameter.
688 * So volume becomes maximum when avol is 0 (no attenuation), and
689 * minimum when 255 (-96dB or silence).
690 */
691
692/* tables for volume->attenuation calculation */
693static unsigned char voltab1[128] = {
694 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
695 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
696 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
697 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
698 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
699 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
700 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
701 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
702 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
703 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
704 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
705 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
706 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
707};
708
709static unsigned char voltab2[128] = {
710 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
711 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
712 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
713 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
714 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
715 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
716 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
717 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
718 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
719 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
720 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
721 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
722 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
723};
724
725static unsigned char expressiontab[128] = {
726 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
727 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
728 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
729 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
730 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
731 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
732 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
733 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
734 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
735 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
736 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
737 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
738 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
739};
740
741/*
742 * Magic to calculate the volume (actually attenuation) from all the
743 * voice and channels parameters.
744 */
745static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100746calc_volume(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747{
748 int vol;
749 int main_vol, expression_vol, master_vol;
Takashi Iwai03da3122005-11-17 14:24:47 +0100750 struct snd_midi_channel *chan = vp->chan;
751 struct snd_emux_port *port = vp->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 expression_vol = chan->control[MIDI_CTL_MSB_EXPRESSION];
754 LIMITMAX(vp->velocity, 127);
755 LIMITVALUE(expression_vol, 0, 127);
756 if (port->port_mode == SNDRV_EMUX_PORT_MODE_OSS_SYNTH) {
757 /* 0 - 127 */
758 main_vol = chan->control[MIDI_CTL_MSB_MAIN_VOLUME];
759 vol = (vp->velocity * main_vol * expression_vol) / (127*127);
760 vol = vol * vp->reg.amplitude / 127;
761
762 LIMITVALUE(vol, 0, 127);
763
764 /* calc to attenuation */
765 vol = snd_sf_vol_table[vol];
766
767 } else {
768 main_vol = chan->control[MIDI_CTL_MSB_MAIN_VOLUME] * vp->reg.amplitude / 127;
769 LIMITVALUE(main_vol, 0, 127);
770
771 vol = voltab1[main_vol] + voltab2[vp->velocity];
772 vol = (vol * 8) / 3;
773 vol += vp->reg.attenuation;
774 vol += ((0x100 - vol) * expressiontab[expression_vol])/128;
775 }
776
777 master_vol = port->chset.gs_master_volume;
778 LIMITVALUE(master_vol, 0, 127);
779 vol += snd_sf_vol_table[master_vol];
780 vol += port->volume_atten;
781
782#ifdef SNDRV_EMUX_USE_RAW_EFFECT
783 if (chan->private) {
Takashi Iwai03da3122005-11-17 14:24:47 +0100784 struct snd_emux_effect_table *fx = chan->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 vol += fx->val[EMUX_FX_ATTEN];
786 }
787#endif
788
789 LIMITVALUE(vol, 0, 255);
790 if (vp->avol == vol)
791 return 0; /* value unchanged */
792
793 vp->avol = vol;
794 if (!SF_IS_DRUM_BANK(get_bank(port, chan))
795 && LO_BYTE(vp->reg.parm.volatkhld) < 0x7d) {
796 int atten;
797 if (vp->velocity < 70)
798 atten = 70;
799 else
800 atten = vp->velocity;
801 vp->acutoff = (atten * vp->reg.parm.cutoff + 0xa0) >> 7;
802 } else {
803 vp->acutoff = vp->reg.parm.cutoff;
804 }
805
806 return 1; /* value changed */
807}
808
809/*
810 * calculate pitch offset
811 *
812 * 0xE000 is no pitch offset at 44100Hz sample.
813 * Every 4096 is one octave.
814 */
815
816static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100817calc_pitch(struct snd_emux_voice *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
Takashi Iwai03da3122005-11-17 14:24:47 +0100819 struct snd_midi_channel *chan = vp->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 int offset;
821
822 /* calculate offset */
823 if (vp->reg.fixkey >= 0) {
824 offset = (vp->reg.fixkey - vp->reg.root) * 4096 / 12;
825 } else {
826 offset = (vp->note - vp->reg.root) * 4096 / 12;
827 }
828 offset = (offset * vp->reg.scaleTuning) / 100;
829 offset += vp->reg.tune * 4096 / 1200;
830 if (chan->midi_pitchbend != 0) {
831 /* (128 * 8192: 1 semitone) ==> (4096: 12 semitones) */
832 offset += chan->midi_pitchbend * chan->gm_rpn_pitch_bend_range / 3072;
833 }
834
835 /* tuning via RPN:
836 * coarse = -8192 to 8192 (100 cent per 128)
837 * fine = -8192 to 8192 (max=100cent)
838 */
839 /* 4096 = 1200 cents in emu8000 parameter */
840 offset += chan->gm_rpn_coarse_tuning * 4096 / (12 * 128);
841 offset += chan->gm_rpn_fine_tuning / 24;
842
843#ifdef SNDRV_EMUX_USE_RAW_EFFECT
844 /* add initial pitch correction */
845 if (chan->private) {
Takashi Iwai03da3122005-11-17 14:24:47 +0100846 struct snd_emux_effect_table *fx = chan->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (fx->flag[EMUX_FX_INIT_PITCH])
848 offset += fx->val[EMUX_FX_INIT_PITCH];
849 }
850#endif
851
852 /* 0xe000: root pitch */
853 offset += 0xe000 + vp->reg.rate_offset;
854 offset += vp->emu->pitch_shift;
855 LIMITVALUE(offset, 0, 0xffff);
856 if (offset == vp->apitch)
857 return 0; /* unchanged */
858 vp->apitch = offset;
859 return 1; /* value changed */
860}
861
862/*
863 * Get the bank number assigned to the channel
864 */
865static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100866get_bank(struct snd_emux_port *port, struct snd_midi_channel *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
868 int val;
869
870 switch (port->chset.midi_mode) {
871 case SNDRV_MIDI_MODE_XG:
872 val = chan->control[MIDI_CTL_MSB_BANK];
873 if (val == 127)
874 return 128; /* return drum bank */
875 return chan->control[MIDI_CTL_LSB_BANK];
876
877 case SNDRV_MIDI_MODE_GS:
878 if (chan->drum_channel)
879 return 128;
880 /* ignore LSB (bank map) */
881 return chan->control[MIDI_CTL_MSB_BANK];
882
883 default:
884 if (chan->drum_channel)
885 return 128;
886 return chan->control[MIDI_CTL_MSB_BANK];
887 }
888}
889
890
891/* Look for the zones matching with the given note and velocity.
892 * The resultant zones are stored on table.
893 */
894static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100895get_zone(struct snd_emux *emu, struct snd_emux_port *port,
896 int *notep, int vel, struct snd_midi_channel *chan,
897 struct snd_sf_zone **table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898{
899 int preset, bank, def_preset, def_bank;
900
901 bank = get_bank(port, chan);
902 preset = chan->midi_program;
903
904 if (SF_IS_DRUM_BANK(bank)) {
905 def_preset = port->ctrls[EMUX_MD_DEF_DRUM];
906 def_bank = bank;
907 } else {
908 def_preset = preset;
909 def_bank = port->ctrls[EMUX_MD_DEF_BANK];
910 }
911
912 return snd_soundfont_search_zone(emu->sflist, notep, vel, preset, bank,
913 def_preset, def_bank,
914 table, SNDRV_EMUX_MAX_MULTI_VOICES);
915}
916
917/*
918 */
919void
Takashi Iwai03da3122005-11-17 14:24:47 +0100920snd_emux_init_voices(struct snd_emux *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
Takashi Iwai03da3122005-11-17 14:24:47 +0100922 struct snd_emux_voice *vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int i;
924 unsigned long flags;
925
926 spin_lock_irqsave(&emu->voice_lock, flags);
927 for (i = 0; i < emu->max_voices; i++) {
928 vp = &emu->voices[i];
929 vp->ch = -1; /* not used */
930 vp->state = SNDRV_EMUX_ST_OFF;
931 vp->chan = NULL;
932 vp->port = NULL;
933 vp->time = 0;
934 vp->emu = emu;
935 vp->hw = emu->hw;
936 }
937 spin_unlock_irqrestore(&emu->voice_lock, flags);
938}
939
940/*
941 */
Takashi Iwai03da3122005-11-17 14:24:47 +0100942void snd_emux_lock_voice(struct snd_emux *emu, int voice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
944 unsigned long flags;
945
946 spin_lock_irqsave(&emu->voice_lock, flags);
947 if (emu->voices[voice].state == SNDRV_EMUX_ST_OFF)
948 emu->voices[voice].state = SNDRV_EMUX_ST_LOCKED;
949 else
950 snd_printk("invalid voice for lock %d (state = %x)\n",
951 voice, emu->voices[voice].state);
952 spin_unlock_irqrestore(&emu->voice_lock, flags);
953}
954
Takashi Iwai95ff17562006-04-28 15:13:40 +0200955EXPORT_SYMBOL(snd_emux_lock_voice);
956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957/*
958 */
Takashi Iwai03da3122005-11-17 14:24:47 +0100959void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960{
961 unsigned long flags;
962
963 spin_lock_irqsave(&emu->voice_lock, flags);
964 if (emu->voices[voice].state == SNDRV_EMUX_ST_LOCKED)
965 emu->voices[voice].state = SNDRV_EMUX_ST_OFF;
966 else
967 snd_printk("invalid voice for unlock %d (state = %x)\n",
968 voice, emu->voices[voice].state);
969 spin_unlock_irqrestore(&emu->voice_lock, flags);
970}
Takashi Iwai95ff17562006-04-28 15:13:40 +0200971
972EXPORT_SYMBOL(snd_emux_unlock_voice);