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

📄 gus_lfo.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> *  Routines for control of LFO generators (tremolo & vibrato) for *  GF1/InterWave chips... * * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#include <sound/driver.h>#include <sound/core.h>#include <sound/gus.h>/* *  called by engine routines */static signed char snd_gf1_lfo_compute_value(snd_gus_card_t * gus,					     unsigned char *ptr){	unsigned int twaveinc, depth_delta;	signed int result;	unsigned short control, twave, depth, depth_final;	unsigned char *ptr1;	control = *(unsigned short *) (ptr + 0x00);	ptr1 = ptr + ((control & 0x4000) >> 12);	/* 1. add TWAVEINC to TWAVE and write the result back */	/* LFO update rate is 689Hz, effect timer is in ms */	if (gus->gf1.timer_slave)		twaveinc = (689 * gus->gf1.timer_master_gus->gf1.effect_timer) / 1000;	else		twaveinc = (689 * gus->gf1.effect_timer) / 1000;	if (!twaveinc)		twaveinc++;#if 0	printk("twaveinc = 0x%x, effect_timer = %i\n", twaveinc, gus->gf1.effect_timer);#endif	depth = *(unsigned short *) (ptr1 + 0x0a);	depth_final = *(unsigned char *) (ptr + 0x02) << 5;	if (depth != depth_final) {		depth_delta = ((twaveinc * *(ptr + 0x03)) + *(unsigned short *) (ptr + 0x04));		*(unsigned short *) (ptr + 0x04) = depth_delta % 8000;		depth_delta /= 8000;		if (depth < depth_final) {			if (depth + depth_delta > depth_final)				depth = depth_final;			else				depth += depth_delta;		}		if (depth > depth_final) {			if (depth - depth_delta < depth_final)				depth = depth_final;			else				depth -= depth_delta;		}		*(unsigned short *) (ptr1 + 0x0a) = depth;	}	twaveinc *= (unsigned int) control & 0x7ff;	twaveinc += *(unsigned short *) (ptr + 0x06);	*(unsigned short *) (ptr + 0x06) = twaveinc % 1000;	twave = *(unsigned short *) (ptr1 + 0x08);	twave += (unsigned short) (twaveinc / (unsigned int) 1000);	*(unsigned short *) (ptr1 + 0x08) = twave;	if (!(control & 0x2000)) {		/* 2. if shift is low */		if (twave & 0x4000) {	/* bit 14 high -> invert TWAVE 13-0 */			twave ^= 0x3fff;			twave &= ~0x4000;		}		/* TWAVE bit 15 is exclusive or'd with the invert bit (12) */		twave ^= (control & 0x1000) << 3;	} else {		/* 2. if shift is high */		if (twave & 0x8000)	/* bit 15 high -> invert TWAVE 14-0 */			twave ^= 0x7fff;		/* the invert bit (12) is used as sign bit */		if (control & 0x1000)			twave |= 0x8000;		else			twave &= ~0x8000;	}	/* 3. multiply the 14-bit LFO waveform magnitude by 13-bit DEPTH */#if 0	printk("c=0x%x,tw=0x%x,to=0x%x,d=0x%x,df=0x%x,di=0x%x,r=0x%x,r1=%i\n",	       control, twave,	       *(unsigned short *) (ptr1 + 0x08),	       depth, depth_final, *(ptr + 0x03),	     (twave & 0x7fff) * depth, ((twave & 0x7fff) * depth) >> 21);#endif	result = (twave & 0x7fff) * depth;	if (result) {		/* shift */		result >>= 21;		result &= 0x3f;	}	/* add sign */	if (twave & 0x8000)		result = -result;#if 0	printk("lfo final value = %i\n", result);#endif	return result;}static void snd_gf1_lfo_register_setup(snd_gus_card_t * gus,				       snd_gf1_voice_t * voice,				       int lfo_type){	unsigned long flags;	if (gus->gf1.enh_mode) {		CLI(&flags);		gf1_select_voice(gus, voice->number);		if (lfo_type & 1) {			snd_gf1_write8(gus, GF1_VB_FREQUENCY_LFO, voice->lfo_fc);			voice->lfo_fc = 0;		}		if (lfo_type & 2) {			snd_gf1_write8(gus, GF1_VB_VOLUME_LFO, voice->lfo_volume);			voice->lfo_volume = 0;		}		STI(&flags);	} else {		/*		 * ok.. with old GF1 chip can be only vibrato emulated...		 * volume register can be in volume ramp state, so tremolo isn't simple..		 */		if (!(lfo_type & 1))			return;#if 0		if (voice->lfo_fc)			printk("setup - %i = %i\n", voice->number, voice->lfo_fc);#endif		CLI(&flags);		gf1_select_voice(gus, voice->number);		snd_gf1_write16(gus, GF1_VW_FREQUENCY, voice->fc_register + voice->lfo_fc);		STI(&flags);	}}void snd_gf1_lfo_effect_interrupt(snd_gus_card_t * gus, snd_gf1_voice_t * voice){	unsigned char *ptr;#if 0	if (voice->number != 0)		return;#endif	ptr = gus->gf1.lfos + ((voice->number) << 5);	/* 1. vibrato */	if (*(unsigned short *) (ptr + 0x00) & 0x8000)		voice->lfo_fc = snd_gf1_lfo_compute_value(gus, ptr);	/* 2. tremolo */	ptr += 16;	if (*(unsigned short *) (ptr + 0x00) & 0x8000)		voice->lfo_volume = snd_gf1_lfo_compute_value(gus, ptr);	/* 3. register setup */	snd_gf1_lfo_register_setup(gus, voice, 3);}/* */void snd_gf1_lfo_init(snd_gus_card_t * gus){	if (gus->gf1.hw_lfo) {		snd_gf1_i_write16(gus, GF1_GW_LFO_BASE, 0x0000);		snd_gf1_dram_setmem(gus, 0, 0x0000, 1024);		/* now enable LFO */		snd_gf1_i_write8(gus, GF1_GB_GLOBAL_MODE, snd_gf1_i_look8(gus, GF1_GB_GLOBAL_MODE) | 0x02);	}	if (gus->gf1.sw_lfo) {#if 1		gus->gf1.lfos = snd_calloc(1024);		if (!gus->gf1.lfos)#endif			gus->gf1.sw_lfo = 0;	}}void snd_gf1_lfo_done(snd_gus_card_t * gus){	if (gus->gf1.sw_lfo) {		if (gus->gf1.lfos) {			snd_gf1_free(gus->gf1.lfos, 1024);			gus->gf1.lfos = NULL;		}	}}void snd_gf1_lfo_program(snd_gus_card_t * gus, int voice, int lfo_type,                         struct ULTRA_STRU_IW_LFO_PROGRAM *program){	unsigned int lfo_addr, wave_select;	wave_select = (program->freq_and_control & 0x4000) >> 12;	lfo_addr = (voice << 5) | (lfo_type << 4);	if (gus->gf1.hw_lfo) {#if 0		printk("LMCI = 0x%x\n", snd_gf1_i_look8(gus, 0x53));		printk("lfo_program: lfo_addr=0x%x,wave_sel=0x%x,fac=0x%x,df=0x%x,di=0x%x,twave=0x%x,depth=0x%x\n",		       lfo_addr, wave_select,		       program->freq_and_control,		       program->depth_final,		       program->depth_inc,		       program->twave,		       program->depth);#endif		snd_gf1_poke(gus, lfo_addr + 0x02, program->depth_final);		snd_gf1_poke(gus, lfo_addr + 0x03, program->depth_inc);		snd_gf1_pokew(gus, lfo_addr + 0x08 + wave_select, program->twave);		snd_gf1_pokew(gus, lfo_addr + 0x0a + wave_select, program->depth);		snd_gf1_pokew(gus, lfo_addr + 0x00, program->freq_and_control);#if 0		{			int i = 0;			for (i = 0; i < 16; i++)				printk("%02x:", snd_gf1_peek(gus, lfo_addr + i));			printk("\n");		}#endif	}	if (gus->gf1.sw_lfo) {		unsigned char *ptr = gus->gf1.lfos + lfo_addr;		*(ptr + 0x02) = program->depth_final;		*(ptr + 0x03) = program->depth_inc;		*(unsigned short *) (ptr + 0x08 + wave_select) = program->twave;		*(unsigned short *) (ptr + 0x0a + wave_select) = program->depth;		*(unsigned short *) (ptr + 0x00) = program->freq_and_control;	}}void snd_gf1_lfo_enable(snd_gus_card_t * gus, int voice, int lfo_type){	unsigned int lfo_addr;	lfo_addr = (voice << 5) | (lfo_type << 4);	if (gus->gf1.hw_lfo)		snd_gf1_pokew(gus, lfo_addr + 0x00, snd_gf1_peekw(gus, lfo_addr + 0x00) | 0x8000);	if (gus->gf1.sw_lfo) {		unsigned char *ptr = gus->gf1.lfos + lfo_addr;		*(unsigned short *) (ptr + 0x00) |= 0x8000;	}}void snd_gf1_lfo_disable(snd_gus_card_t * gus, int voice, int lfo_type){	unsigned int lfo_addr;	lfo_addr = (voice << 5) | (lfo_type << 4);	if (gus->gf1.hw_lfo)		snd_gf1_pokew(gus, lfo_addr + 0x00,				snd_gf1_peekw(gus, lfo_addr + 0x00) & ~0x8000);	if (gus->gf1.sw_lfo) {		unsigned char *ptr = gus->gf1.lfos + lfo_addr;		*(unsigned short *) (ptr + 0x00) &= ~0x8000;	}}void snd_gf1_lfo_change_freq(snd_gus_card_t * gus, int voice,		             int lfo_type, int freq){	unsigned int lfo_addr;	lfo_addr = (voice << 5) | (lfo_type << 4);	if (gus->gf1.hw_lfo)		snd_gf1_pokew(gus, lfo_addr + 0x00,				(snd_gf1_peekw(gus, lfo_addr + 0x00) & ~0x7ff) | (freq & 0x7ff));	if (gus->gf1.sw_lfo) {		unsigned long flags;		unsigned char *ptr = gus->gf1.lfos + lfo_addr;		CLI(&flags);		*(unsigned short *) (ptr + 0x00) &= ~0x7ff;		*(unsigned short *) (ptr + 0x00) |= freq & 0x7ff;		STI(&flags);	}}void snd_gf1_lfo_change_depth(snd_gus_card_t * gus, int voice,			      int lfo_type, int depth){	unsigned long flags;	unsigned int lfo_addr;	unsigned short control = 0;	unsigned char *ptr;	lfo_addr = (voice << 5) | (lfo_type << 4);	ptr = gus->gf1.lfos + lfo_addr;	if (gus->gf1.hw_lfo)		control = snd_gf1_peekw(gus, lfo_addr + 0x00);	if (gus->gf1.sw_lfo)		control = *(unsigned short *) (ptr + 0x00);	if (depth < 0) {		control |= 0x1000;		depth = -depth;	} else		control &= ~0x1000;	if (gus->gf1.hw_lfo) {		CLI(&flags);		snd_gf1_poke(gus, lfo_addr + 0x02, (unsigned char) depth);		snd_gf1_pokew(gus, lfo_addr + 0x0a + ((control & 0x4000) >> 12), depth << 5);		snd_gf1_pokew(gus, lfo_addr + 0x00, control);		STI(&flags);	}	if (gus->gf1.sw_lfo) {		unsigned char *ptr = gus->gf1.lfos + lfo_addr;		CLI(&flags);		*(ptr + 0x02) = (unsigned char) depth;		*(unsigned short *) (ptr + 0x0a + ((control & 0x4000) >> 12)) = depth << 5;		*(unsigned short *) (ptr + 0x00) = control;		STI(&flags);	}}void snd_gf1_lfo_setup(snd_gus_card_t * gus, int voice, int lfo_type,		       int freq, int current_depth, int depth, int sweep,		       int shape){	struct ULTRA_STRU_IW_LFO_PROGRAM program;	program.freq_and_control = 0x8000 | (freq & 0x7ff);	if (shape & ULTRA_STRU_IW_LFO_SHAPE_POSTRIANGLE)		program.freq_and_control |= 0x2000;	if (depth < 0) {		program.freq_and_control |= 0x1000;		depth = -depth;	}	program.twave = 0;	program.depth = current_depth;	program.depth_final = depth;	if (sweep) {		program.depth_inc = (unsigned char) (((int) ((depth << 5) - current_depth) << 9) / (sweep * 4410L));		if (!program.depth_inc)			program.depth_inc++;	} else		program.depth = (unsigned short) (depth << 5);	snd_gf1_lfo_program(gus, voice, lfo_type, &program);}void snd_gf1_lfo_shutdown(snd_gus_card_t * gus, int voice, int lfo_type){	unsigned long flags;	unsigned int lfo_addr;	lfo_addr = (voice << 5) | (lfo_type << 4);	if (gus->gf1.hw_lfo) {		snd_gf1_pokew(gus, lfo_addr + 0x00, 0x0000);		CLI(&flags);		gf1_select_voice(gus, voice);		snd_gf1_write8(gus, lfo_type == ULTRA_LFO_VIBRATO ? GF1_VB_FREQUENCY_LFO : GF1_VB_VOLUME_LFO, 0);		STI(&flags);	}	if (gus->gf1.sw_lfo) {		unsigned char *ptr = gus->gf1.lfos + lfo_addr;		snd_gf1_voice_t *pvoice;		*(unsigned short *) (ptr + 0x00) = 0;		*(unsigned short *) (ptr + 0x04) = 0;		*(unsigned short *) (ptr + 0x06) = 0;		if (gus->gf1.syn_voices) {			pvoice = gus->gf1.syn_voices + voice;			if (lfo_type == ULTRA_LFO_VIBRATO)				pvoice->lfo_fc = 0;			else				pvoice->lfo_volume = 0;			snd_gf1_lfo_register_setup(gus, pvoice, lfo_type == ULTRA_LFO_VIBRATO ? 1 : 2);		} else if (gus->gf1.enh_mode) {			CLI(&flags);			gf1_select_voice(gus, voice);			snd_gf1_write8(gus, lfo_type == ULTRA_LFO_VIBRATO ? GF1_VB_FREQUENCY_LFO : GF1_VB_VOLUME_LFO, 0);			STI(&flags);		}	}}void snd_gf1_lfo_command(snd_gus_card_t * gus, int voice, unsigned char *data){	int lfo_type;	int lfo_command;	int temp1, temp2;	lfo_type = *data >> 7;	lfo_command = *data & 0x7f;	switch (lfo_command) {	case ULTRA_LFO_SETUP:	/* setup */		temp1 = snd_gf1_get_word(data, 2);		temp2 = snd_gf1_get_word(data, 4);		snd_gf1_lfo_setup(gus, voice, lfo_type, temp1 & 0x7ff, 0, temp2 > 255 ? 255 : temp2, snd_gf1_get_byte(data, 1), (temp1 & 0x2000) >> 13);		break;	case ULTRA_LFO_FREQ:	/* freq */		snd_gf1_lfo_change_depth(gus, voice, lfo_type, snd_gf1_get_word(data, 2));		break;	case ULTRA_LFO_DEPTH:	/* depth */		snd_gf1_lfo_change_freq(gus, voice, lfo_type, snd_gf1_get_word(data, 2));		break;	case ULTRA_LFO_ENABLE:	/* enable */		snd_gf1_lfo_enable(gus, voice, lfo_type);		break;	case ULTRA_LFO_DISABLE:	/* disable */		snd_gf1_lfo_disable(gus, voice, lfo_type);		break;	case ULTRA_LFO_SHUTDOWN:	/* shutdown */		snd_gf1_lfo_shutdown(gus, voice, lfo_type);		break;	}}

⌨️ 快捷键说明

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