brintos

brintos / linux-shallow public Read only

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