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

📄 opl4_synth.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	opl4_voice_t *voice;	spin_lock_irqsave(&opl4->reg_lock, flags);	for (i = 0; i < OPL4_MAX_VOICES; i++) {		voice = &opl4->voices[i];		if (voice->chan == chan && voice->note == note) {			func(opl4, voice);		}	}	spin_unlock_irqrestore(&opl4->reg_lock, flags);}/* * Executes the callback for all voices of to the specified channel. */static void snd_opl4_do_for_channel(opl4_t *opl4, snd_midi_channel_t *chan,				    void (*func)(opl4_t *opl4, opl4_voice_t *voice)){	int i;	unsigned long flags;	opl4_voice_t *voice;	spin_lock_irqsave(&opl4->reg_lock, flags);	for (i = 0; i < OPL4_MAX_VOICES; i++) {		voice = &opl4->voices[i];		if (voice->chan == chan) {			func(opl4, voice);		}	}	spin_unlock_irqrestore(&opl4->reg_lock, flags);}/* * Executes the callback for all active voices. */static void snd_opl4_do_for_all(opl4_t *opl4,				void (*func)(opl4_t *opl4, opl4_voice_t *voice)){	int i;	unsigned long flags;	opl4_voice_t *voice;	spin_lock_irqsave(&opl4->reg_lock, flags);	for (i = 0; i < OPL4_MAX_VOICES; i++) {		voice = &opl4->voices[i];		if (voice->chan)			func(opl4, voice);	}	spin_unlock_irqrestore(&opl4->reg_lock, flags);}static void snd_opl4_update_volume(opl4_t *opl4, opl4_voice_t *voice){	int att;	att = voice->sound->tone_attenuate;	att += snd_opl4_volume_table[opl4->chset->gs_master_volume & 0x7f];	att += snd_opl4_volume_table[voice->chan->gm_volume & 0x7f];	att += snd_opl4_volume_table[voice->chan->gm_expression & 0x7f];	att += snd_opl4_volume_table[voice->velocity];	att = 0x7f - (0x7f - att) * (voice->sound->volume_factor) / 0xfe - volume_boost;	if (att < 0)		att = 0;	else if (att > 0x7e)		att = 0x7e;	snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number,		       (att << 1) | voice->level_direct);	voice->level_direct = 0;}static void snd_opl4_update_pan(opl4_t *opl4, opl4_voice_t *voice){	int pan = voice->sound->panpot;	if (!voice->chan->drum_channel)		pan += (voice->chan->control[MIDI_CTL_MSB_PAN] - 0x40) >> 3;	if (pan < -7)		pan = -7;	else if (pan > 7)		pan = 7;	voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK)		| (pan & OPL4_PAN_POT_MASK);	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);}static void snd_opl4_update_vibrato_depth(opl4_t *opl4, opl4_voice_t *voice){	int depth;	if (voice->chan->drum_channel)		return;	depth = (7 - voice->sound->vibrato)		* (voice->chan->control[MIDI_CTL_VIBRATO_DEPTH] & 0x7f);	depth = (depth >> 7) + voice->sound->vibrato;	voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK;	voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK;	snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number,		       voice->reg_lfo_vibrato);}static void snd_opl4_update_pitch(opl4_t *opl4, opl4_voice_t *voice){	snd_midi_channel_t *chan = voice->chan;	int note, pitch, octave;	note = chan->drum_channel ? 60 : voice->note;	/*	 * pitch is in 100/128 cents, so 0x80 is one semitone and	 * 0x600 is one octave.	 */	pitch = ((note - 60) << 7) * voice->sound->key_scaling / 100 + (60 << 7);	pitch += voice->sound->pitch_offset;	if (!chan->drum_channel)		pitch += chan->gm_rpn_coarse_tuning;	pitch += chan->gm_rpn_fine_tuning >> 7;	pitch += chan->midi_pitchbend * chan->gm_rpn_pitch_bend_range / 0x2000;	if (pitch < 0)		pitch = 0;	else if (pitch >= 0x6000)		pitch = 0x5fff;	octave = pitch / 0x600 - 8;	pitch = snd_opl4_pitch_map[pitch % 0x600];	snd_opl4_write(opl4, OPL4_REG_OCTAVE + voice->number,		       (octave << 4) | ((pitch >> 7) & OPL4_F_NUMBER_HIGH_MASK));	voice->reg_f_number = (voice->reg_f_number & OPL4_TONE_NUMBER_BIT8)		| ((pitch << 1) & OPL4_F_NUMBER_LOW_MASK);	snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice->number, voice->reg_f_number);}static void snd_opl4_update_tone_parameters(opl4_t *opl4, opl4_voice_t *voice){	snd_opl4_write(opl4, OPL4_REG_ATTACK_DECAY1 + voice->number,		       voice->sound->reg_attack_decay1);	snd_opl4_write(opl4, OPL4_REG_LEVEL_DECAY2 + voice->number,		       voice->sound->reg_level_decay2);	snd_opl4_write(opl4, OPL4_REG_RELEASE_CORRECTION + voice->number,		       voice->sound->reg_release_correction);	snd_opl4_write(opl4, OPL4_REG_TREMOLO + voice->number,		       voice->sound->reg_tremolo);}/* allocate one voice */static opl4_voice_t *snd_opl4_get_voice(opl4_t *opl4){	/* first, try to get the oldest key-off voice */	if (!list_empty(&opl4->off_voices))		return list_entry(opl4->off_voices.next, opl4_voice_t, list);	/* then get the oldest key-on voice */	snd_assert(!list_empty(&opl4->on_voices), );	return list_entry(opl4->on_voices.next, opl4_voice_t, list);}static void snd_opl4_wait_for_wave_headers(opl4_t *opl4){	int timeout = 200;	while ((inb(opl4->fm_port) & OPL4_STATUS_LOAD) && --timeout > 0)		udelay(10);}void snd_opl4_note_on(void *private_data, int note, int vel, snd_midi_channel_t *chan){	opl4_t *opl4 = private_data;	const opl4_region_ptr_t *regions;	opl4_voice_t *voice[2];	const opl4_sound_t *sound[2];	int voices = 0, i;	unsigned long flags;	/* determine the number of voices and voice parameters */	i = chan->drum_channel ? 0x80 : (chan->midi_program & 0x7f);	regions = &snd_yrw801_regions[i];	for (i = 0; i < regions->count; i++) {		if (note >= regions->regions[i].key_min &&		    note <= regions->regions[i].key_max) {			sound[voices] = &regions->regions[i].sound;			if (++voices >= 2)				break;		}	}	/* allocate and initialize the needed voices */	spin_lock_irqsave(&opl4->reg_lock, flags);	for (i = 0; i < voices; i++) {		voice[i] = snd_opl4_get_voice(opl4);		list_del(&voice[i]->list);		list_add_tail(&voice[i]->list, &opl4->on_voices);		voice[i]->chan = chan;		voice[i]->note = note;		voice[i]->velocity = vel & 0x7f;		voice[i]->sound = sound[i];	}	/* set tone number (triggers header loading) */	for (i = 0; i < voices; i++) {		voice[i]->reg_f_number =			(sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8;		snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number,			       voice[i]->reg_f_number);		snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number,			       sound[i]->tone & 0xff);	}	/* set parameters which can be set while loading */	for (i = 0; i < voices; i++) {		voice[i]->reg_misc = OPL4_LFO_RESET_BIT;		snd_opl4_update_pan(opl4, voice[i]);		snd_opl4_update_pitch(opl4, voice[i]);		voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;		snd_opl4_update_volume(opl4, voice[i]);	}	spin_unlock_irqrestore(&opl4->reg_lock, flags);	/* wait for completion of loading */	snd_opl4_wait_for_wave_headers(opl4);	/* set remaining parameters */	spin_lock_irqsave(&opl4->reg_lock, flags);	for (i = 0; i < voices; i++) {		snd_opl4_update_tone_parameters(opl4, voice[i]);		voice[i]->reg_lfo_vibrato = voice[i]->sound->reg_lfo_vibrato;		snd_opl4_update_vibrato_depth(opl4, voice[i]);	}	/* finally, switch on all voices */	for (i = 0; i < voices; i++) {		voice[i]->reg_misc =			(voice[i]->reg_misc & 0x1f) | OPL4_KEY_ON_BIT;		snd_opl4_write(opl4, OPL4_REG_MISC + voice[i]->number,			       voice[i]->reg_misc);	}	spin_unlock_irqrestore(&opl4->reg_lock, flags);}static void snd_opl4_voice_off(opl4_t *opl4, opl4_voice_t *voice){	list_del(&voice->list);	list_add_tail(&voice->list, &opl4->off_voices);	voice->reg_misc &= ~OPL4_KEY_ON_BIT;	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);}void snd_opl4_note_off(void *private_data, int note, int vel, snd_midi_channel_t *chan){	opl4_t *opl4 = private_data;	snd_opl4_do_for_note(opl4, note, chan, snd_opl4_voice_off);}static void snd_opl4_terminate_voice(opl4_t *opl4, opl4_voice_t *voice){	list_del(&voice->list);	list_add_tail(&voice->list, &opl4->off_voices);	voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT;	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);}void snd_opl4_terminate_note(void *private_data, int note, snd_midi_channel_t *chan){	opl4_t *opl4 = private_data;	snd_opl4_do_for_note(opl4, note, chan, snd_opl4_terminate_voice);}void snd_opl4_control(void *private_data, int type, snd_midi_channel_t *chan){	opl4_t *opl4 = private_data;	switch (type) {	case MIDI_CTL_MSB_MODWHEEL:		chan->control[MIDI_CTL_VIBRATO_DEPTH] = chan->control[MIDI_CTL_MSB_MODWHEEL];		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth);		break;	case MIDI_CTL_MSB_MAIN_VOLUME:		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume);		break;	case MIDI_CTL_MSB_PAN:		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pan);		break;	case MIDI_CTL_MSB_EXPRESSION:		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume);		break;	case MIDI_CTL_VIBRATO_RATE:		/* not yet supported */		break;	case MIDI_CTL_VIBRATO_DEPTH:		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth);		break;	case MIDI_CTL_VIBRATO_DELAY:		/* not yet supported */		break;	case MIDI_CTL_E1_REVERB_DEPTH:		/*		 * Each OPL4 voice has a bit called "Pseudo-Reverb", but		 * IMHO _not_ using it enhances the listening experience.		 */		break;	case MIDI_CTL_PITCHBEND:		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pitch);		break;	}}void snd_opl4_sysex(void *private_data, unsigned char *buf, int len,		    int parsed, snd_midi_channel_set_t *chset){	opl4_t *opl4 = private_data;	if (parsed == SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME)		snd_opl4_do_for_all(opl4, snd_opl4_update_volume);}

⌨️ 快捷键说明

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