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

📄 gus_wave.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * sound/gus_wave.c * * Driver for the Gravis UltraSound wave table synth. * * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * * Thomas Sailer    : ioctl code reworked (vmalloc/vfree removed) * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX. * Bartlomiej Zolnierkiewicz : added some __init/__exit */ #include <linux/init.h> #include <linux/config.h>#define GUSPNP_AUTODETECT#include "sound_config.h"#include <linux/ultrasound.h>#include "gus.h"#include "gus_hw.h"#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))#define MAX_SAMPLE	150#define MAX_PATCH	256#define NOT_SAMPLE	0xffffstruct voice_info{	unsigned long   orig_freq;	unsigned long   current_freq;	unsigned long   mode;	int             fixed_pitch;	int             bender;	int             bender_range;	int             panning;	int             midi_volume;	unsigned int    initial_volume;	unsigned int    current_volume;	int             loop_irq_mode, loop_irq_parm;#define LMODE_FINISH		1#define LMODE_PCM		2#define LMODE_PCM_STOP		3	int             volume_irq_mode, volume_irq_parm;#define VMODE_HALT		1#define VMODE_ENVELOPE		2#define VMODE_START_NOTE	3	int             env_phase;	unsigned char   env_rate[6];	unsigned char   env_offset[6];	/*	 * Volume computation parameters for gus_adagio_vol()	 */	int		main_vol, expression_vol, patch_vol;	/* Variables for "Ultraclick" removal */	int             dev_pending, note_pending, volume_pending,	                sample_pending;	char            kill_pending;	long            offset_pending;};static struct voice_alloc_info *voice_alloc;static struct address_info *gus_hw_config;extern int      gus_base;extern int      gus_irq, gus_dma;extern int      gus_pnp_flag;extern int      gus_no_wave_dma;static int      gus_dma2 = -1;static int      dual_dma_mode = 0;static long     gus_mem_size = 0;static long     free_mem_ptr = 0;static int      gus_busy = 0;static int      gus_no_dma = 0;static int      nr_voices = 0;static int      gus_devnum = 0;static int      volume_base, volume_scale, volume_method;static int      gus_recmask = SOUND_MASK_MIC;static int      recording_active = 0;static int      only_read_access = 0;static int      only_8_bits = 0;int             iw_mode = 0;int             gus_wave_volume = 60;int             gus_pcm_volume = 80;int             have_gus_max = 0;static int      gus_line_vol = 100, gus_mic_vol = 0;static unsigned char mix_image = 0x00;int             gus_timer_enabled = 0;/* * Current version of this driver doesn't allow synth and PCM functions * at the same time. The active_device specifies the active driver */static int      active_device = 0;#define GUS_DEV_WAVE		1	/* Wave table synth */#define GUS_DEV_PCM_DONE	2	/* PCM device, transfer done */#define GUS_DEV_PCM_CONTINUE	3	/* PCM device, transfer done ch. 1/2 */static int      gus_audio_speed;static int      gus_audio_channels;static int      gus_audio_bits;static int      gus_audio_bsize;static char     bounce_buf[8 * 1024];	/* Must match value set to max_fragment */static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper);/* * Variables and buffers for PCM output */#define MAX_PCM_BUFFERS		(128*MAX_REALTIME_FACTOR)	/* Don't change */static int      pcm_bsize, pcm_nblk, pcm_banksize;static int      pcm_datasize[MAX_PCM_BUFFERS];static volatile int pcm_head, pcm_tail, pcm_qlen;static volatile int pcm_active;static volatile int dma_active;static int      pcm_opened = 0;static int      pcm_current_dev;static int      pcm_current_block;static unsigned long pcm_current_buf;static int      pcm_current_count;static int      pcm_current_intrflag;extern int     *gus_osp;static struct voice_info voices[32];static int      freq_div_table[] ={	44100,			/* 14 */	41160,			/* 15 */	38587,			/* 16 */	36317,			/* 17 */	34300,			/* 18 */	32494,			/* 19 */	30870,			/* 20 */	29400,			/* 21 */	28063,			/* 22 */	26843,			/* 23 */	25725,			/* 24 */	24696,			/* 25 */	23746,			/* 26 */	22866,			/* 27 */	22050,			/* 28 */	21289,			/* 29 */	20580,			/* 30 */	19916,			/* 31 */	19293			/* 32 */};static struct patch_info *samples = NULL;static long     sample_ptrs[MAX_SAMPLE + 1];static int      sample_map[32];static int      free_sample;static int      mixer_type = 0;static int      patch_table[MAX_PATCH];static int      patch_map[32];static struct synth_info gus_info = {	"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 	0, 16, 0, MAX_PATCH};static void     gus_poke(long addr, unsigned char data);static void     compute_and_set_volume(int voice, int volume, int ramp_time);extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);extern unsigned short gus_linear_vol(int vol, int mainvol);static void     compute_volume(int voice, int volume);static void     do_volume_irq(int voice);static void     set_input_volumes(void);static void     gus_tmr_install(int io_base);#define	INSTANT_RAMP		-1	/* Instant change. No ramping */#define FAST_RAMP		0	/* Fastest possible ramp */static void reset_sample_memory(void){	int i;	for (i = 0; i <= MAX_SAMPLE; i++)		sample_ptrs[i] = -1;	for (i = 0; i < 32; i++)		sample_map[i] = -1;	for (i = 0; i < 32; i++)		patch_map[i] = -1;	gus_poke(0, 0);		/* Put a silent sample to the beginning */	gus_poke(1, 0);	free_mem_ptr = 2;	free_sample = 0;	for (i = 0; i < MAX_PATCH; i++)		patch_table[i] = NOT_SAMPLE;}void gus_delay(void){	int i;	for (i = 0; i < 7; i++)		inb(u_DRAMIO);}static void gus_poke(long addr, unsigned char data){				/* Writes a byte to the DRAM */	unsigned long   flags;	save_flags(flags);	cli();	outb((0x43), u_Command);	outb((addr & 0xff), u_DataLo);	outb(((addr >> 8) & 0xff), u_DataHi);	outb((0x44), u_Command);	outb(((addr >> 16) & 0xff), u_DataHi);	outb((data), u_DRAMIO);	restore_flags(flags);}static unsigned char gus_peek(long addr){				/* Reads a byte from the DRAM */	unsigned long   flags;	unsigned char   tmp;	save_flags(flags);	cli();	outb((0x43), u_Command);	outb((addr & 0xff), u_DataLo);	outb(((addr >> 8) & 0xff), u_DataHi);	outb((0x44), u_Command);	outb(((addr >> 16) & 0xff), u_DataHi);	tmp = inb(u_DRAMIO);	restore_flags(flags);	return tmp;}void gus_write8(int reg, unsigned int data){				/* Writes to an indirect register (8 bit) */	unsigned long   flags;	save_flags(flags);	cli();	outb((reg), u_Command);	outb(((unsigned char) (data & 0xff)), u_DataHi);	restore_flags(flags);}static unsigned char gus_read8(int reg){					/* Reads from an indirect register (8 bit). Offset 0x80. */	unsigned long   flags;	unsigned char   val;	save_flags(flags);	cli();	outb((reg | 0x80), u_Command);	val = inb(u_DataHi);	restore_flags(flags);	return val;}static unsigned char gus_look8(int reg){	/* Reads from an indirect register (8 bit). No additional offset. */	unsigned long   flags;	unsigned char   val;	save_flags(flags);	cli();	outb((reg), u_Command);	val = inb(u_DataHi);	restore_flags(flags);	return val;}static void gus_write16(int reg, unsigned int data){	/* Writes to an indirect register (16 bit) */	unsigned long   flags;	save_flags(flags);	cli();	outb((reg), u_Command);	outb(((unsigned char) (data & 0xff)), u_DataLo);	outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi);	restore_flags(flags);}static unsigned short gus_read16(int reg){	/* Reads from an indirect register (16 bit). Offset 0x80. */	unsigned long   flags;	unsigned char   hi, lo;	save_flags(flags);	cli();	outb((reg | 0x80), u_Command);	lo = inb(u_DataLo);	hi = inb(u_DataHi);	restore_flags(flags);	return ((hi << 8) & 0xff00) | lo;}static unsigned short gus_look16(int reg){			/* Reads from an indirect register (16 bit). No additional offset. */	unsigned long   flags;	unsigned char   hi, lo;	save_flags(flags);	cli();	outb((reg), u_Command);	lo = inb(u_DataLo);	hi = inb(u_DataHi);	restore_flags(flags);	return ((hi << 8) & 0xff00) | lo;}static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit){	/* Writes an 24 bit memory address */	unsigned long   hold_address;	unsigned long   flags;	save_flags(flags);	cli();	if (is16bit)	{		if (iw_mode)		{			/* Interwave spesific address translations */			address >>= 1;		}		else		{			/*			 * Special processing required for 16 bit patches			 */			hold_address = address;			address = address >> 1;			address &= 0x0001ffffL;			address |= (hold_address & 0x000c0000L);		}	}	gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));	gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)		    + (frac << 5));	/* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */	gus_delay();	gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));	gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)		    + (frac << 5));	restore_flags(flags);}static void gus_select_voice(int voice){	if (voice < 0 || voice > 31)		return;	outb((voice), u_Voice);}static void gus_select_max_voices(int nvoices){	if (iw_mode)		nvoices = 32;	if (nvoices < 14)		nvoices = 14;	if (nvoices > 32)		nvoices = 32;	voice_alloc->max_voice = nr_voices = nvoices;	gus_write8(0x0e, (nvoices - 1) | 0xc0);}static void gus_voice_on(unsigned int mode){	gus_write8(0x00, (unsigned char) (mode & 0xfc));	gus_delay();	gus_write8(0x00, (unsigned char) (mode & 0xfc));}static void gus_voice_off(void){	gus_write8(0x00, gus_read8(0x00) | 0x03);}static void gus_voice_mode(unsigned int m){	unsigned char   mode = (unsigned char) (m & 0xff);	gus_write8(0x00, (gus_read8(0x00) & 0x03) |		   (mode & 0xfc));	/* Don't touch last two bits */	gus_delay();	gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc));}static void gus_voice_freq(unsigned long freq){	unsigned long   divisor = freq_div_table[nr_voices - 14];	unsigned short  fc;	/* Interwave plays at 44100 Hz with any number of voices */	if (iw_mode)		fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100);	else		fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);	fc = fc << 1;	gus_write16(0x01, fc);}static void gus_voice_volume(unsigned int vol){	gus_write8(0x0d, 0x03);	/* Stop ramp before setting volume */	gus_write16(0x09, (unsigned short) (vol << 4));}static void gus_voice_balance(unsigned int balance){	gus_write8(0x0c, (unsigned char) (balance & 0xff));}static void gus_ramp_range(unsigned int low, unsigned int high){	gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff));	gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff));}static void gus_ramp_rate(unsigned int scale, unsigned int rate){	gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));}static void gus_rampon(unsigned int m){	unsigned char   mode = (unsigned char) (m & 0xff);	gus_write8(0x0d, mode & 0xfc);	gus_delay();	gus_write8(0x0d, mode & 0xfc);}static void gus_ramp_mode(unsigned int m){	unsigned char mode = (unsigned char) (m & 0xff);	gus_write8(0x0d, (gus_read8(0x0d) & 0x03) |		   (mode & 0xfc));	/* Leave the last 2 bits alone */	gus_delay();	gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc));}static void gus_rampoff(void){	gus_write8(0x0d, 0x03);}static void gus_set_voice_pos(int voice, long position){	int sample_no;	if ((sample_no = sample_map[voice]) != -1) {		if (position < samples[sample_no].len) {			if (voices[voice].volume_irq_mode == VMODE_START_NOTE)				voices[voice].offset_pending = position;			else				gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0,				 samples[sample_no].mode & WAVE_16_BITS);		}	}}static void gus_voice_init(int voice){	unsigned long   flags;	save_flags(flags);	cli();	gus_select_voice(voice);	gus_voice_volume(0);	gus_voice_off();	gus_write_addr(0x0a, 0, 0, 0);	/* Set current position to 0 */	gus_write8(0x00, 0x03);	/* Voice off */	gus_write8(0x0d, 0x03);	/* Ramping off */	voice_alloc->map[voice] = 0;	voice_alloc->alloc_times[voice] = 0;	restore_flags(flags);}static void gus_voice_init2(int voice){	voices[voice].panning = 0;	voices[voice].mode = 0;	voices[voice].orig_freq = 20000;	voices[voice].current_freq = 20000;	voices[voice].bender = 0;	voices[voice].bender_range = 200;	voices[voice].initial_volume = 0;	voices[voice].current_volume = 0;	voices[voice].loop_irq_mode = 0;	voices[voice].loop_irq_parm = 0;	voices[voice].volume_irq_mode = 0;	voices[voice].volume_irq_parm = 0;	voices[voice].env_phase = 0;	voices[voice].main_vol = 127;	voices[voice].patch_vol = 127;	voices[voice].expression_vol = 127;	voices[voice].sample_pending = -1;	voices[voice].fixed_pitch = 0;}static void step_envelope(int voice){	unsigned        vol, prev_vol, phase;	unsigned char   rate;	long int        flags;	if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)	{		save_flags(flags);		cli();		gus_select_voice(voice);		gus_rampoff();		restore_flags(flags);		return;		/*		 * Sustain phase begins. Continue envelope after receiving note off.		 */	}	if (voices[voice].env_phase >= 5)	{

⌨️ 快捷键说明

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