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

📄 gus_wave.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*		printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/		return -EINVAL;	/* Patch not defined */	}	if (sample_ptrs[sample_no] == -1)	/* Sample not loaded */	{/*		printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/		return -EINVAL;	}	sample_map[voice] = sample_no;	patch_map[voice] = instr_no;	return 0;}static int guswave_kill_note(int dev, int voice, int note, int velocity){	unsigned long flags;	save_flags(flags);	cli();	/* voice_alloc->map[voice] = 0xffff; */	if (voices[voice].volume_irq_mode == VMODE_START_NOTE)	{		voices[voice].kill_pending = 1;		restore_flags(flags);	}	else	{		restore_flags(flags);		gus_voice_fade(voice);	}	return 0;}static void guswave_aftertouch(int dev, int voice, int pressure){}static void guswave_panning(int dev, int voice, int value){	if (voice >= 0 || voice < 32)		voices[voice].panning = value;}static void guswave_volume_method(int dev, int mode){	if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)		volume_method = mode;}static void compute_volume(int voice, int volume){	if (volume < 128)		voices[voice].midi_volume = volume;	switch (volume_method)	{		case VOL_METHOD_ADAGIO:			voices[voice].initial_volume =				gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol,					voices[voice].expression_vol,					voices[voice].patch_vol);			break;		case VOL_METHOD_LINEAR:	/* Totally ignores patch-volume and expression */			voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol);			break;		default:			voices[voice].initial_volume = volume_base +				(voices[voice].midi_volume * volume_scale);	}	if (voices[voice].initial_volume > 4030)		voices[voice].initial_volume = 4030;}static void compute_and_set_volume(int voice, int volume, int ramp_time){	int curr, target, rate;	unsigned long flags;	compute_volume(voice, volume);	voices[voice].current_volume = voices[voice].initial_volume;	save_flags(flags);	cli();	/*	 * CAUTION! Interrupts disabled. Enable them before returning	 */	gus_select_voice(voice);	curr = gus_read16(0x09) >> 4;	target = voices[voice].initial_volume;	if (ramp_time == INSTANT_RAMP)	{		gus_rampoff();		gus_voice_volume(target);		restore_flags(flags);		return;	}	if (ramp_time == FAST_RAMP)		rate = 63;	else		rate = 16;	gus_ramp_rate(0, rate);	if ((target - curr) / 64 == 0)	/* Close enough to target. */	{		gus_rampoff();		gus_voice_volume(target);		restore_flags(flags);		return;	}	if (target > curr)	{		if (target > (4095 - 65))			target = 4095 - 65;		gus_ramp_range(curr, target);		gus_rampon(0x00);	/* Ramp up, once, no IRQ */	}	else	{		if (target < 65)			target = 65;		gus_ramp_range(target, curr);		gus_rampon(0x40);	/* Ramp down, once, no irq */	}	restore_flags(flags);}static void dynamic_volume_change(int voice){	unsigned char status;	unsigned long flags;	save_flags(flags);	cli();	gus_select_voice(voice);	status = gus_read8(0x00);	/* Get voice status */	restore_flags(flags);	if (status & 0x03)		return;		/* Voice was not running */	if (!(voices[voice].mode & WAVE_ENVELOPES))	{		compute_and_set_volume(voice, voices[voice].midi_volume, 1);		return;	}		/*	 * Voice is running and has envelopes.	 */	save_flags(flags);	cli();	gus_select_voice(voice);	status = gus_read8(0x0d);	/* Ramping status */	restore_flags(flags);	if (status & 0x03)	/* Sustain phase? */	{		compute_and_set_volume(voice, voices[voice].midi_volume, 1);		return;	}	if (voices[voice].env_phase < 0)		return;	compute_volume(voice, voices[voice].midi_volume);}static void guswave_controller(int dev, int voice, int ctrl_num, int value){	unsigned long   flags;	unsigned long   freq;	if (voice < 0 || voice > 31)		return;	switch (ctrl_num)	{		case CTRL_PITCH_BENDER:			voices[voice].bender = value;			if (voices[voice].volume_irq_mode != VMODE_START_NOTE)			{				freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0);				voices[voice].current_freq = freq;				save_flags(flags);				cli();				gus_select_voice(voice);				gus_voice_freq(freq);				restore_flags(flags);			}			break;		case CTRL_PITCH_BENDER_RANGE:			voices[voice].bender_range = value;			break;		case CTL_EXPRESSION:			value /= 128;		case CTRL_EXPRESSION:			if (volume_method == VOL_METHOD_ADAGIO)			{				voices[voice].expression_vol = value;				if (voices[voice].volume_irq_mode != VMODE_START_NOTE)					dynamic_volume_change(voice);			}			break;		case CTL_PAN:			voices[voice].panning = (value * 2) - 128;			break;		case CTL_MAIN_VOLUME:			value = (value * 100) / 16383;		case CTRL_MAIN_VOLUME:			voices[voice].main_vol = value;			if (voices[voice].volume_irq_mode != VMODE_START_NOTE)				dynamic_volume_change(voice);			break;		default:			break;	}}static int guswave_start_note2(int dev, int voice, int note_num, int volume){	int sample, best_sample, best_delta, delta_freq;	int is16bits, samplep, patch, pan;	unsigned long   note_freq, base_note, freq, flags;	unsigned char   mode = 0;	if (voice < 0 || voice > 31)	{/*		printk("GUS: Invalid voice\n");*/		return -EINVAL;	}	if (note_num == 255)	{		if (voices[voice].mode & WAVE_ENVELOPES)		{			voices[voice].midi_volume = volume;			dynamic_volume_change(voice);			return 0;		}		compute_and_set_volume(voice, volume, 1);		return 0;	}	if ((patch = patch_map[voice]) == -1)		return -EINVAL;	if ((samplep = patch_table[patch]) == NOT_SAMPLE)	{		return -EINVAL;	}	note_freq = note_to_freq(note_num);	/*	 * Find a sample within a patch so that the note_freq is between low_note	 * and high_note.	 */	sample = -1;	best_sample = samplep;	best_delta = 1000000;	while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1)	{		delta_freq = note_freq - samples[samplep].base_note;		if (delta_freq < 0)			delta_freq = -delta_freq;		if (delta_freq < best_delta)		{			best_sample = samplep;			best_delta = delta_freq;		}		if (samples[samplep].low_note <= note_freq &&			note_freq <= samples[samplep].high_note)		{			sample = samplep;		}		else			samplep = samples[samplep].key;	/* Link to next sample */	  }	if (sample == -1)		sample = best_sample;	if (sample == -1)	{/*		printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/		return 0;	/* Should play default patch ??? */	}	is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;	voices[voice].mode = samples[sample].mode;	voices[voice].patch_vol = samples[sample].volume;	if (iw_mode)		gus_write8(0x15, 0x00);		/* RAM, Reset voice deactivate bit of SMSI */	if (voices[voice].mode & WAVE_ENVELOPES)	{		int i;		for (i = 0; i < 6; i++)		{			voices[voice].env_rate[i] = samples[sample].env_rate[i];			voices[voice].env_offset[i] = samples[sample].env_offset[i];		}	}	sample_map[voice] = sample;	if (voices[voice].fixed_pitch)	/* Fixed pitch */	{		  freq = samples[sample].base_freq;	}	else	{		base_note = samples[sample].base_note / 100;		note_freq /= 100;		freq = samples[sample].base_freq * note_freq / base_note;	}	voices[voice].orig_freq = freq;	/*	 * Since the pitch bender may have been set before playing the note, we	 * have to calculate the bending now.	 */	freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender,				voices[voice].bender_range, 0);	voices[voice].current_freq = freq;	pan = (samples[sample].panning + voices[voice].panning) / 32;	pan += 7;	if (pan < 0)		pan = 0;	if (pan > 15)		pan = 15;	if (samples[sample].mode & WAVE_16_BITS)	{		mode |= 0x04;	/* 16 bits */		if ((sample_ptrs[sample] / GUS_BANK_SIZE) !=			((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))				printk(KERN_ERR "GUS: Sample address error\n");	}	/*************************************************************************	 *    CAUTION!        Interrupts disabled. Don't return before enabling	 *************************************************************************/	save_flags(flags);	cli();	gus_select_voice(voice);	gus_voice_off();	gus_rampoff();	restore_flags(flags);	if (voices[voice].mode & WAVE_ENVELOPES)	{		compute_volume(voice, volume);		init_envelope(voice);	}	else	{		compute_and_set_volume(voice, volume, 0);	}	save_flags(flags);	cli();	gus_select_voice(voice);	if (samples[sample].mode & WAVE_LOOP_BACK)		gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -			voices[voice].offset_pending, 0, is16bits);	/* start=end */	else		gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits);	/* Sample start=begin */	if (samples[sample].mode & WAVE_LOOPING)	{		mode |= 0x08;		if (samples[sample].mode & WAVE_BIDIR_LOOP)			mode |= 0x10;		if (samples[sample].mode & WAVE_LOOP_BACK)		{			gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end -					   voices[voice].offset_pending,					   (samples[sample].fractions >> 4) & 0x0f, is16bits);			mode |= 0x40;		}		gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start,			samples[sample].fractions & 0x0f, is16bits);	/* Loop start location */		gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end,			(samples[sample].fractions >> 4) & 0x0f, is16bits);	/* Loop end location */	}	else	{		mode |= 0x20;	/* Loop IRQ at the end */		voices[voice].loop_irq_mode = LMODE_FINISH;	/* Ramp down at the end */		voices[voice].loop_irq_parm = 1;		gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits);	/* Loop start location */		gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1,			(samples[sample].fractions >> 4) & 0x0f, is16bits);	/* Loop end location */	}	gus_voice_freq(freq);	gus_voice_balance(pan);	gus_voice_on(mode);	restore_flags(flags);	return 0;}/* * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking * when the note playing on the voice is changed.  It uses volume * ramping. */static int guswave_start_note(int dev, int voice, int note_num, int volume){	long int flags;	int mode;	int ret_val = 0;	save_flags(flags);	cli();	if (note_num == 255)	{		if (voices[voice].volume_irq_mode == VMODE_START_NOTE)		{			voices[voice].volume_pending = volume;		}		else		{			ret_val = guswave_start_note2(dev, voice, note_num, volume);		}	}	else	{		gus_select_voice(voice);		mode = gus_read8(0x00);		if (mode & 0x20)			gus_write8(0x00, mode & 0xdf);	/* No interrupt! */		voices[voice].offset_pending = 0;		voices[voice].kill_pending = 0;		voices[voice].volume_irq_mode = 0;		voices[voice].loop_irq_mode = 0;		if (voices[voice].sample_pending >= 0)		{			restore_flags(flags);	/* Run temporarily with interrupts enabled */			guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending);			voices[voice].sample_pending = -1;			save_flags(flags);			cli();			gus_select_voice(voice);	/* Reselect the voice (just to be sure) */		}		if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065))		{			ret_val = guswave_start_note2(dev, voice, note_num, volume);		}		else		{			voices[voice].dev_pending = dev;			voices[voice].note_pending = note_num;			voices[voice].volume_pending = volume;			voices[voice].volume_irq_mode = VMODE_START_NOTE;			gus_rampoff();			gus_ramp_range(2000, 4065);			gus_ramp_rate(0, 63);	/* Fastest possible rate */			gus_rampon(0x20 | 0x40);	/* Ramp down, once, irq */		}	}	restore_flags(flags);	return ret_val;}static void guswave_reset(int dev){	int i;	for (i = 0; i < 32; i++)	{		gus_voice_init(i);		gus_voice_init2(i);	}}static int guswave_open(int dev, int mode){	int err;	if (gus_busy)		return -EBUSY;	voice_alloc->timestamp = 0;	if (gus_no_wave_dma) {		gus_no_dma = 1;	} else {		if ((err = DMAbuf_open_dma(gus_devnum)) < 0)		{			/* printk( "GUS: Loading samples without DMA\n"); */			gus_no_dma = 1;	/* Upload samples using PIO */		}		else			gus_no_dma = 0;	}	init_waitqueue_head(&dram_sleeper);	gus_busy = 1;	active_device = GUS_DEV_WAVE;	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */	gus_initialize();	gus_reset();	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */	return 0;}static void guswave_close(int dev){	gus_busy = 0;	active_device = 0;	gus_reset();	if (!gus_no_dma)		DMAbuf_close_dma(gus_devnum);}static int guswave_load_patch(int dev, int format, const char *addr,		   int offs, int count, int pmgr_flag){	struct patch_info patch;	int instr;	long sizeof_patch;	unsigned long blk_sz, blk_end, left, src_offs, target;	sizeof_patch = (long) &patch.data[0] - (long) &patch;	/* Header size */	if (format != GUS_PATCH)	{/*		printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/		return -EINVAL;	}	if (count < sizeof_patch)	{/*		  printk("GUS Error: Patch header too short\n");*/		  return -EINVAL;	}	count -= sizeof_patch;	if (free_sample >= MAX_SAMPLE)	{/*		  printk("GUS: Sample table full\n");*/		  return -ENOSPC;	}

⌨️ 快捷键说明

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