📄 gus_wave.c
字号:
/* * 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 + -