?? gus_wave.c
字號:
return RET_ERROR (ENOSPC);
free_mem_ptr = tmp_mem; /*
* This leaves unusable memory
*/
}
}
if ((free_mem_ptr + patch.len) > gus_mem_size)
return RET_ERROR (ENOSPC);
sample_ptrs[free_sample] = free_mem_ptr;
/*
* Tremolo is not possible with envelopes
*/
if (patch.mode & WAVE_ENVELOPES)
patch.mode &= ~WAVE_TREMOLO;
memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
/*
* Link this_one sample to the list of samples for patch 'instr'.
*/
samples[free_sample].key = patch_table[instr];
patch_table[instr] = free_sample;
/*
* Use DMA to transfer the wave data to the DRAM
*/
left = patch.len;
src_offs = 0;
target = free_mem_ptr;
while (left) /*
* Not all moved
*/
{
blk_size = sound_buffsizes[gus_devnum];
if (blk_size > left)
blk_size = left;
/*
* DMA cannot cross 256k bank boundaries. Check for that.
*/
blk_end = target + blk_size;
if ((target >> 18) != (blk_end >> 18))
{ /*
* Have to split the block
*/
blk_end &= ~(256 * 1024 - 1);
blk_size = blk_end - target;
}
#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
/*
* For some reason the DMA is not possible. We have to use PIO.
*/
{
long i;
unsigned char data;
for (i = 0; i < blk_size; i++)
{
GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
if (patch.mode & WAVE_UNSIGNED)
if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
data ^= 0x80; /*
* Convert to signed
*/
gus_poke (target + i, data);
}
}
#else /*
* * * GUS_NO_DMA */
{
unsigned long address, hold_address;
unsigned char dma_command;
unsigned long flags;
/*
* OK, move now. First in and then out.
*/
COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
addr, sizeof_patch + src_offs,
blk_size);
DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/
gus_write8 (0x41, 0); /*
* Disable GF1 DMA
*/
DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
blk_size, DMA_MODE_WRITE);
/*
* Set the DRAM address for the wave data
*/
address = target;
if (sound_dsp_dmachan[gus_devnum] > 3)
{
hold_address = address;
address = address >> 1;
address &= 0x0001ffffL;
address |= (hold_address & 0x000c0000L);
}
gus_write16 (0x42, (address >> 4) & 0xffff); /*
* DRAM DMA address
*/
/*
* Start the DMA transfer
*/
dma_command = 0x21; /*
* IRQ enable, DMA start
*/
if (patch.mode & WAVE_UNSIGNED)
dma_command |= 0x80; /*
* Invert MSB
*/
if (patch.mode & WAVE_16_BITS)
dma_command |= 0x40; /*
* 16 bit _DATA_
*/
if (sound_dsp_dmachan[gus_devnum] > 3)
dma_command |= 0x04; /*
* 16 bit DMA channel
*/
gus_write8 (0x41, dma_command); /*
* Let's go luteet (=bugs)
*/
/*
* Sleep here until the DRAM DMA done interrupt is served
*/
active_device = GUS_DEV_WAVE;
DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
printk ("GUS: DMA Transfer timed out\n");
RESTORE_INTR (flags);
}
#endif /*
* * * GUS_NO_DMA */
/*
* Now the next part
*/
left -= blk_size;
src_offs += blk_size;
target += blk_size;
gus_write8 (0x41, 0); /*
* Stop DMA
*/
}
free_mem_ptr += patch.len;
if (!pmgr_flag)
pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
free_sample++;
return 0;
}
static void
guswave_hw_control (int dev, unsigned char *event)
{
int voice, cmd;
unsigned short p1, p2;
unsigned long plong, flags;
cmd = event[2];
voice = event[3];
p1 = *(unsigned short *) &event[4];
p2 = *(unsigned short *) &event[6];
plong = *(unsigned long *) &event[4];
if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
(cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
do_volume_irq (voice);
switch (cmd)
{
case _GUS_NUMVOICES:
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_select_max_voices (p1);
RESTORE_INTR (flags);
break;
case _GUS_VOICESAMPLE:
guswave_set_instr (dev, voice, p1);
break;
case _GUS_VOICEON:
DISABLE_INTR (flags);
gus_select_voice (voice);
p1 &= ~0x20; /*
* Disable intr
*/
gus_voice_on (p1);
RESTORE_INTR (flags);
break;
case _GUS_VOICEOFF:
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_off ();
RESTORE_INTR (flags);
break;
case _GUS_VOICEFADE:
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_fade (voice);
RESTORE_INTR (flags);
break;
case _GUS_VOICEMODE:
DISABLE_INTR (flags);
gus_select_voice (voice);
p1 &= ~0x20; /*
* Disable intr
*/
gus_voice_mode (p1);
RESTORE_INTR (flags);
break;
case _GUS_VOICEBALA:
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_balance (p1);
RESTORE_INTR (flags);
break;
case _GUS_VOICEFREQ:
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_freq (plong);
RESTORE_INTR (flags);
break;
case _GUS_VOICEVOL:
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_volume (p1);
RESTORE_INTR (flags);
break;
case _GUS_VOICEVOL2: /*
* Just update the voice value
*/
voices[voice].initial_volume =
voices[voice].current_volume = p1;
break;
case _GUS_RAMPRANGE:
if (voices[voice].mode & WAVE_ENVELOPES)
break; /*
* NO-NO
*/
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_ramp_range (p1, p2);
RESTORE_INTR (flags);
break;
case _GUS_RAMPRATE:
if (voices[voice].mode & WAVE_ENVELOPES)
break; /*
* NO-NO
*/
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_ramp_rate (p1, p2);
RESTORE_INTR (flags);
break;
case _GUS_RAMPMODE:
if (voices[voice].mode & WAVE_ENVELOPES)
break; /*
* NO-NO
*/
DISABLE_INTR (flags);
gus_select_voice (voice);
p1 &= ~0x20; /*
* Disable intr
*/
gus_ramp_mode (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPON:
if (voices[voice].mode & WAVE_ENVELOPES)
break; /*
* NO-NO
*/
DISABLE_INTR (flags);
gus_select_voice (voice);
p1 &= ~0x20; /*
* Disable intr
*/
gus_rampon (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPOFF:
if (voices[voice].mode & WAVE_ENVELOPES)
break; /*
* NO-NO
*/
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_rampoff ();
RESTORE_INTR (flags);
break;
case _GUS_VOLUME_SCALE:
volume_base = p1;
volume_scale = p2;
break;
case _GUS_VOICE_POS:
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_set_voice_pos (voice, plong);
RESTORE_INTR (flags);
break;
default:;
}
}
static int
gus_sampling_set_speed (int speed)
{
if (speed <= 0)
return gus_sampling_speed;
if (speed > 44100)
speed = 44100;
gus_sampling_speed = speed;
return speed;
}
static int
gus_sampling_set_channels (int channels)
{
if (!channels)
return gus_sampling_channels;
if (channels > 2)
channels = 2;
if (channels < 1)
channels = 1;
gus_sampling_channels = channels;
return channels;
}
static int
gus_sampling_set_bits (int bits)
{
if (!bits)
return gus_sampling_bits;
if (bits != 8 && bits != 16)
bits = 8;
gus_sampling_bits = bits;
return bits;
}
static int
gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
{
switch (cmd)
{
case SOUND_PCM_WRITE_RATE:
if (local)
return gus_sampling_set_speed (arg);
return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg)));
break;
case SOUND_PCM_READ_RATE:
if (local)
return gus_sampling_speed;
return IOCTL_OUT (arg, gus_sampling_speed);
break;
case SNDCTL_DSP_STEREO:
if (local)
return gus_sampling_set_channels (arg + 1) - 1;
return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1);
break;
case SOUND_PCM_WRITE_CHANNELS:
if (local)
return gus_sampling_set_channels (arg);
return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
break;
case SOUND_PCM_READ_CHANNELS:
if (local)
return gus_sampling_channels;
return IOCTL_OUT (arg, gus_sampling_channels);
break;
case SNDCTL_DSP_SAMPLESIZE:
if (local)
return gus_sampling_set_bits (arg);
return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
break;
case SOUND_PCM_READ_BITS:
if (local)
return gus_sampling_bits;
return IOCTL_OUT (arg, gus_sampling_bits);
case SOUND_PCM_WRITE_FILTER: /*
* NOT YET IMPLEMENTED
*/
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
break;
case SOUND_PCM_READ_FILTER:
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
break;
default:
return RET_ERROR (EINVAL);
}
return RET_ERROR (EINVAL);
}
static void
gus_sampling_reset (int dev)
{
}
static int
gus_sampling_open (int dev, int mode)
{
#ifdef GUS_NO_DMA
printk ("GUS: DMA mode not enabled. Device not supported\n");
return RET_ERROR (ENXIO);
#endif
if (gus_busy)
return RET_ERROR (EBUSY);
gus_initialize ();
gus_busy = 1;
active_device = 0;
gus_reset ();
reset_sample_memory ();
gus_select_max_voices (14);
pcm_active = 0;
pcm_opened = 1;
if (mode & OPEN_READ)
{
recording_active = 1;
set_input_volumes();
}
return 0;
}
static void
gus_sampling_close (int dev)
{
gus_reset ();
gus_busy = 0;
pcm_opened = 0;
active_device = 0;
if (recording_active)
set_input_volumes();
recording_active = 0;
}
static void
gus_sampling_update_volume (void)
{
unsigned long flags;
int voice;
DISABLE_INTR (flags);
if (pcm_active && pcm_opened)
for (voice = 0; voice < gus_sampling_channels; voice++)
{
gus_select_voice (voice);
gus_rampoff ();
gus_voice_volume (1530 + (25 * gus_pcm_volume));
gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
}
RESTORE_INTR (flags);
}
static void
play_next_pcm_block (void)
{
unsigned long flags;
int speed = gus_sampling_speed;
int this_one, is16bits, chn;
unsigned long dram_loc;
unsigned char mode[2], ramp_mode[2];
if (!pcm_qlen)
return;
this_one = pcm_head;
for (chn = 0; chn < gus_sampling_channels; chn++)
{
mode[chn] = 0x00;
ramp_mode[chn] = 0x03; /*
* Ramping and rollover off
*/
if (chn == 0)
{
mode[chn] |= 0x20; /*
* Loop irq
*/
voices[chn].loop_irq_mode = LMODE_PCM;
}
if (gus_sampling_bits != 8)
{
is16bits = 1;
mode[chn] |= 0x04; /*
* 16 bit data
*/
}
else
is16bits = 0;
dram_loc = this_one * pcm_bsize;
dram_loc += chn * pcm_banksize;
if (this_one == (pcm_nblk - 1)) /*
* Last of the DRAM buffers
*/
{
mode[chn] |= 0x08; /*
* Enable loop
*/
ramp_mode[chn] = 0x03; /*
* Disable rollover
*/
}
else
{
if (chn == 0)
ramp_mode[chn] = 0x04; /*
* Enable rollover bit
*/
}
DISABLE_INTR (flags);
gus_select_voice (chn);
gus_voice_freq (speed);
if (gus_sampling_channels == 1)
gus_voice_balance (7); /*
* mono
*/
else if (chn == 0)
gus_voice_balance (0); /*
* left
*/
else
gus_voice_balance (15); /*
* right
*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -