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

📄 gus_wave.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  * sound/gus_wave.c *  * Driver for the Gravis UltraSound wave table synth. *  * Copyright by Hannu Savolainen 1993 *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. *  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *  */#include "sound_config.h"#include <linux/ultrasound.h>#include "gus_hw.h"#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)#define MAX_SAMPLE	128#define MAX_PATCH	256struct voice_info  {    unsigned long   orig_freq;    unsigned long   current_freq;    unsigned long   mode;    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;  };extern int      gus_base;extern int      gus_irq, gus_dma;extern char    *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];extern int      snd_raw_count[MAX_DSP_DEV];static long     gus_mem_size = 0;static long     free_mem_ptr = 0;static int      gus_busy = 0;static int      nr_voices = 0;static int      gus_devnum = 0;static int      volume_base, volume_scale, volume_method;static int	gus_line_vol = 100, gus_mic_vol = 0;static int	gus_recmask = SOUND_MASK_MIC;static int	recording_active = 0;#define VOL_METHOD_ADAGIO	1int             gus_wave_volume = 60;int             gus_pcm_volume = 80;static unsigned char mix_image = 0x00;/*  * 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 the					 * second * * * chn   */static int      gus_sampling_speed;static int      gus_sampling_channels;static int      gus_sampling_bits;DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);/*  * Variables and buffers for PCM output */#define MAX_PCM_BUFFERS		(32*MAX_REALTIME_FACTOR)	/* 								 * * * Don't								 * * * change 								 * 								 */static int      pcm_bsize,	/* 				 * Current blocksize 				 */                pcm_nblk,	/* 				 * Current # of blocks 				 */                pcm_banksize;	/* 				 * 				 * *  * * # bytes allocated for channels   */static int      pcm_datasize[MAX_PCM_BUFFERS];	/* 						 * 						 * *  * * Actual # of bytes						 * in blk  *  */static volatile int pcm_head, pcm_tail, pcm_qlen;	/* 							 * 							 * *  * * DRAM queue							 *  */static volatile int pcm_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;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;static long     sample_ptrs[MAX_SAMPLE + 1];static int      sample_map[32];static int      free_sample;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);static void     compute_volume (int voice, int volume);static void     do_volume_irq (int voice);static void	set_input_volumes(void);#define	INSTANT_RAMP		-1	/* 					 * * * Dont use ramping   */#define FAST_RAMP		0	/* 					 * * * Fastest possible ramp   */static voidreset_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 silence here 				 */  gus_poke (1, 0);  free_mem_ptr = 2;  free_sample = 0;  for (i = 0; i < MAX_PATCH; i++)    patch_table[i] = -1;}voidgus_delay (void){  int             i;  for (i = 0; i < 7; i++)    INB (u_DRAMIO);}static voidgus_poke (long addr, unsigned char data){  unsigned long   flags;  DISABLE_INTR (flags);  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_INTR (flags);}static unsigned chargus_peek (long addr){  unsigned long   flags;  unsigned char   tmp;  DISABLE_INTR (flags);  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_INTR (flags);  return tmp;}voidgus_write8 (int reg, unsigned int data){  unsigned long   flags;  DISABLE_INTR (flags);  OUTB (reg, u_Command);  OUTB ((unsigned char) (data & 0xff), u_DataHi);  RESTORE_INTR (flags);}unsigned chargus_read8 (int reg){  unsigned long   flags;  unsigned char   val;  DISABLE_INTR (flags);  OUTB (reg | 0x80, u_Command);  val = INB (u_DataHi);  RESTORE_INTR (flags);  return val;}unsigned chargus_look8 (int reg){  unsigned long   flags;  unsigned char   val;  DISABLE_INTR (flags);  OUTB (reg, u_Command);  val = INB (u_DataHi);  RESTORE_INTR (flags);  return val;}voidgus_write16 (int reg, unsigned int data){  unsigned long   flags;  DISABLE_INTR (flags);  OUTB (reg, u_Command);  OUTB ((unsigned char) (data & 0xff), u_DataLo);  OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);  RESTORE_INTR (flags);}unsigned shortgus_read16 (int reg){  unsigned long   flags;  unsigned char   hi, lo;  DISABLE_INTR (flags);  OUTB (reg | 0x80, u_Command);  lo = INB (u_DataLo);  hi = INB (u_DataHi);  RESTORE_INTR (flags);  return ((hi << 8) & 0xff00) | lo;}voidgus_write_addr (int reg, unsigned long address, int is16bit){  unsigned long   hold_address;  if (is16bit)    {      /*        * 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));}static voidgus_select_voice (int voice){  if (voice < 0 || voice > 31)    return;  OUTB (voice, u_Voice);}static voidgus_select_max_voices (int nvoices){  if (nvoices < 14)    nvoices = 14;  if (nvoices > 32)    nvoices = 32;  nr_voices = nvoices;  gus_write8 (0x0e, (nvoices - 1) | 0xc0);}static voidgus_voice_on (unsigned int mode){  gus_write8 (0x00, (unsigned char) (mode & 0xfc));  gus_delay ();  gus_write8 (0x00, (unsigned char) (mode & 0xfc));}static voidgus_voice_off (void){  gus_write8 (0x00, gus_read8 (0x00) | 0x03);}static voidgus_voice_mode (unsigned int m){  unsigned char   mode = (unsigned char) (m & 0xff);  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));		/* 									 * Don't 									 * start 									 * or 									 * stop									 * *									 * voice 									 */  gus_delay ();  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));}static voidgus_voice_freq (unsigned long freq){  unsigned long   divisor = freq_div_table[nr_voices - 14];  unsigned short  fc;  fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);  fc = fc << 1;  gus_write16 (0x01, fc);}static voidgus_voice_volume (unsigned int vol){  gus_write8 (0x0d, 0x03);	/* 				 * Stop ramp before setting volume 				 */  gus_write16 (0x09, (unsigned short) (vol << 4));}static voidgus_voice_balance (unsigned int balance){  gus_write8 (0x0c, (unsigned char) (balance & 0xff));}static voidgus_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 voidgus_ramp_rate (unsigned int scale, unsigned int rate){  gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));}static voidgus_rampon (unsigned int m){  unsigned char   mode = (unsigned char) (m & 0xff);  gus_write8 (0x0d, mode & 0xfc);  gus_delay ();  gus_write8 (0x0d, mode & 0xfc);}static voidgus_ramp_mode (unsigned int m){  unsigned char   mode = (unsigned char) (m & 0xff);  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));		/* 									 * Don't 									 * start 									 * or 									 * stop									 * *									 * ramping 									 */  gus_delay ();  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));}static voidgus_rampoff (void){  gus_write8 (0x0d, 0x03);}static voidgus_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,			samples[sample_no].mode & WAVE_16_BITS);}static voidgus_voice_init (int voice){  unsigned long   flags;  DISABLE_INTR (flags);  gus_select_voice (voice);  gus_voice_volume (0);  gus_write_addr (0x0a, 0, 0);	/* 				 * Set current position to 0 				 */  gus_write8 (0x00, 0x03);	/* 				 * Voice off 				 */  gus_write8 (0x0d, 0x03);	/* 				 * Ramping off 				 */  RESTORE_INTR (flags);}static voidgus_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;}static voidstep_envelope (int voice){  unsigned        vol, prev_vol, phase;  unsigned char   rate;  if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)    {      gus_rampoff ();      return;			/* 				 * Sustain 				 */    }  if (voices[voice].env_phase >= 5)    {      /*        * Shoot the voice off       */      gus_voice_init (voice);      return;    }  prev_vol = voices[voice].current_volume;  gus_voice_volume (prev_vol);  phase = ++voices[voice].env_phase;  compute_volume (voice, voices[voice].midi_volume);  vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;  rate = voices[voice].env_rate[phase];  gus_write8 (0x06, rate);	/* 				 * Ramping rate 

⌨️ 快捷键说明

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