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

📄 gus_wave.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * sound/gus_wave.c * * Driver for the Gravis UltraSound wave table synth. * * Copyright by Hannu Savolainen 1993, 1994 * * 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 <i386/isa/sound/sound_config.h>#include <machine/ultrasound.h>#include <i386/isa/sound/gus_hw.h>static unsigned char gus_look8 __P((int reg));static unsigned short gus_read16 __P((int reg));static void gus_write_addr __P((int reg, unsigned long address, int is16bit));static void gus_write16 __P((int reg, unsigned int data));#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)#define MAX_SAMPLE	150#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;  };static struct voice_alloc_info *voice_alloc;extern int      gus_base;extern int      gus_irq, gus_dma;static long     gus_mem_size = 0;static long     free_mem_ptr = 0;static int	gus_busy[MAX_AUDIO_DEV], gus_dspnum=0;static int	gus_dma_read=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;int             gus_wave_volume = 60;static 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;/* * 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_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, 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;#if defined(__FreeBSD__)static char    *gus_copy_buf;#endifstatic 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);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);#define	INSTANT_RAMP		-1	/* Instant change. No 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 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] = -1;}voidgus_delay (void){  int             i;  for (i = 0; i < 7; i++)    INB (u_DRAMIO);}static voidgus_poke (long addr, unsigned char data){				/* Writes a byte to the DRAM */  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){				/* Reads a byte from the DRAM */  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){				/* Writes to an indirect register (8 bit) */  unsigned long   flags;  DISABLE_INTR (flags);  OUTB (reg, u_Command);  OUTB ((unsigned char) (data & 0xff), u_DataHi);  RESTORE_INTR (flags);}static unsigned chargus_read8 (int reg){				/* Reads from an indirect register (8 bit). Offset 0x80. */  unsigned long   flags;  unsigned char   val;  DISABLE_INTR (flags);  OUTB (reg | 0x80, u_Command);  val = INB (u_DataHi);  RESTORE_INTR (flags);  return val;}static unsigned chargus_look8 (int reg){				/* Reads from an indirect register (8 bit). No additional offset. */  unsigned long   flags;  unsigned char   val;  DISABLE_INTR (flags);  OUTB (reg, u_Command);  val = INB (u_DataHi);  RESTORE_INTR (flags);  return val;}static voidgus_write16 (int reg, unsigned int data){				/* Writes to an indirect register (16 bit) */  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);}static unsigned shortgus_read16 (int reg){				/* Reads from an indirect register (16 bit). Offset 0x80. */  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;}static voidgus_write_addr (int reg, unsigned long address, int is16bit){				/* Writes an 24 bit memory address */  unsigned long   hold_address;  unsigned long   flags;  DISABLE_INTR (flags);  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));  /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */  gus_delay ();  gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));  RESTORE_INTR (flags);}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;  voice_alloc->max_voice = 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 touch last two bits */  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));	/* Leave the last 2 bits alone */  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_voice_off ();  gus_write_addr (0x0a, 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_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;  long int        flags;  if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)    {      DISABLE_INTR (flags);      gus_select_voice (voice);      gus_rampoff ();      RESTORE_INTR (flags);      return;      /*       * Sustain phase begins. Continue envelope after receiving note off.       */    }  if (voices[voice].env_phase >= 5)    {				/* Envelope finished. Shoot the voice down */      gus_voice_init (voice);      return;    }  prev_vol = voices[voice].current_volume;  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];  DISABLE_INTR (flags);  gus_select_voice (voice);  gus_voice_volume (prev_vol);  gus_write8 (0x06, rate);	/* Ramping rate */  voices[voice].volume_irq_mode = VMODE_ENVELOPE;  if (((vol - prev_vol) / 64) == 0)	/* No significant volume change */    {      RESTORE_INTR (flags);      step_envelope (voice);	/* Continue the envelope on the next step */

⌨️ 快捷键说明

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