📄 gus_wave.c
字号:
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
*/
voices[voice].volume_irq_mode = VMODE_ENVELOPE;
if (((vol - prev_vol) / 64) == 0) /*
* No significant volume change
*/
{
step_envelope (voice); /*
* Continue with the next phase
*/
return;
}
if (vol > prev_vol)
{
if (vol >= (4096 - 64))
vol = 4096 - 65;
gus_ramp_range (0, vol);
gus_rampon (0x20); /*
* Increasing, irq
*/
}
else
{
if (vol <= 64)
vol = 65;
gus_ramp_range (vol, 4030);
gus_rampon (0x60); /*
* Decreasing, irq
*/
}
voices[voice].current_volume = vol;
}
static void
init_envelope (int voice)
{
voices[voice].env_phase = -1;
voices[voice].current_volume = 64;
step_envelope (voice);
}
static void
start_release (int voice)
{
if (gus_read8 (0x00) & 0x03)
return; /*
* Voice already stopped
*/
voices[voice].env_phase = 2; /*
* Will be incremented by step_envelope
*/
voices[voice].current_volume =
voices[voice].initial_volume =
gus_read16 (0x09) >> 4; /*
* Get current volume
*/
voices[voice].mode &= ~WAVE_SUSTAIN_ON;
gus_rampoff ();
step_envelope (voice);
}
static void
gus_voice_fade (int voice)
{
int instr_no = sample_map[voice], is16bits;
if (instr_no < 0 || instr_no > MAX_SAMPLE)
{
gus_write8 (0x00, 0x03); /*
* Hard stop
*/
return;
}
is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /*
* 8 or 16
* bit
* samples
*/
if (voices[voice].mode & WAVE_ENVELOPES)
{
start_release (voice);
return;
}
/*
* Ramp the volume down but not too quickly.
*/
if ((gus_read16 (0x09) >> 4) < 100) /*
* Get current volume
*/
{
gus_voice_off ();
gus_rampoff ();
gus_voice_init (voice);
return;
}
gus_ramp_range (65, 4030);
gus_ramp_rate (2, 4);
gus_rampon (0x40 | 0x20); /*
* Down, once, irq
*/
voices[voice].volume_irq_mode = VMODE_HALT;
}
static void
gus_reset (void)
{
int i;
gus_select_max_voices (24);
volume_base = 3071;
volume_scale = 4;
volume_method = VOL_METHOD_ADAGIO;
for (i = 0; i < 32; i++)
{
gus_voice_init (i); /*
* Turn voice off
*/
gus_voice_init2 (i);
}
INB (u_Status); /*
* Touch the status register
*/
gus_look8 (0x41); /*
* Clear any pending DMA IRQs
*/
gus_look8 (0x49); /*
* Clear any pending sample IRQs
*/
gus_read8 (0x0f); /*
* Clear pending IRQs
*/
}
static void
gus_initialize (void)
{
unsigned long flags;
unsigned char dma_image, irq_image, tmp;
static unsigned char gus_irq_map[16] =
{0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
static unsigned char gus_dma_map[8] =
{0, 1, 0, 2, 0, 3, 4, 5};
DISABLE_INTR (flags);
gus_write8 (0x4c, 0); /*
* Reset GF1
*/
gus_delay ();
gus_delay ();
gus_write8 (0x4c, 1); /*
* Release Reset
*/
gus_delay ();
gus_delay ();
/*
* Clear all interrupts
*/
gus_write8 (0x41, 0); /*
* DMA control
*/
gus_write8 (0x45, 0); /*
* Timer control
*/
gus_write8 (0x49, 0); /*
* Sample control
*/
gus_select_max_voices (24);
INB (u_Status); /*
* Touch the status register
*/
gus_look8 (0x41); /*
* Clear any pending DMA IRQs
*/
gus_look8 (0x49); /*
* Clear any pending sample IRQs
*/
gus_read8 (0x0f); /*
* Clear pending IRQs
*/
gus_reset (); /*
* Resets all voices
*/
gus_look8 (0x41); /*
* Clear any pending DMA IRQs
*/
gus_look8 (0x49); /*
* Clear any pending sample IRQs
*/
gus_read8 (0x0f); /*
* Clear pending IRQs
*/
gus_write8 (0x4c, 7); /*
* Master reset | DAC enable | IRQ enable
*/
/*
* Set up for Digital ASIC
*/
OUTB (0x05, gus_base + 0x0f);
mix_image |= 0x02; /*
* Disable line out
*/
OUTB (mix_image, u_Mixer);
OUTB (0x00, u_IRQDMAControl);
OUTB (0x00, gus_base + 0x0f);
/*
* Now set up the DMA and IRQ interface
*
* The GUS supports two IRQs and two DMAs.
*
* Just one DMA channel is used. This prevents simultaneous ADC and DAC.
* Adding this support requires significant changes to the dmabuf.c, dsp.c
* and audio.c also.
*/
irq_image = 0;
tmp = gus_irq_map[gus_irq];
if (!tmp)
printk ("Warning! GUS IRQ not selected\n");
irq_image |= tmp;
irq_image |= 0x40; /*
* Combine IRQ1 (GF1) and IRQ2 (Midi)
*/
dma_image = 0x40; /*
* Combine DMA1 (DRAM) and IRQ2 (ADC)
*/
tmp = gus_dma_map[gus_dma];
if (!tmp)
printk ("Warning! GUS DMA not selected\n");
dma_image |= tmp;
/*
* For some reason the IRQ and DMA addresses must be written twice
*/
/*
* Doing it first time
*/
OUTB (mix_image, u_Mixer); /*
* Select DMA control
*/
OUTB (dma_image | 0x80, u_IRQDMAControl); /*
* Set DMA address
*/
OUTB (mix_image | 0x40, u_Mixer); /*
* Select IRQ control
*/
OUTB (irq_image, u_IRQDMAControl); /*
* Set IRQ address
*/
/*
* Doing it second time
*/
OUTB (mix_image, u_Mixer); /*
* Select DMA control
*/
OUTB (dma_image, u_IRQDMAControl); /*
* Set DMA address
*/
OUTB (mix_image | 0x40, u_Mixer); /*
* Select IRQ control
*/
OUTB (irq_image, u_IRQDMAControl); /*
* Set IRQ address
*/
gus_select_voice (0); /*
* This disables writes to IRQ/DMA reg
*/
mix_image &= ~0x02; /*
* Enable line out
*/
mix_image |= 0x08; /*
* Enable IRQ
*/
OUTB (mix_image, u_Mixer); /*
* Turn mixer channels on
* Note! Mic in is left off.
*/
gus_select_voice (0); /*
* This disables writes to IRQ/DMA reg
*/
gusintr (0); /*
* Serve pending interrupts
*/
RESTORE_INTR (flags);
}
int
gus_wave_detect (int baseaddr)
{
unsigned long i;
unsigned long loc;
gus_base = baseaddr;
gus_write8 (0x4c, 0); /* Reset GF1 */
gus_delay ();
gus_delay ();
gus_write8 (0x4c, 1); /* Release Reset */
gus_delay ();
gus_delay ();
/* See if there is first block there.... */
gus_poke (0L, 0xaa);
if (gus_peek (0L) != 0xaa)
return (0);
/* Now zero it out so that I can check for mirroring .. */
gus_poke (0L, 0x00);
for (i = 1L; i < 1024L; i++)
{
int n, failed;
/* check for mirroring ... */
if (gus_peek (0L) != 0)
break;
loc = i << 10;
for (n = loc - 1, failed = 0; n <= loc; n++)
{
gus_poke (loc, 0xaa);
if (gus_peek (loc) != 0xaa)
failed = 1;
gus_poke (loc, 0x55);
if (gus_peek (loc) != 0x55)
failed = 1;
}
if (failed)
break;
}
gus_mem_size = i << 10;
return 1;
}
static int
guswave_ioctl (int dev,
unsigned int cmd, unsigned int arg)
{
switch (cmd)
{
case SNDCTL_SYNTH_INFO:
gus_info.nr_voices = nr_voices;
IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info));
return 0;
break;
case SNDCTL_SEQ_RESETSAMPLES:
reset_sample_memory ();
return 0;
break;
case SNDCTL_SEQ_PERCMODE:
return 0;
break;
case SNDCTL_SYNTH_MEMAVL:
return gus_mem_size - free_mem_ptr - 32;
default:
return RET_ERROR (EINVAL);
}
}
static int
guswave_set_instr (int dev, int voice, int instr_no)
{
int sample_no;
if (instr_no < 0 || instr_no > MAX_PATCH)
return RET_ERROR (EINVAL);
if (voice < 0 || voice > 31)
return RET_ERROR (EINVAL);
if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
{
voices[voice].sample_pending = instr_no;
return 0;
}
sample_no = patch_table[instr_no];
patch_map[voice] = -1;
if (sample_no < 0)
{
printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
return RET_ERROR (EINVAL); /*
* Patch not defined
*/
}
if (sample_ptrs[sample_no] == -1) /*
* Sample not loaded
*/
{
printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);
return RET_ERROR (EINVAL);
}
sample_map[voice] = sample_no;
patch_map[voice] = instr_no;
return 0;
}
static int
#ifdef FUTURE_VERSION
guswave_kill_note (int dev, int voice, int note, int velocity)
#else
guswave_kill_note (int dev, int voice, int velocity)
#endif
{
unsigned long flags;
DISABLE_INTR (flags);
if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
voices[voice].kill_pending = 1;
else
{
gus_select_voice (voice);
gus_voice_fade (voice);
}
RESTORE_INTR (flags);
return 0;
}
static void
guswave_aftertouch (int dev, int voice, int pressure)
{
short lo_limit, hi_limit;
unsigned long flags;
return; /*
* Currently disabled
*/
if (voice < 0 || voice > 31)
return;
if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
return; /*
* Don't mix with envelopes
*/
if (pressure < 32)
{
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_rampoff ();
compute_and_set_volume (voice, 255, 0); /*
* Back to original volume
*/
RESTORE_INTR (flags);
return;
}
hi_limit = voices[voice].current_volume;
lo_limit = hi_limit * 99 / 100;
if (lo_limit < 65)
lo_limit = 65;
DISABLE_INTR (flags);
gus_select_voice (voice);
if (hi_limit > (4095 - 65))
{
hi_limit = 4095 - 65;
gus_voice_volume (hi_limit);
}
gus_ramp_range (lo_limit, hi_limit);
gus_ramp_rate (3, 8);
gus_rampon (0x58); /*
* Bidirectional, Down, Loop
*/
RESTORE_INTR (flags);
}
static void
guswave_panning (int dev, int voice, int value)
{
if (voice >= 0 || voice < 32)
voices[voice].panning = value;
}
static void
compute_volume (int voice, int volume)
{
if (volume < 128)
voices[voice].midi_volume = volume;
switch (volume_method)
{
case VOL_METHOD_ADAGIO:
voices[voice].initial_volume =
gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
voices[voice].expression_vol,
voices[voice].patch_vol);
break;
default:
voices[voice].initial_volume = volume_base +
(voices[voice].midi_volume * volume_scale);
}
if (voices[voice].initial_volume > 4030)
voices[voice].initial_volume = 4030;
}
static void
compute_and_set_volume (int voice, int volume, int ramp_time)
{
int current, target, rate;
unsigned long flags;
DISABLE_INTR (flags);
/*
* CAUTION! Interrupts disabled. Enable them before returning
*/
gus_select_voice (voice);
compute_volume (voice, volume);
voices[voice].current_volume = voices[voice].initial_volume;
current = gus_read16 (0x09) >> 4;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -