xref: /openbmc/linux/sound/drivers/opl3/opl3_midi.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *  Copyright (c) by Uros Bizjak <uros@kss-loka.si>
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  *  Midi synth routines for OPL2/OPL3/OPL4 FM
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
7*1da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
8*1da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
9*1da177e4SLinus Torvalds  *   (at your option) any later version.
10*1da177e4SLinus Torvalds  *
11*1da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
12*1da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13*1da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*1da177e4SLinus Torvalds  *   GNU General Public License for more details.
15*1da177e4SLinus Torvalds  *
16*1da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
17*1da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
18*1da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19*1da177e4SLinus Torvalds  *
20*1da177e4SLinus Torvalds  */
21*1da177e4SLinus Torvalds 
22*1da177e4SLinus Torvalds #undef DEBUG_ALLOC
23*1da177e4SLinus Torvalds #undef DEBUG_MIDI
24*1da177e4SLinus Torvalds 
25*1da177e4SLinus Torvalds #include "opl3_voice.h"
26*1da177e4SLinus Torvalds #include <sound/asoundef.h>
27*1da177e4SLinus Torvalds 
28*1da177e4SLinus Torvalds extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
29*1da177e4SLinus Torvalds 
30*1da177e4SLinus Torvalds extern int use_internal_drums;
31*1da177e4SLinus Torvalds 
32*1da177e4SLinus Torvalds /*
33*1da177e4SLinus Torvalds  * The next table looks magical, but it certainly is not. Its values have
34*1da177e4SLinus Torvalds  * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception
35*1da177e4SLinus Torvalds  * for i=0. This log-table converts a linear volume-scaling (0..127) to a
36*1da177e4SLinus Torvalds  * logarithmic scaling as present in the FM-synthesizer chips. so :    Volume
37*1da177e4SLinus Torvalds  * 64 =  0 db = relative volume  0 and:    Volume 32 = -6 db = relative
38*1da177e4SLinus Torvalds  * volume -8 it was implemented as a table because it is only 128 bytes and
39*1da177e4SLinus Torvalds  * it saves a lot of log() calculations. (Rob Hooft <hooft@chem.ruu.nl>)
40*1da177e4SLinus Torvalds  */
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds static char opl3_volume_table[128] =
43*1da177e4SLinus Torvalds {
44*1da177e4SLinus Torvalds 	-63, -48, -40, -35, -32, -29, -27, -26,
45*1da177e4SLinus Torvalds 	-24, -23, -21, -20, -19, -18, -18, -17,
46*1da177e4SLinus Torvalds 	-16, -15, -15, -14, -13, -13, -12, -12,
47*1da177e4SLinus Torvalds 	-11, -11, -10, -10, -10, -9, -9, -8,
48*1da177e4SLinus Torvalds 	-8, -8, -7, -7, -7, -6, -6, -6,
49*1da177e4SLinus Torvalds 	-5, -5, -5, -5, -4, -4, -4, -4,
50*1da177e4SLinus Torvalds 	-3, -3, -3, -3, -2, -2, -2, -2,
51*1da177e4SLinus Torvalds 	-2, -1, -1, -1, -1, 0, 0, 0,
52*1da177e4SLinus Torvalds 	0, 0, 0, 1, 1, 1, 1, 1,
53*1da177e4SLinus Torvalds 	1, 2, 2, 2, 2, 2, 2, 2,
54*1da177e4SLinus Torvalds 	3, 3, 3, 3, 3, 3, 3, 4,
55*1da177e4SLinus Torvalds 	4, 4, 4, 4, 4, 4, 4, 5,
56*1da177e4SLinus Torvalds 	5, 5, 5, 5, 5, 5, 5, 5,
57*1da177e4SLinus Torvalds 	6, 6, 6, 6, 6, 6, 6, 6,
58*1da177e4SLinus Torvalds 	6, 7, 7, 7, 7, 7, 7, 7,
59*1da177e4SLinus Torvalds 	7, 7, 7, 8, 8, 8, 8, 8
60*1da177e4SLinus Torvalds };
61*1da177e4SLinus Torvalds 
62*1da177e4SLinus Torvalds void snd_opl3_calc_volume(unsigned char *volbyte, int vel,
63*1da177e4SLinus Torvalds 			  snd_midi_channel_t *chan)
64*1da177e4SLinus Torvalds {
65*1da177e4SLinus Torvalds 	int oldvol, newvol, n;
66*1da177e4SLinus Torvalds 	int volume;
67*1da177e4SLinus Torvalds 
68*1da177e4SLinus Torvalds 	volume = (vel * chan->gm_volume * chan->gm_expression) / (127*127);
69*1da177e4SLinus Torvalds 	if (volume > 127)
70*1da177e4SLinus Torvalds 		volume = 127;
71*1da177e4SLinus Torvalds 
72*1da177e4SLinus Torvalds 	oldvol = OPL3_TOTAL_LEVEL_MASK - (*volbyte & OPL3_TOTAL_LEVEL_MASK);
73*1da177e4SLinus Torvalds 
74*1da177e4SLinus Torvalds 	newvol = opl3_volume_table[volume] + oldvol;
75*1da177e4SLinus Torvalds 	if (newvol > OPL3_TOTAL_LEVEL_MASK)
76*1da177e4SLinus Torvalds 		newvol = OPL3_TOTAL_LEVEL_MASK;
77*1da177e4SLinus Torvalds 	else if (newvol < 0)
78*1da177e4SLinus Torvalds 		newvol = 0;
79*1da177e4SLinus Torvalds 
80*1da177e4SLinus Torvalds 	n = OPL3_TOTAL_LEVEL_MASK - (newvol & OPL3_TOTAL_LEVEL_MASK);
81*1da177e4SLinus Torvalds 
82*1da177e4SLinus Torvalds 	*volbyte = (*volbyte & OPL3_KSL_MASK) | (n & OPL3_TOTAL_LEVEL_MASK);
83*1da177e4SLinus Torvalds }
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds /*
86*1da177e4SLinus Torvalds  * Converts the note frequency to block and fnum values for the FM chip
87*1da177e4SLinus Torvalds  */
88*1da177e4SLinus Torvalds static short opl3_note_table[16] =
89*1da177e4SLinus Torvalds {
90*1da177e4SLinus Torvalds 	305, 323,	/* for pitch bending, -2 semitones */
91*1da177e4SLinus Torvalds 	343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647,
92*1da177e4SLinus Torvalds 	686, 726	/* for pitch bending, +2 semitones */
93*1da177e4SLinus Torvalds };
94*1da177e4SLinus Torvalds 
95*1da177e4SLinus Torvalds static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum,
96*1da177e4SLinus Torvalds 				int note, snd_midi_channel_t *chan)
97*1da177e4SLinus Torvalds {
98*1da177e4SLinus Torvalds 	int block = ((note / 12) & 0x07) - 1;
99*1da177e4SLinus Torvalds 	int idx = (note % 12) + 2;
100*1da177e4SLinus Torvalds 	int freq;
101*1da177e4SLinus Torvalds 
102*1da177e4SLinus Torvalds 	if (chan->midi_pitchbend) {
103*1da177e4SLinus Torvalds 		int pitchbend = chan->midi_pitchbend;
104*1da177e4SLinus Torvalds 		int segment;
105*1da177e4SLinus Torvalds 
106*1da177e4SLinus Torvalds 		if (pitchbend > 0x1FFF)
107*1da177e4SLinus Torvalds 			pitchbend = 0x1FFF;
108*1da177e4SLinus Torvalds 
109*1da177e4SLinus Torvalds 		segment = pitchbend / 0x1000;
110*1da177e4SLinus Torvalds 		freq = opl3_note_table[idx+segment];
111*1da177e4SLinus Torvalds 		freq += ((opl3_note_table[idx+segment+1] - freq) *
112*1da177e4SLinus Torvalds 			 (pitchbend % 0x1000)) / 0x1000;
113*1da177e4SLinus Torvalds 	} else {
114*1da177e4SLinus Torvalds 		freq = opl3_note_table[idx];
115*1da177e4SLinus Torvalds 	}
116*1da177e4SLinus Torvalds 
117*1da177e4SLinus Torvalds 	*fnum = (unsigned char) freq;
118*1da177e4SLinus Torvalds 	*blocknum = ((freq >> 8) & OPL3_FNUM_HIGH_MASK) |
119*1da177e4SLinus Torvalds 		((block << 2) & OPL3_BLOCKNUM_MASK);
120*1da177e4SLinus Torvalds }
121*1da177e4SLinus Torvalds 
122*1da177e4SLinus Torvalds 
123*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC
124*1da177e4SLinus Torvalds static void debug_alloc(opl3_t *opl3, char *s, int voice) {
125*1da177e4SLinus Torvalds 	int i;
126*1da177e4SLinus Torvalds 	char *str = "x.24";
127*1da177e4SLinus Torvalds 
128*1da177e4SLinus Torvalds 	printk("time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
129*1da177e4SLinus Torvalds 	for (i = 0; i < opl3->max_voices; i++)
130*1da177e4SLinus Torvalds 		printk("%c", *(str + opl3->voices[i].state + 1));
131*1da177e4SLinus Torvalds 	printk("\n");
132*1da177e4SLinus Torvalds }
133*1da177e4SLinus Torvalds #endif
134*1da177e4SLinus Torvalds 
135*1da177e4SLinus Torvalds /*
136*1da177e4SLinus Torvalds  * Get a FM voice (channel) to play a note on.
137*1da177e4SLinus Torvalds  */
138*1da177e4SLinus Torvalds static int opl3_get_voice(opl3_t *opl3, int instr_4op,
139*1da177e4SLinus Torvalds 			  snd_midi_channel_t *chan) {
140*1da177e4SLinus Torvalds 	int chan_4op_1;		/* first voice for 4op instrument */
141*1da177e4SLinus Torvalds 	int chan_4op_2;		/* second voice for 4op instrument */
142*1da177e4SLinus Torvalds 
143*1da177e4SLinus Torvalds 	snd_opl3_voice_t *vp, *vp2;
144*1da177e4SLinus Torvalds 	unsigned int voice_time;
145*1da177e4SLinus Torvalds 	int i;
146*1da177e4SLinus Torvalds 
147*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC
148*1da177e4SLinus Torvalds 	char *alloc_type[3] = { "FREE     ", "CHEAP    ", "EXPENSIVE" };
149*1da177e4SLinus Torvalds #endif
150*1da177e4SLinus Torvalds 
151*1da177e4SLinus Torvalds 	/* This is our "allocation cost" table */
152*1da177e4SLinus Torvalds 	enum {
153*1da177e4SLinus Torvalds 		FREE = 0, CHEAP, EXPENSIVE, END
154*1da177e4SLinus Torvalds 	};
155*1da177e4SLinus Torvalds 
156*1da177e4SLinus Torvalds 	/* Keeps track of what we are finding */
157*1da177e4SLinus Torvalds 	struct best {
158*1da177e4SLinus Torvalds 		unsigned int time;
159*1da177e4SLinus Torvalds 		int voice;
160*1da177e4SLinus Torvalds 	} best[END];
161*1da177e4SLinus Torvalds 	struct best *bp;
162*1da177e4SLinus Torvalds 
163*1da177e4SLinus Torvalds 	for (i = 0; i < END; i++) {
164*1da177e4SLinus Torvalds 		best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */;
165*1da177e4SLinus Torvalds 		best[i].voice = -1;
166*1da177e4SLinus Torvalds 	}
167*1da177e4SLinus Torvalds 
168*1da177e4SLinus Torvalds 	/* Look through all the channels for the most suitable. */
169*1da177e4SLinus Torvalds 	for (i = 0; i < opl3->max_voices; i++) {
170*1da177e4SLinus Torvalds 		vp = &opl3->voices[i];
171*1da177e4SLinus Torvalds 
172*1da177e4SLinus Torvalds 		if (vp->state == SNDRV_OPL3_ST_NOT_AVAIL)
173*1da177e4SLinus Torvalds 		  /* skip unavailable channels, allocated by
174*1da177e4SLinus Torvalds 		     drum voices or by bounded 4op voices) */
175*1da177e4SLinus Torvalds 			continue;
176*1da177e4SLinus Torvalds 
177*1da177e4SLinus Torvalds 		voice_time = vp->time;
178*1da177e4SLinus Torvalds 		bp = best;
179*1da177e4SLinus Torvalds 
180*1da177e4SLinus Torvalds 		chan_4op_1 = ((i < 3) || (i > 8 && i < 12));
181*1da177e4SLinus Torvalds 		chan_4op_2 = ((i > 2 && i < 6) || (i > 11 && i < 15));
182*1da177e4SLinus Torvalds 		if (instr_4op) {
183*1da177e4SLinus Torvalds 			/* allocate 4op voice */
184*1da177e4SLinus Torvalds 			/* skip channels unavailable to 4op instrument */
185*1da177e4SLinus Torvalds 			if (!chan_4op_1)
186*1da177e4SLinus Torvalds 				continue;
187*1da177e4SLinus Torvalds 
188*1da177e4SLinus Torvalds 			if (vp->state)
189*1da177e4SLinus Torvalds 				/* kill one voice, CHEAP */
190*1da177e4SLinus Torvalds 				bp++;
191*1da177e4SLinus Torvalds 			/* get state of bounded 2op channel
192*1da177e4SLinus Torvalds 			   to be allocated for 4op instrument */
193*1da177e4SLinus Torvalds 			vp2 = &opl3->voices[i + 3];
194*1da177e4SLinus Torvalds 			if (vp2->state == SNDRV_OPL3_ST_ON_2OP) {
195*1da177e4SLinus Torvalds 				/* kill two voices, EXPENSIVE */
196*1da177e4SLinus Torvalds 				bp++;
197*1da177e4SLinus Torvalds 				voice_time = (voice_time > vp->time) ?
198*1da177e4SLinus Torvalds 					voice_time : vp->time;
199*1da177e4SLinus Torvalds 			}
200*1da177e4SLinus Torvalds 		} else {
201*1da177e4SLinus Torvalds 			/* allocate 2op voice */
202*1da177e4SLinus Torvalds 			if ((chan_4op_1) || (chan_4op_2))
203*1da177e4SLinus Torvalds 				/* use bounded channels for 2op, CHEAP */
204*1da177e4SLinus Torvalds 				bp++;
205*1da177e4SLinus Torvalds 			else if (vp->state)
206*1da177e4SLinus Torvalds 				/* kill one voice on 2op channel, CHEAP */
207*1da177e4SLinus Torvalds 				bp++;
208*1da177e4SLinus Torvalds 			/* raise kill cost to EXPENSIVE for all channels */
209*1da177e4SLinus Torvalds 			if (vp->state)
210*1da177e4SLinus Torvalds 				bp++;
211*1da177e4SLinus Torvalds 		}
212*1da177e4SLinus Torvalds 		if (voice_time < bp->time) {
213*1da177e4SLinus Torvalds 			bp->time = voice_time;
214*1da177e4SLinus Torvalds 			bp->voice = i;
215*1da177e4SLinus Torvalds 		}
216*1da177e4SLinus Torvalds 	}
217*1da177e4SLinus Torvalds 
218*1da177e4SLinus Torvalds 	for (i = 0; i < END; i++) {
219*1da177e4SLinus Torvalds 		if (best[i].voice >= 0) {
220*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC
221*1da177e4SLinus Torvalds 			printk("%s %iop allocation on voice %i\n",
222*1da177e4SLinus Torvalds 			       alloc_type[i], instr_4op ? 4 : 2,
223*1da177e4SLinus Torvalds 			       best[i].voice);
224*1da177e4SLinus Torvalds #endif
225*1da177e4SLinus Torvalds 			return best[i].voice;
226*1da177e4SLinus Torvalds 		}
227*1da177e4SLinus Torvalds 	}
228*1da177e4SLinus Torvalds 	/* not found */
229*1da177e4SLinus Torvalds 	return -1;
230*1da177e4SLinus Torvalds }
231*1da177e4SLinus Torvalds 
232*1da177e4SLinus Torvalds /* ------------------------------ */
233*1da177e4SLinus Torvalds 
234*1da177e4SLinus Torvalds /*
235*1da177e4SLinus Torvalds  * System timer interrupt function
236*1da177e4SLinus Torvalds  */
237*1da177e4SLinus Torvalds void snd_opl3_timer_func(unsigned long data)
238*1da177e4SLinus Torvalds {
239*1da177e4SLinus Torvalds 
240*1da177e4SLinus Torvalds 	opl3_t *opl3 = (opl3_t *)data;
241*1da177e4SLinus Torvalds 	int again = 0;
242*1da177e4SLinus Torvalds 	int i;
243*1da177e4SLinus Torvalds 
244*1da177e4SLinus Torvalds 	spin_lock(&opl3->sys_timer_lock);
245*1da177e4SLinus Torvalds 	for (i = 0; i < opl3->max_voices; i++) {
246*1da177e4SLinus Torvalds 		snd_opl3_voice_t *vp = &opl3->voices[i];
247*1da177e4SLinus Torvalds 		if (vp->state > 0 && vp->note_off_check) {
248*1da177e4SLinus Torvalds 			if (vp->note_off == jiffies)
249*1da177e4SLinus Torvalds 				snd_opl3_note_off(opl3, vp->note, 0, vp->chan);
250*1da177e4SLinus Torvalds 			else
251*1da177e4SLinus Torvalds 				again++;
252*1da177e4SLinus Torvalds 		}
253*1da177e4SLinus Torvalds 	}
254*1da177e4SLinus Torvalds 	if (again) {
255*1da177e4SLinus Torvalds 		opl3->tlist.expires = jiffies + 1;	/* invoke again */
256*1da177e4SLinus Torvalds 		add_timer(&opl3->tlist);
257*1da177e4SLinus Torvalds 	} else {
258*1da177e4SLinus Torvalds 		opl3->sys_timer_status = 0;
259*1da177e4SLinus Torvalds 	}
260*1da177e4SLinus Torvalds 	spin_unlock(&opl3->sys_timer_lock);
261*1da177e4SLinus Torvalds }
262*1da177e4SLinus Torvalds 
263*1da177e4SLinus Torvalds /*
264*1da177e4SLinus Torvalds  * Start system timer
265*1da177e4SLinus Torvalds  */
266*1da177e4SLinus Torvalds static void snd_opl3_start_timer(opl3_t *opl3)
267*1da177e4SLinus Torvalds {
268*1da177e4SLinus Torvalds 	unsigned long flags;
269*1da177e4SLinus Torvalds 	spin_lock_irqsave(&opl3->sys_timer_lock, flags);
270*1da177e4SLinus Torvalds 	if (! opl3->sys_timer_status) {
271*1da177e4SLinus Torvalds 		opl3->tlist.expires = jiffies + 1;
272*1da177e4SLinus Torvalds 		add_timer(&opl3->tlist);
273*1da177e4SLinus Torvalds 		opl3->sys_timer_status = 1;
274*1da177e4SLinus Torvalds 	}
275*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
276*1da177e4SLinus Torvalds }
277*1da177e4SLinus Torvalds 
278*1da177e4SLinus Torvalds /* ------------------------------ */
279*1da177e4SLinus Torvalds 
280*1da177e4SLinus Torvalds 
281*1da177e4SLinus Torvalds static int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
282*1da177e4SLinus Torvalds 	0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, 3, 4 ,5, 12, 13, 14
283*1da177e4SLinus Torvalds };
284*1da177e4SLinus Torvalds 
285*1da177e4SLinus Torvalds /*
286*1da177e4SLinus Torvalds  * Start a note.
287*1da177e4SLinus Torvalds  */
288*1da177e4SLinus Torvalds void snd_opl3_note_on(void *p, int note, int vel, snd_midi_channel_t *chan)
289*1da177e4SLinus Torvalds {
290*1da177e4SLinus Torvalds 	opl3_t *opl3;
291*1da177e4SLinus Torvalds 	snd_seq_instr_t wanted;
292*1da177e4SLinus Torvalds 	snd_seq_kinstr_t *kinstr;
293*1da177e4SLinus Torvalds 	int instr_4op;
294*1da177e4SLinus Torvalds 
295*1da177e4SLinus Torvalds 	int voice;
296*1da177e4SLinus Torvalds 	snd_opl3_voice_t *vp, *vp2;
297*1da177e4SLinus Torvalds 	unsigned short connect_mask;
298*1da177e4SLinus Torvalds 	unsigned char connection;
299*1da177e4SLinus Torvalds 	unsigned char vol_op[4];
300*1da177e4SLinus Torvalds 
301*1da177e4SLinus Torvalds 	int extra_prg = 0;
302*1da177e4SLinus Torvalds 
303*1da177e4SLinus Torvalds 	unsigned short reg_side;
304*1da177e4SLinus Torvalds 	unsigned char op_offset;
305*1da177e4SLinus Torvalds 	unsigned char voice_offset;
306*1da177e4SLinus Torvalds 	unsigned short opl3_reg;
307*1da177e4SLinus Torvalds 	unsigned char reg_val;
308*1da177e4SLinus Torvalds 
309*1da177e4SLinus Torvalds 	int key = note;
310*1da177e4SLinus Torvalds 	unsigned char fnum, blocknum;
311*1da177e4SLinus Torvalds 	int i;
312*1da177e4SLinus Torvalds 
313*1da177e4SLinus Torvalds 	fm_instrument_t *fm;
314*1da177e4SLinus Torvalds 	unsigned long flags;
315*1da177e4SLinus Torvalds 
316*1da177e4SLinus Torvalds 	opl3 = p;
317*1da177e4SLinus Torvalds 
318*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
319*1da177e4SLinus Torvalds 	snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
320*1da177e4SLinus Torvalds 		   chan->number, chan->midi_program, note, vel);
321*1da177e4SLinus Torvalds #endif
322*1da177e4SLinus Torvalds 	wanted.cluster = 0;
323*1da177e4SLinus Torvalds 	wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
324*1da177e4SLinus Torvalds 
325*1da177e4SLinus Torvalds 	/* in SYNTH mode, application takes care of voices */
326*1da177e4SLinus Torvalds 	/* in SEQ mode, drum voice numbers are notes on drum channel */
327*1da177e4SLinus Torvalds 	if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
328*1da177e4SLinus Torvalds 		if (chan->drum_channel) {
329*1da177e4SLinus Torvalds 			/* percussion instruments are located in bank 128 */
330*1da177e4SLinus Torvalds 			wanted.bank = 128;
331*1da177e4SLinus Torvalds 			wanted.prg = note;
332*1da177e4SLinus Torvalds 		} else {
333*1da177e4SLinus Torvalds 			wanted.bank = chan->gm_bank_select;
334*1da177e4SLinus Torvalds 			wanted.prg = chan->midi_program;
335*1da177e4SLinus Torvalds 		}
336*1da177e4SLinus Torvalds 	} else {
337*1da177e4SLinus Torvalds 		/* Prepare for OSS mode */
338*1da177e4SLinus Torvalds 		if (chan->number >= MAX_OPL3_VOICES)
339*1da177e4SLinus Torvalds 			return;
340*1da177e4SLinus Torvalds 
341*1da177e4SLinus Torvalds 		/* OSS instruments are located in bank 127 */
342*1da177e4SLinus Torvalds 		wanted.bank = 127;
343*1da177e4SLinus Torvalds 		wanted.prg = chan->midi_program;
344*1da177e4SLinus Torvalds 	}
345*1da177e4SLinus Torvalds 
346*1da177e4SLinus Torvalds 	spin_lock_irqsave(&opl3->voice_lock, flags);
347*1da177e4SLinus Torvalds 
348*1da177e4SLinus Torvalds 	if (use_internal_drums) {
349*1da177e4SLinus Torvalds 		snd_opl3_drum_switch(opl3, note, vel, 1, chan);
350*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&opl3->voice_lock, flags);
351*1da177e4SLinus Torvalds 		return;
352*1da177e4SLinus Torvalds 	}
353*1da177e4SLinus Torvalds 
354*1da177e4SLinus Torvalds  __extra_prg:
355*1da177e4SLinus Torvalds 	kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0);
356*1da177e4SLinus Torvalds 	if (kinstr == NULL) {
357*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&opl3->voice_lock, flags);
358*1da177e4SLinus Torvalds 		return;
359*1da177e4SLinus Torvalds 	}
360*1da177e4SLinus Torvalds 
361*1da177e4SLinus Torvalds 	fm = KINSTR_DATA(kinstr);
362*1da177e4SLinus Torvalds 
363*1da177e4SLinus Torvalds 	switch (fm->type) {
364*1da177e4SLinus Torvalds 	case FM_PATCH_OPL2:
365*1da177e4SLinus Torvalds 		instr_4op = 0;
366*1da177e4SLinus Torvalds 		break;
367*1da177e4SLinus Torvalds 	case FM_PATCH_OPL3:
368*1da177e4SLinus Torvalds 		if (opl3->hardware >= OPL3_HW_OPL3) {
369*1da177e4SLinus Torvalds 			instr_4op = 1;
370*1da177e4SLinus Torvalds 			break;
371*1da177e4SLinus Torvalds 		}
372*1da177e4SLinus Torvalds 	default:
373*1da177e4SLinus Torvalds 		snd_seq_instr_free_use(opl3->ilist, kinstr);
374*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&opl3->voice_lock, flags);
375*1da177e4SLinus Torvalds 		return;
376*1da177e4SLinus Torvalds 	}
377*1da177e4SLinus Torvalds 
378*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
379*1da177e4SLinus Torvalds 	snd_printk("  --> OPL%i instrument: %s\n",
380*1da177e4SLinus Torvalds 		   instr_4op ? 3 : 2, kinstr->name);
381*1da177e4SLinus Torvalds #endif
382*1da177e4SLinus Torvalds 	/* in SYNTH mode, application takes care of voices */
383*1da177e4SLinus Torvalds 	/* in SEQ mode, allocate voice on free OPL3 channel */
384*1da177e4SLinus Torvalds 	if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
385*1da177e4SLinus Torvalds 		voice = opl3_get_voice(opl3, instr_4op, chan);
386*1da177e4SLinus Torvalds 	} else {
387*1da177e4SLinus Torvalds 		/* remap OSS voice */
388*1da177e4SLinus Torvalds 		voice = snd_opl3_oss_map[chan->number];
389*1da177e4SLinus Torvalds 	}
390*1da177e4SLinus Torvalds 
391*1da177e4SLinus Torvalds 	if (voice < MAX_OPL2_VOICES) {
392*1da177e4SLinus Torvalds 		/* Left register block for voices 0 .. 8 */
393*1da177e4SLinus Torvalds 		reg_side = OPL3_LEFT;
394*1da177e4SLinus Torvalds 		voice_offset = voice;
395*1da177e4SLinus Torvalds 		connect_mask = (OPL3_LEFT_4OP_0 << voice_offset) & 0x07;
396*1da177e4SLinus Torvalds 	} else {
397*1da177e4SLinus Torvalds 		/* Right register block for voices 9 .. 17 */
398*1da177e4SLinus Torvalds 		reg_side = OPL3_RIGHT;
399*1da177e4SLinus Torvalds 		voice_offset = voice - MAX_OPL2_VOICES;
400*1da177e4SLinus Torvalds 		connect_mask = (OPL3_RIGHT_4OP_0 << voice_offset) & 0x38;
401*1da177e4SLinus Torvalds 	}
402*1da177e4SLinus Torvalds 
403*1da177e4SLinus Torvalds 	/* kill voice on channel */
404*1da177e4SLinus Torvalds 	vp = &opl3->voices[voice];
405*1da177e4SLinus Torvalds 	if (vp->state > 0) {
406*1da177e4SLinus Torvalds 		opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
407*1da177e4SLinus Torvalds 		reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT;
408*1da177e4SLinus Torvalds 		opl3->command(opl3, opl3_reg, reg_val);
409*1da177e4SLinus Torvalds 	}
410*1da177e4SLinus Torvalds 	if (instr_4op) {
411*1da177e4SLinus Torvalds 		vp2 = &opl3->voices[voice + 3];
412*1da177e4SLinus Torvalds 		if (vp->state > 0) {
413*1da177e4SLinus Torvalds 			opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK +
414*1da177e4SLinus Torvalds 					       voice_offset + 3);
415*1da177e4SLinus Torvalds 			reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT;
416*1da177e4SLinus Torvalds 			opl3->command(opl3, opl3_reg, reg_val);
417*1da177e4SLinus Torvalds 		}
418*1da177e4SLinus Torvalds 	}
419*1da177e4SLinus Torvalds 
420*1da177e4SLinus Torvalds 	/* set connection register */
421*1da177e4SLinus Torvalds 	if (instr_4op) {
422*1da177e4SLinus Torvalds 		if ((opl3->connection_reg ^ connect_mask) & connect_mask) {
423*1da177e4SLinus Torvalds 			opl3->connection_reg |= connect_mask;
424*1da177e4SLinus Torvalds 			/* set connection bit */
425*1da177e4SLinus Torvalds 			opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT;
426*1da177e4SLinus Torvalds 			opl3->command(opl3, opl3_reg, opl3->connection_reg);
427*1da177e4SLinus Torvalds 		}
428*1da177e4SLinus Torvalds 	} else {
429*1da177e4SLinus Torvalds 		if ((opl3->connection_reg ^ ~connect_mask) & connect_mask) {
430*1da177e4SLinus Torvalds 			opl3->connection_reg &= ~connect_mask;
431*1da177e4SLinus Torvalds 			/* clear connection bit */
432*1da177e4SLinus Torvalds 			opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT;
433*1da177e4SLinus Torvalds 			opl3->command(opl3, opl3_reg, opl3->connection_reg);
434*1da177e4SLinus Torvalds 		}
435*1da177e4SLinus Torvalds 	}
436*1da177e4SLinus Torvalds 
437*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
438*1da177e4SLinus Torvalds 	snd_printk("  --> setting OPL3 connection: 0x%x\n",
439*1da177e4SLinus Torvalds 		   opl3->connection_reg);
440*1da177e4SLinus Torvalds #endif
441*1da177e4SLinus Torvalds 	/*
442*1da177e4SLinus Torvalds 	 * calculate volume depending on connection
443*1da177e4SLinus Torvalds 	 * between FM operators (see include/opl3.h)
444*1da177e4SLinus Torvalds 	 */
445*1da177e4SLinus Torvalds 	for (i = 0; i < (instr_4op ? 4 : 2); i++)
446*1da177e4SLinus Torvalds 		vol_op[i] = fm->op[i].ksl_level;
447*1da177e4SLinus Torvalds 
448*1da177e4SLinus Torvalds 	connection = fm->feedback_connection[0] & 0x01;
449*1da177e4SLinus Torvalds 	if (instr_4op) {
450*1da177e4SLinus Torvalds 		connection <<= 1;
451*1da177e4SLinus Torvalds 		connection |= fm->feedback_connection[1] & 0x01;
452*1da177e4SLinus Torvalds 
453*1da177e4SLinus Torvalds 		snd_opl3_calc_volume(&vol_op[3], vel, chan);
454*1da177e4SLinus Torvalds 		switch (connection) {
455*1da177e4SLinus Torvalds 		case 0x03:
456*1da177e4SLinus Torvalds 			snd_opl3_calc_volume(&vol_op[2], vel, chan);
457*1da177e4SLinus Torvalds 			/* fallthru */
458*1da177e4SLinus Torvalds 		case 0x02:
459*1da177e4SLinus Torvalds 			snd_opl3_calc_volume(&vol_op[0], vel, chan);
460*1da177e4SLinus Torvalds 			break;
461*1da177e4SLinus Torvalds 		case 0x01:
462*1da177e4SLinus Torvalds 			snd_opl3_calc_volume(&vol_op[1], vel, chan);
463*1da177e4SLinus Torvalds 		}
464*1da177e4SLinus Torvalds 	} else {
465*1da177e4SLinus Torvalds 		snd_opl3_calc_volume(&vol_op[1], vel, chan);
466*1da177e4SLinus Torvalds 		if (connection)
467*1da177e4SLinus Torvalds 			snd_opl3_calc_volume(&vol_op[0], vel, chan);
468*1da177e4SLinus Torvalds 	}
469*1da177e4SLinus Torvalds 
470*1da177e4SLinus Torvalds 	/* Program the FM voice characteristics */
471*1da177e4SLinus Torvalds 	for (i = 0; i < (instr_4op ? 4 : 2); i++) {
472*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
473*1da177e4SLinus Torvalds 		snd_printk("  --> programming operator %i\n", i);
474*1da177e4SLinus Torvalds #endif
475*1da177e4SLinus Torvalds 		op_offset = snd_opl3_regmap[voice_offset][i];
476*1da177e4SLinus Torvalds 
477*1da177e4SLinus Torvalds 		/* Set OPL3 AM_VIB register of requested voice/operator */
478*1da177e4SLinus Torvalds 		reg_val = fm->op[i].am_vib;
479*1da177e4SLinus Torvalds 		opl3_reg = reg_side | (OPL3_REG_AM_VIB + op_offset);
480*1da177e4SLinus Torvalds 		opl3->command(opl3, opl3_reg, reg_val);
481*1da177e4SLinus Torvalds 
482*1da177e4SLinus Torvalds 		/* Set OPL3 KSL_LEVEL register of requested voice/operator */
483*1da177e4SLinus Torvalds 		reg_val = vol_op[i];
484*1da177e4SLinus Torvalds 		opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + op_offset);
485*1da177e4SLinus Torvalds 		opl3->command(opl3, opl3_reg, reg_val);
486*1da177e4SLinus Torvalds 
487*1da177e4SLinus Torvalds 		/* Set OPL3 ATTACK_DECAY register of requested voice/operator */
488*1da177e4SLinus Torvalds 		reg_val = fm->op[i].attack_decay;
489*1da177e4SLinus Torvalds 		opl3_reg = reg_side | (OPL3_REG_ATTACK_DECAY + op_offset);
490*1da177e4SLinus Torvalds 		opl3->command(opl3, opl3_reg, reg_val);
491*1da177e4SLinus Torvalds 
492*1da177e4SLinus Torvalds 		/* Set OPL3 SUSTAIN_RELEASE register of requested voice/operator */
493*1da177e4SLinus Torvalds 		reg_val = fm->op[i].sustain_release;
494*1da177e4SLinus Torvalds 		opl3_reg = reg_side | (OPL3_REG_SUSTAIN_RELEASE + op_offset);
495*1da177e4SLinus Torvalds 		opl3->command(opl3, opl3_reg, reg_val);
496*1da177e4SLinus Torvalds 
497*1da177e4SLinus Torvalds 		/* Select waveform */
498*1da177e4SLinus Torvalds 		reg_val = fm->op[i].wave_select;
499*1da177e4SLinus Torvalds 		opl3_reg = reg_side | (OPL3_REG_WAVE_SELECT + op_offset);
500*1da177e4SLinus Torvalds 		opl3->command(opl3, opl3_reg, reg_val);
501*1da177e4SLinus Torvalds 	}
502*1da177e4SLinus Torvalds 
503*1da177e4SLinus Torvalds 	/* Set operator feedback and 2op inter-operator connection */
504*1da177e4SLinus Torvalds 	reg_val = fm->feedback_connection[0];
505*1da177e4SLinus Torvalds 	/* Set output voice connection */
506*1da177e4SLinus Torvalds 	reg_val |= OPL3_STEREO_BITS;
507*1da177e4SLinus Torvalds 	if (chan->gm_pan < 43)
508*1da177e4SLinus Torvalds 		reg_val &= ~OPL3_VOICE_TO_RIGHT;
509*1da177e4SLinus Torvalds 	if (chan->gm_pan > 85)
510*1da177e4SLinus Torvalds 		reg_val &= ~OPL3_VOICE_TO_LEFT;
511*1da177e4SLinus Torvalds 	opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);
512*1da177e4SLinus Torvalds 	opl3->command(opl3, opl3_reg, reg_val);
513*1da177e4SLinus Torvalds 
514*1da177e4SLinus Torvalds 	if (instr_4op) {
515*1da177e4SLinus Torvalds 		/* Set 4op inter-operator connection */
516*1da177e4SLinus Torvalds 		reg_val = fm->feedback_connection[1] & OPL3_CONNECTION_BIT;
517*1da177e4SLinus Torvalds 		/* Set output voice connection */
518*1da177e4SLinus Torvalds 		reg_val |= OPL3_STEREO_BITS;
519*1da177e4SLinus Torvalds 		if (chan->gm_pan < 43)
520*1da177e4SLinus Torvalds 			reg_val &= ~OPL3_VOICE_TO_RIGHT;
521*1da177e4SLinus Torvalds 		if (chan->gm_pan > 85)
522*1da177e4SLinus Torvalds 			reg_val &= ~OPL3_VOICE_TO_LEFT;
523*1da177e4SLinus Torvalds 		opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION +
524*1da177e4SLinus Torvalds 				       voice_offset + 3);
525*1da177e4SLinus Torvalds 		opl3->command(opl3, opl3_reg, reg_val);
526*1da177e4SLinus Torvalds 	}
527*1da177e4SLinus Torvalds 
528*1da177e4SLinus Torvalds 	/*
529*1da177e4SLinus Torvalds 	 * Special treatment of percussion notes for fm:
530*1da177e4SLinus Torvalds 	 * Requested pitch is really program, and pitch for
531*1da177e4SLinus Torvalds 	 * device is whatever was specified in the patch library.
532*1da177e4SLinus Torvalds 	 */
533*1da177e4SLinus Torvalds 	if (fm->fix_key)
534*1da177e4SLinus Torvalds 		note = fm->fix_key;
535*1da177e4SLinus Torvalds 	/*
536*1da177e4SLinus Torvalds 	 * use transpose if defined in patch library
537*1da177e4SLinus Torvalds 	 */
538*1da177e4SLinus Torvalds 	if (fm->trnsps)
539*1da177e4SLinus Torvalds 		note += (fm->trnsps - 64);
540*1da177e4SLinus Torvalds 
541*1da177e4SLinus Torvalds 	snd_opl3_calc_pitch(&fnum, &blocknum, note, chan);
542*1da177e4SLinus Torvalds 
543*1da177e4SLinus Torvalds 	/* Set OPL3 FNUM_LOW register of requested voice */
544*1da177e4SLinus Torvalds 	opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset);
545*1da177e4SLinus Torvalds 	opl3->command(opl3, opl3_reg, fnum);
546*1da177e4SLinus Torvalds 
547*1da177e4SLinus Torvalds 	opl3->voices[voice].keyon_reg = blocknum;
548*1da177e4SLinus Torvalds 
549*1da177e4SLinus Torvalds 	/* Set output sound flag */
550*1da177e4SLinus Torvalds 	blocknum |= OPL3_KEYON_BIT;
551*1da177e4SLinus Torvalds 
552*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
553*1da177e4SLinus Torvalds 	snd_printk("  --> trigger voice %i\n", voice);
554*1da177e4SLinus Torvalds #endif
555*1da177e4SLinus Torvalds 	/* Set OPL3 KEYON_BLOCK register of requested voice */
556*1da177e4SLinus Torvalds 	opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
557*1da177e4SLinus Torvalds 	opl3->command(opl3, opl3_reg, blocknum);
558*1da177e4SLinus Torvalds 
559*1da177e4SLinus Torvalds 	/* kill note after fixed duration (in centiseconds) */
560*1da177e4SLinus Torvalds 	if (fm->fix_dur) {
561*1da177e4SLinus Torvalds 		opl3->voices[voice].note_off = jiffies +
562*1da177e4SLinus Torvalds 			(fm->fix_dur * HZ) / 100;
563*1da177e4SLinus Torvalds 		snd_opl3_start_timer(opl3);
564*1da177e4SLinus Torvalds 		opl3->voices[voice].note_off_check = 1;
565*1da177e4SLinus Torvalds 	} else
566*1da177e4SLinus Torvalds 		opl3->voices[voice].note_off_check = 0;
567*1da177e4SLinus Torvalds 
568*1da177e4SLinus Torvalds 	/* get extra pgm, but avoid possible loops */
569*1da177e4SLinus Torvalds 	extra_prg = (extra_prg) ? 0 : fm->modes;
570*1da177e4SLinus Torvalds 
571*1da177e4SLinus Torvalds 	snd_seq_instr_free_use(opl3->ilist, kinstr);
572*1da177e4SLinus Torvalds 
573*1da177e4SLinus Torvalds 	/* do the bookkeeping */
574*1da177e4SLinus Torvalds 	vp->time = opl3->use_time++;
575*1da177e4SLinus Torvalds 	vp->note = key;
576*1da177e4SLinus Torvalds 	vp->chan = chan;
577*1da177e4SLinus Torvalds 
578*1da177e4SLinus Torvalds 	if (instr_4op) {
579*1da177e4SLinus Torvalds 		vp->state = SNDRV_OPL3_ST_ON_4OP;
580*1da177e4SLinus Torvalds 
581*1da177e4SLinus Torvalds 		vp2 = &opl3->voices[voice + 3];
582*1da177e4SLinus Torvalds 		vp2->time = opl3->use_time++;
583*1da177e4SLinus Torvalds 		vp2->note = key;
584*1da177e4SLinus Torvalds 		vp2->chan = chan;
585*1da177e4SLinus Torvalds 		vp2->state = SNDRV_OPL3_ST_NOT_AVAIL;
586*1da177e4SLinus Torvalds 	} else {
587*1da177e4SLinus Torvalds 		if (vp->state == SNDRV_OPL3_ST_ON_4OP) {
588*1da177e4SLinus Torvalds 			/* 4op killed by 2op, release bounded voice */
589*1da177e4SLinus Torvalds 			vp2 = &opl3->voices[voice + 3];
590*1da177e4SLinus Torvalds 			vp2->time = opl3->use_time++;
591*1da177e4SLinus Torvalds 			vp2->state = SNDRV_OPL3_ST_OFF;
592*1da177e4SLinus Torvalds 		}
593*1da177e4SLinus Torvalds 		vp->state = SNDRV_OPL3_ST_ON_2OP;
594*1da177e4SLinus Torvalds 	}
595*1da177e4SLinus Torvalds 
596*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC
597*1da177e4SLinus Torvalds 	debug_alloc(opl3, "note on ", voice);
598*1da177e4SLinus Torvalds #endif
599*1da177e4SLinus Torvalds 
600*1da177e4SLinus Torvalds 	/* allocate extra program if specified in patch library */
601*1da177e4SLinus Torvalds 	if (extra_prg) {
602*1da177e4SLinus Torvalds 		if (extra_prg > 128) {
603*1da177e4SLinus Torvalds 			wanted.bank = 128;
604*1da177e4SLinus Torvalds 			/* percussions start at 35 */
605*1da177e4SLinus Torvalds 			wanted.prg = extra_prg - 128 + 35 - 1;
606*1da177e4SLinus Torvalds 		} else {
607*1da177e4SLinus Torvalds 			wanted.bank = 0;
608*1da177e4SLinus Torvalds 			wanted.prg = extra_prg - 1;
609*1da177e4SLinus Torvalds 		}
610*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
611*1da177e4SLinus Torvalds 		snd_printk(" *** allocating extra program\n");
612*1da177e4SLinus Torvalds #endif
613*1da177e4SLinus Torvalds 		goto __extra_prg;
614*1da177e4SLinus Torvalds 	}
615*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl3->voice_lock, flags);
616*1da177e4SLinus Torvalds }
617*1da177e4SLinus Torvalds 
618*1da177e4SLinus Torvalds static void snd_opl3_kill_voice(opl3_t *opl3, int voice)
619*1da177e4SLinus Torvalds {
620*1da177e4SLinus Torvalds 	unsigned short reg_side;
621*1da177e4SLinus Torvalds 	unsigned char voice_offset;
622*1da177e4SLinus Torvalds 	unsigned short opl3_reg;
623*1da177e4SLinus Torvalds 
624*1da177e4SLinus Torvalds 	snd_opl3_voice_t *vp, *vp2;
625*1da177e4SLinus Torvalds 
626*1da177e4SLinus Torvalds 	snd_assert(voice < MAX_OPL3_VOICES, return);
627*1da177e4SLinus Torvalds 
628*1da177e4SLinus Torvalds 	vp = &opl3->voices[voice];
629*1da177e4SLinus Torvalds 	if (voice < MAX_OPL2_VOICES) {
630*1da177e4SLinus Torvalds 		/* Left register block for voices 0 .. 8 */
631*1da177e4SLinus Torvalds 		reg_side = OPL3_LEFT;
632*1da177e4SLinus Torvalds 		voice_offset = voice;
633*1da177e4SLinus Torvalds 	} else {
634*1da177e4SLinus Torvalds 		/* Right register block for voices 9 .. 17 */
635*1da177e4SLinus Torvalds 		reg_side = OPL3_RIGHT;
636*1da177e4SLinus Torvalds 		voice_offset = voice - MAX_OPL2_VOICES;
637*1da177e4SLinus Torvalds 	}
638*1da177e4SLinus Torvalds 
639*1da177e4SLinus Torvalds 	/* kill voice */
640*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
641*1da177e4SLinus Torvalds 	snd_printk("  --> kill voice %i\n", voice);
642*1da177e4SLinus Torvalds #endif
643*1da177e4SLinus Torvalds 	opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
644*1da177e4SLinus Torvalds 	/* clear Key ON bit */
645*1da177e4SLinus Torvalds 	opl3->command(opl3, opl3_reg, vp->keyon_reg);
646*1da177e4SLinus Torvalds 
647*1da177e4SLinus Torvalds 	/* do the bookkeeping */
648*1da177e4SLinus Torvalds 	vp->time = opl3->use_time++;
649*1da177e4SLinus Torvalds 
650*1da177e4SLinus Torvalds 	if (vp->state == SNDRV_OPL3_ST_ON_4OP) {
651*1da177e4SLinus Torvalds 		vp2 = &opl3->voices[voice + 3];
652*1da177e4SLinus Torvalds 
653*1da177e4SLinus Torvalds 		vp2->time = opl3->use_time++;
654*1da177e4SLinus Torvalds 		vp2->state = SNDRV_OPL3_ST_OFF;
655*1da177e4SLinus Torvalds 	}
656*1da177e4SLinus Torvalds 	vp->state = SNDRV_OPL3_ST_OFF;
657*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC
658*1da177e4SLinus Torvalds 	debug_alloc(opl3, "note off", voice);
659*1da177e4SLinus Torvalds #endif
660*1da177e4SLinus Torvalds 
661*1da177e4SLinus Torvalds }
662*1da177e4SLinus Torvalds 
663*1da177e4SLinus Torvalds /*
664*1da177e4SLinus Torvalds  * Release a note in response to a midi note off.
665*1da177e4SLinus Torvalds  */
666*1da177e4SLinus Torvalds void snd_opl3_note_off(void *p, int note, int vel, snd_midi_channel_t *chan)
667*1da177e4SLinus Torvalds {
668*1da177e4SLinus Torvalds   	opl3_t *opl3;
669*1da177e4SLinus Torvalds 
670*1da177e4SLinus Torvalds 	int voice;
671*1da177e4SLinus Torvalds 	snd_opl3_voice_t *vp;
672*1da177e4SLinus Torvalds 
673*1da177e4SLinus Torvalds 	unsigned long flags;
674*1da177e4SLinus Torvalds 
675*1da177e4SLinus Torvalds 	opl3 = p;
676*1da177e4SLinus Torvalds 
677*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
678*1da177e4SLinus Torvalds 	snd_printk("Note off, ch %i, inst %i, note %i\n",
679*1da177e4SLinus Torvalds 		   chan->number, chan->midi_program, note);
680*1da177e4SLinus Torvalds #endif
681*1da177e4SLinus Torvalds 
682*1da177e4SLinus Torvalds 	spin_lock_irqsave(&opl3->voice_lock, flags);
683*1da177e4SLinus Torvalds 
684*1da177e4SLinus Torvalds 	if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
685*1da177e4SLinus Torvalds 		if (chan->drum_channel && use_internal_drums) {
686*1da177e4SLinus Torvalds 			snd_opl3_drum_switch(opl3, note, vel, 0, chan);
687*1da177e4SLinus Torvalds 			spin_unlock_irqrestore(&opl3->voice_lock, flags);
688*1da177e4SLinus Torvalds 			return;
689*1da177e4SLinus Torvalds 		}
690*1da177e4SLinus Torvalds 		/* this loop will hopefully kill all extra voices, because
691*1da177e4SLinus Torvalds 		   they are grouped by the same channel and note values */
692*1da177e4SLinus Torvalds 		for (voice = 0; voice < opl3->max_voices; voice++) {
693*1da177e4SLinus Torvalds 			vp = &opl3->voices[voice];
694*1da177e4SLinus Torvalds 			if (vp->state > 0 && vp->chan == chan && vp->note == note) {
695*1da177e4SLinus Torvalds 				snd_opl3_kill_voice(opl3, voice);
696*1da177e4SLinus Torvalds 			}
697*1da177e4SLinus Torvalds 		}
698*1da177e4SLinus Torvalds 	} else {
699*1da177e4SLinus Torvalds 		/* remap OSS voices */
700*1da177e4SLinus Torvalds 		if (chan->number < MAX_OPL3_VOICES) {
701*1da177e4SLinus Torvalds 			voice = snd_opl3_oss_map[chan->number];
702*1da177e4SLinus Torvalds 			snd_opl3_kill_voice(opl3, voice);
703*1da177e4SLinus Torvalds 		}
704*1da177e4SLinus Torvalds 	}
705*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl3->voice_lock, flags);
706*1da177e4SLinus Torvalds }
707*1da177e4SLinus Torvalds 
708*1da177e4SLinus Torvalds /*
709*1da177e4SLinus Torvalds  * key pressure change
710*1da177e4SLinus Torvalds  */
711*1da177e4SLinus Torvalds void snd_opl3_key_press(void *p, int note, int vel, snd_midi_channel_t *chan)
712*1da177e4SLinus Torvalds {
713*1da177e4SLinus Torvalds   	opl3_t *opl3;
714*1da177e4SLinus Torvalds 
715*1da177e4SLinus Torvalds 	opl3 = p;
716*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
717*1da177e4SLinus Torvalds 	snd_printk("Key pressure, ch#: %i, inst#: %i\n",
718*1da177e4SLinus Torvalds 		   chan->number, chan->midi_program);
719*1da177e4SLinus Torvalds #endif
720*1da177e4SLinus Torvalds }
721*1da177e4SLinus Torvalds 
722*1da177e4SLinus Torvalds /*
723*1da177e4SLinus Torvalds  * terminate note
724*1da177e4SLinus Torvalds  */
725*1da177e4SLinus Torvalds void snd_opl3_terminate_note(void *p, int note, snd_midi_channel_t *chan)
726*1da177e4SLinus Torvalds {
727*1da177e4SLinus Torvalds   	opl3_t *opl3;
728*1da177e4SLinus Torvalds 
729*1da177e4SLinus Torvalds 	opl3 = p;
730*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
731*1da177e4SLinus Torvalds 	snd_printk("Terminate note, ch#: %i, inst#: %i\n",
732*1da177e4SLinus Torvalds 		   chan->number, chan->midi_program);
733*1da177e4SLinus Torvalds #endif
734*1da177e4SLinus Torvalds }
735*1da177e4SLinus Torvalds 
736*1da177e4SLinus Torvalds static void snd_opl3_update_pitch(opl3_t *opl3, int voice)
737*1da177e4SLinus Torvalds {
738*1da177e4SLinus Torvalds 	unsigned short reg_side;
739*1da177e4SLinus Torvalds 	unsigned char voice_offset;
740*1da177e4SLinus Torvalds 	unsigned short opl3_reg;
741*1da177e4SLinus Torvalds 
742*1da177e4SLinus Torvalds 	unsigned char fnum, blocknum;
743*1da177e4SLinus Torvalds 
744*1da177e4SLinus Torvalds 	snd_opl3_voice_t *vp;
745*1da177e4SLinus Torvalds 
746*1da177e4SLinus Torvalds 	snd_assert(voice < MAX_OPL3_VOICES, return);
747*1da177e4SLinus Torvalds 
748*1da177e4SLinus Torvalds 	vp = &opl3->voices[voice];
749*1da177e4SLinus Torvalds 	if (vp->chan == NULL)
750*1da177e4SLinus Torvalds 		return; /* not allocated? */
751*1da177e4SLinus Torvalds 
752*1da177e4SLinus Torvalds 	if (voice < MAX_OPL2_VOICES) {
753*1da177e4SLinus Torvalds 		/* Left register block for voices 0 .. 8 */
754*1da177e4SLinus Torvalds 		reg_side = OPL3_LEFT;
755*1da177e4SLinus Torvalds 		voice_offset = voice;
756*1da177e4SLinus Torvalds 	} else {
757*1da177e4SLinus Torvalds 		/* Right register block for voices 9 .. 17 */
758*1da177e4SLinus Torvalds 		reg_side = OPL3_RIGHT;
759*1da177e4SLinus Torvalds 		voice_offset = voice - MAX_OPL2_VOICES;
760*1da177e4SLinus Torvalds 	}
761*1da177e4SLinus Torvalds 
762*1da177e4SLinus Torvalds 	snd_opl3_calc_pitch(&fnum, &blocknum, vp->note, vp->chan);
763*1da177e4SLinus Torvalds 
764*1da177e4SLinus Torvalds 	/* Set OPL3 FNUM_LOW register of requested voice */
765*1da177e4SLinus Torvalds 	opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset);
766*1da177e4SLinus Torvalds 	opl3->command(opl3, opl3_reg, fnum);
767*1da177e4SLinus Torvalds 
768*1da177e4SLinus Torvalds 	vp->keyon_reg = blocknum;
769*1da177e4SLinus Torvalds 
770*1da177e4SLinus Torvalds 	/* Set output sound flag */
771*1da177e4SLinus Torvalds 	blocknum |= OPL3_KEYON_BIT;
772*1da177e4SLinus Torvalds 
773*1da177e4SLinus Torvalds 	/* Set OPL3 KEYON_BLOCK register of requested voice */
774*1da177e4SLinus Torvalds 	opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
775*1da177e4SLinus Torvalds 	opl3->command(opl3, opl3_reg, blocknum);
776*1da177e4SLinus Torvalds 
777*1da177e4SLinus Torvalds 	vp->time = opl3->use_time++;
778*1da177e4SLinus Torvalds }
779*1da177e4SLinus Torvalds 
780*1da177e4SLinus Torvalds /*
781*1da177e4SLinus Torvalds  * Update voice pitch controller
782*1da177e4SLinus Torvalds  */
783*1da177e4SLinus Torvalds static void snd_opl3_pitch_ctrl(opl3_t *opl3, snd_midi_channel_t *chan)
784*1da177e4SLinus Torvalds {
785*1da177e4SLinus Torvalds 	int voice;
786*1da177e4SLinus Torvalds 	snd_opl3_voice_t *vp;
787*1da177e4SLinus Torvalds 
788*1da177e4SLinus Torvalds 	unsigned long flags;
789*1da177e4SLinus Torvalds 
790*1da177e4SLinus Torvalds 	spin_lock_irqsave(&opl3->voice_lock, flags);
791*1da177e4SLinus Torvalds 
792*1da177e4SLinus Torvalds 	if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
793*1da177e4SLinus Torvalds 		for (voice = 0; voice < opl3->max_voices; voice++) {
794*1da177e4SLinus Torvalds 			vp = &opl3->voices[voice];
795*1da177e4SLinus Torvalds 			if (vp->state > 0 && vp->chan == chan) {
796*1da177e4SLinus Torvalds 				snd_opl3_update_pitch(opl3, voice);
797*1da177e4SLinus Torvalds 			}
798*1da177e4SLinus Torvalds 		}
799*1da177e4SLinus Torvalds 	} else {
800*1da177e4SLinus Torvalds 		/* remap OSS voices */
801*1da177e4SLinus Torvalds 		if (chan->number < MAX_OPL3_VOICES) {
802*1da177e4SLinus Torvalds 			voice = snd_opl3_oss_map[chan->number];
803*1da177e4SLinus Torvalds 			snd_opl3_update_pitch(opl3, voice);
804*1da177e4SLinus Torvalds 		}
805*1da177e4SLinus Torvalds 	}
806*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl3->voice_lock, flags);
807*1da177e4SLinus Torvalds }
808*1da177e4SLinus Torvalds 
809*1da177e4SLinus Torvalds /*
810*1da177e4SLinus Torvalds  * Deal with a controler type event.  This includes all types of
811*1da177e4SLinus Torvalds  * control events, not just the midi controllers
812*1da177e4SLinus Torvalds  */
813*1da177e4SLinus Torvalds void snd_opl3_control(void *p, int type, snd_midi_channel_t *chan)
814*1da177e4SLinus Torvalds {
815*1da177e4SLinus Torvalds   	opl3_t *opl3;
816*1da177e4SLinus Torvalds 
817*1da177e4SLinus Torvalds 	opl3 = p;
818*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
819*1da177e4SLinus Torvalds 	snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n",
820*1da177e4SLinus Torvalds 		   type, chan->number, chan->midi_program);
821*1da177e4SLinus Torvalds #endif
822*1da177e4SLinus Torvalds 
823*1da177e4SLinus Torvalds 	switch (type) {
824*1da177e4SLinus Torvalds 	case MIDI_CTL_MSB_MODWHEEL:
825*1da177e4SLinus Torvalds 		if (chan->control[MIDI_CTL_MSB_MODWHEEL] > 63)
826*1da177e4SLinus Torvalds 			opl3->drum_reg |= OPL3_VIBRATO_DEPTH;
827*1da177e4SLinus Torvalds 		else
828*1da177e4SLinus Torvalds 			opl3->drum_reg &= ~OPL3_VIBRATO_DEPTH;
829*1da177e4SLinus Torvalds 		opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,
830*1da177e4SLinus Torvalds 				 opl3->drum_reg);
831*1da177e4SLinus Torvalds 		break;
832*1da177e4SLinus Torvalds 	case MIDI_CTL_E2_TREMOLO_DEPTH:
833*1da177e4SLinus Torvalds 		if (chan->control[MIDI_CTL_E2_TREMOLO_DEPTH] > 63)
834*1da177e4SLinus Torvalds 			opl3->drum_reg |= OPL3_TREMOLO_DEPTH;
835*1da177e4SLinus Torvalds 		else
836*1da177e4SLinus Torvalds 			opl3->drum_reg &= ~OPL3_TREMOLO_DEPTH;
837*1da177e4SLinus Torvalds 		opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,
838*1da177e4SLinus Torvalds 				 opl3->drum_reg);
839*1da177e4SLinus Torvalds 		break;
840*1da177e4SLinus Torvalds 	case MIDI_CTL_PITCHBEND:
841*1da177e4SLinus Torvalds 		snd_opl3_pitch_ctrl(opl3, chan);
842*1da177e4SLinus Torvalds 		break;
843*1da177e4SLinus Torvalds 	}
844*1da177e4SLinus Torvalds }
845*1da177e4SLinus Torvalds 
846*1da177e4SLinus Torvalds /*
847*1da177e4SLinus Torvalds  * NRPN events
848*1da177e4SLinus Torvalds  */
849*1da177e4SLinus Torvalds void snd_opl3_nrpn(void *p, snd_midi_channel_t *chan,
850*1da177e4SLinus Torvalds 		   snd_midi_channel_set_t *chset)
851*1da177e4SLinus Torvalds {
852*1da177e4SLinus Torvalds   	opl3_t *opl3;
853*1da177e4SLinus Torvalds 
854*1da177e4SLinus Torvalds 	opl3 = p;
855*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
856*1da177e4SLinus Torvalds 	snd_printk("NRPN, ch#: %i, inst#: %i\n",
857*1da177e4SLinus Torvalds 		   chan->number, chan->midi_program);
858*1da177e4SLinus Torvalds #endif
859*1da177e4SLinus Torvalds }
860*1da177e4SLinus Torvalds 
861*1da177e4SLinus Torvalds /*
862*1da177e4SLinus Torvalds  * receive sysex
863*1da177e4SLinus Torvalds  */
864*1da177e4SLinus Torvalds void snd_opl3_sysex(void *p, unsigned char *buf, int len,
865*1da177e4SLinus Torvalds 		    int parsed, snd_midi_channel_set_t *chset)
866*1da177e4SLinus Torvalds {
867*1da177e4SLinus Torvalds   	opl3_t *opl3;
868*1da177e4SLinus Torvalds 
869*1da177e4SLinus Torvalds 	opl3 = p;
870*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI
871*1da177e4SLinus Torvalds 	snd_printk("SYSEX\n");
872*1da177e4SLinus Torvalds #endif
873*1da177e4SLinus Torvalds }
874