⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 opl3_midi.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	snd_printk("  --> setting OPL3 connection: 0x%x\n",		   opl3->connection_reg);#endif	/*	 * calculate volume depending on connection	 * between FM operators (see include/opl3.h)	 */	for (i = 0; i < (instr_4op ? 4 : 2); i++)		vol_op[i] = fm->op[i].ksl_level;	connection = fm->feedback_connection[0] & 0x01;	if (instr_4op) {		connection <<= 1;		connection |= fm->feedback_connection[1] & 0x01;		snd_opl3_calc_volume(&vol_op[3], vel, chan);		switch (connection) {		case 0x03:			snd_opl3_calc_volume(&vol_op[2], vel, chan);			/* fallthru */		case 0x02:			snd_opl3_calc_volume(&vol_op[0], vel, chan);			break;		case 0x01:			snd_opl3_calc_volume(&vol_op[1], vel, chan);		}	} else {		snd_opl3_calc_volume(&vol_op[1], vel, chan);		if (connection)			snd_opl3_calc_volume(&vol_op[0], vel, chan);	}	/* Program the FM voice characteristics */	for (i = 0; i < (instr_4op ? 4 : 2); i++) {#ifdef DEBUG_MIDI		snd_printk("  --> programming operator %i\n", i);#endif		op_offset = snd_opl3_regmap[voice_offset][i];		/* Set OPL3 AM_VIB register of requested voice/operator */ 		reg_val = fm->op[i].am_vib;		opl3_reg = reg_side | (OPL3_REG_AM_VIB + op_offset);		opl3->command(opl3, opl3_reg, reg_val);		/* Set OPL3 KSL_LEVEL register of requested voice/operator */ 		reg_val = vol_op[i];		opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + op_offset);		opl3->command(opl3, opl3_reg, reg_val);		/* Set OPL3 ATTACK_DECAY register of requested voice/operator */ 		reg_val = fm->op[i].attack_decay;		opl3_reg = reg_side | (OPL3_REG_ATTACK_DECAY + op_offset);		opl3->command(opl3, opl3_reg, reg_val);		/* Set OPL3 SUSTAIN_RELEASE register of requested voice/operator */ 		reg_val = fm->op[i].sustain_release;		opl3_reg = reg_side | (OPL3_REG_SUSTAIN_RELEASE + op_offset);		opl3->command(opl3, opl3_reg, reg_val);		/* Select waveform */		reg_val = fm->op[i].wave_select;		opl3_reg = reg_side | (OPL3_REG_WAVE_SELECT + op_offset);		opl3->command(opl3, opl3_reg, reg_val);	}	/* Set operator feedback and 2op inter-operator connection */	reg_val = fm->feedback_connection[0];	/* Set output voice connection */	reg_val |= OPL3_STEREO_BITS;	if (chan->gm_pan < 43)		reg_val &= ~OPL3_VOICE_TO_RIGHT;	if (chan->gm_pan > 85)		reg_val &= ~OPL3_VOICE_TO_LEFT;	opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);	opl3->command(opl3, opl3_reg, reg_val);	if (instr_4op) {		/* Set 4op inter-operator connection */		reg_val = fm->feedback_connection[1] & OPL3_CONNECTION_BIT;		/* Set output voice connection */		reg_val |= OPL3_STEREO_BITS;		if (chan->gm_pan < 43)			reg_val &= ~OPL3_VOICE_TO_RIGHT;		if (chan->gm_pan > 85)			reg_val &= ~OPL3_VOICE_TO_LEFT;		opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION +				       voice_offset + 3);		opl3->command(opl3, opl3_reg, reg_val);	}	/*	 * Special treatment of percussion notes for fm:	 * Requested pitch is really program, and pitch for	 * device is whatever was specified in the patch library.	 */	if (fm->fix_key)		note = fm->fix_key;	/*	 * use transpose if defined in patch library	 */	if (fm->trnsps)		note += (fm->trnsps - 64);	snd_opl3_calc_pitch(&fnum, &blocknum, note, chan);	/* Set OPL3 FNUM_LOW register of requested voice */	opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset);	opl3->command(opl3, opl3_reg, fnum);	opl3->voices[voice].keyon_reg = blocknum;	/* Set output sound flag */	blocknum |= OPL3_KEYON_BIT;#ifdef DEBUG_MIDI	snd_printk("  --> trigger voice %i\n", voice);#endif	/* Set OPL3 KEYON_BLOCK register of requested voice */ 	opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);	opl3->command(opl3, opl3_reg, blocknum);	/* kill note after fixed duration (in centiseconds) */	if (fm->fix_dur) {		opl3->voices[voice].note_off = jiffies +			(fm->fix_dur * HZ) / 100;		snd_opl3_start_timer(opl3);		opl3->voices[voice].note_off_check = 1;	} else		opl3->voices[voice].note_off_check = 0;	/* get extra pgm, but avoid possible loops */	extra_prg = (extra_prg) ? 0 : fm->modes;	snd_seq_instr_free_use(opl3->ilist, kinstr);	/* do the bookkeeping */	vp->time = opl3->use_time++;	vp->note = key;	vp->chan = chan;	if (instr_4op) {		vp->state = SNDRV_OPL3_ST_ON_4OP;		vp2 = &opl3->voices[voice + 3];		vp2->time = opl3->use_time++;		vp2->note = key;		vp2->chan = chan;		vp2->state = SNDRV_OPL3_ST_NOT_AVAIL;	} else {		if (vp->state == SNDRV_OPL3_ST_ON_4OP) {			/* 4op killed by 2op, release bounded voice */			vp2 = &opl3->voices[voice + 3];			vp2->time = opl3->use_time++;			vp2->state = SNDRV_OPL3_ST_OFF;		}		vp->state = SNDRV_OPL3_ST_ON_2OP;	}#ifdef DEBUG_ALLOC	debug_alloc(opl3, "note on ", voice);#endif	/* allocate extra program if specified in patch library */	if (extra_prg) {		if (extra_prg > 128) {			wanted.bank = 128;			/* percussions start at 35 */			wanted.prg = extra_prg - 128 + 35 - 1;		} else {			wanted.bank = 0;			wanted.prg = extra_prg - 1;		}#ifdef DEBUG_MIDI		snd_printk(" *** allocating extra program\n");#endif		goto __extra_prg;	}	spin_unlock_irqrestore(&opl3->voice_lock, flags);}static void snd_opl3_kill_voice(opl3_t *opl3, int voice){	unsigned short reg_side;	unsigned char voice_offset;	unsigned short opl3_reg;	snd_opl3_voice_t *vp, *vp2;	snd_assert(voice < MAX_OPL3_VOICES, return);	vp = &opl3->voices[voice];	if (voice < MAX_OPL2_VOICES) {		/* Left register block for voices 0 .. 8 */		reg_side = OPL3_LEFT;		voice_offset = voice;	} else {		/* Right register block for voices 9 .. 17 */		reg_side = OPL3_RIGHT;		voice_offset = voice - MAX_OPL2_VOICES;	}	/* kill voice */#ifdef DEBUG_MIDI	snd_printk("  --> kill voice %i\n", voice);#endif	opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);	/* clear Key ON bit */	opl3->command(opl3, opl3_reg, vp->keyon_reg);	/* do the bookkeeping */	vp->time = opl3->use_time++;	if (vp->state == SNDRV_OPL3_ST_ON_4OP) {		vp2 = &opl3->voices[voice + 3];		vp2->time = opl3->use_time++;		vp2->state = SNDRV_OPL3_ST_OFF;	}	vp->state = SNDRV_OPL3_ST_OFF;#ifdef DEBUG_ALLOC	debug_alloc(opl3, "note off", voice);#endif}/* * Release a note in response to a midi note off. */void snd_opl3_note_off(void *p, int note, int vel, snd_midi_channel_t *chan){  	opl3_t *opl3;	int voice;	snd_opl3_voice_t *vp;	unsigned long flags;	opl3 = p;#ifdef DEBUG_MIDI	snd_printk("Note off, ch %i, inst %i, note %i\n",		   chan->number, chan->midi_program, note);#endif	spin_lock_irqsave(&opl3->voice_lock, flags);	if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {		if (chan->drum_channel && use_internal_drums) {			snd_opl3_drum_switch(opl3, note, vel, 0, chan);			spin_unlock_irqrestore(&opl3->voice_lock, flags);			return;		}		/* this loop will hopefully kill all extra voices, because		   they are grouped by the same channel and note values */		for (voice = 0; voice < opl3->max_voices; voice++) {			vp = &opl3->voices[voice];			if (vp->state > 0 && vp->chan == chan && vp->note == note) {				snd_opl3_kill_voice(opl3, voice);			}		}	} else {		/* remap OSS voices */		if (chan->number < MAX_OPL3_VOICES) {			voice = snd_opl3_oss_map[chan->number];					snd_opl3_kill_voice(opl3, voice);		}	}	spin_unlock_irqrestore(&opl3->voice_lock, flags);}/* * key pressure change */void snd_opl3_key_press(void *p, int note, int vel, snd_midi_channel_t *chan){  	opl3_t *opl3;	opl3 = p;#ifdef DEBUG_MIDI	snd_printk("Key pressure, ch#: %i, inst#: %i\n",		   chan->number, chan->midi_program);#endif}/* * terminate note */void snd_opl3_terminate_note(void *p, int note, snd_midi_channel_t *chan){  	opl3_t *opl3;	opl3 = p;#ifdef DEBUG_MIDI	snd_printk("Terminate note, ch#: %i, inst#: %i\n",		   chan->number, chan->midi_program);#endif}static void snd_opl3_update_pitch(opl3_t *opl3, int voice){	unsigned short reg_side;	unsigned char voice_offset;	unsigned short opl3_reg;	unsigned char fnum, blocknum;	snd_opl3_voice_t *vp;	snd_assert(voice < MAX_OPL3_VOICES, return);	vp = &opl3->voices[voice];	if (vp->chan == NULL)		return; /* not allocated? */	if (voice < MAX_OPL2_VOICES) {		/* Left register block for voices 0 .. 8 */		reg_side = OPL3_LEFT;		voice_offset = voice;	} else {		/* Right register block for voices 9 .. 17 */		reg_side = OPL3_RIGHT;		voice_offset = voice - MAX_OPL2_VOICES;	}	snd_opl3_calc_pitch(&fnum, &blocknum, vp->note, vp->chan);	/* Set OPL3 FNUM_LOW register of requested voice */	opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset);	opl3->command(opl3, opl3_reg, fnum);	vp->keyon_reg = blocknum;	/* Set output sound flag */	blocknum |= OPL3_KEYON_BIT;	/* Set OPL3 KEYON_BLOCK register of requested voice */ 	opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);	opl3->command(opl3, opl3_reg, blocknum);	vp->time = opl3->use_time++;}/* * Update voice pitch controller */static void snd_opl3_pitch_ctrl(opl3_t *opl3, snd_midi_channel_t *chan){	int voice;	snd_opl3_voice_t *vp;	unsigned long flags;	spin_lock_irqsave(&opl3->voice_lock, flags);	if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {		for (voice = 0; voice < opl3->max_voices; voice++) {			vp = &opl3->voices[voice];			if (vp->state > 0 && vp->chan == chan) {				snd_opl3_update_pitch(opl3, voice);			}		}	} else {		/* remap OSS voices */		if (chan->number < MAX_OPL3_VOICES) {			voice = snd_opl3_oss_map[chan->number];					snd_opl3_update_pitch(opl3, voice);		}	}	spin_unlock_irqrestore(&opl3->voice_lock, flags);}/* * Deal with a controler type event.  This includes all types of * control events, not just the midi controllers */void snd_opl3_control(void *p, int type, snd_midi_channel_t *chan){  	opl3_t *opl3;	opl3 = p;#ifdef DEBUG_MIDI	snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n",		   type, chan->number, chan->midi_program);#endif	switch (type) {	case MIDI_CTL_MSB_MODWHEEL:		if (chan->control[MIDI_CTL_MSB_MODWHEEL] > 63)			opl3->drum_reg |= OPL3_VIBRATO_DEPTH;		else 			opl3->drum_reg &= ~OPL3_VIBRATO_DEPTH;		opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,				 opl3->drum_reg);		break;	case MIDI_CTL_E2_TREMOLO_DEPTH:		if (chan->control[MIDI_CTL_E2_TREMOLO_DEPTH] > 63)			opl3->drum_reg |= OPL3_TREMOLO_DEPTH;		else 			opl3->drum_reg &= ~OPL3_TREMOLO_DEPTH;		opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,				 opl3->drum_reg);		break;	case MIDI_CTL_PITCHBEND:		snd_opl3_pitch_ctrl(opl3, chan);		break;	}}/* * NRPN events */void snd_opl3_nrpn(void *p, snd_midi_channel_t *chan,		   snd_midi_channel_set_t *chset){  	opl3_t *opl3;	opl3 = p;#ifdef DEBUG_MIDI	snd_printk("NRPN, ch#: %i, inst#: %i\n",		   chan->number, chan->midi_program);#endif}/* * receive sysex */void snd_opl3_sysex(void *p, unsigned char *buf, int len,		    int parsed, snd_midi_channel_set_t *chset){  	opl3_t *opl3;	opl3 = p;#ifdef DEBUG_MIDI	snd_printk("SYSEX\n");#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -