?? 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 256
struct 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 1
int 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 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 silence here
*/
gus_poke (1, 0);
free_mem_ptr = 2;
free_sample = 0;
for (i = 0; i < MAX_PATCH; i++)
patch_table[i] = -1;
}
void
gus_delay (void)
{
int i;
for (i = 0; i < 7; i++)
INB (u_DRAMIO);
}
static void
gus_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 char
gus_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;
}
void
gus_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 char
gus_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 char
gus_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;
}
void
gus_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 short
gus_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;
}
void
gus_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 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 (nvoices < 14)
nvoices = 14;
if (nvoices > 32)
nvoices = 32;
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
* start
* or
* stop
* *
* voice
*/
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;
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)); /*
* Don't
* start
* or
* stop
* *
* ramping
*/
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,
samples[sample_no].mode & WAVE_16_BITS);
}
static void
gus_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 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;
}
static void
step_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 ();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -