📄 gus_wave.c
字号:
if (!pcm_active) /*
* Voice not started yet
*/
{
/*
* The playback was not started yet (or there has been a pause).
* Start the voice (again) and ask for a rollover irq at the end of
* this_one block. If this_one one is last of the buffers, use just
* the normal loop with irq.
*/
gus_voice_off (); /*
* It could already be running
*/
gus_rampoff ();
gus_voice_volume (1530 + (25 * gus_pcm_volume));
gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
gus_write_addr (0x0a, dram_loc, is16bits); /*
* Starting position
*/
gus_write_addr (0x02, chn * pcm_banksize, is16bits); /*
* Loop start
* location
*/
if (chn != 0)
gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
is16bits); /*
* Loop end location
*/
}
if (chn == 0)
gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
* Loop
* end
* location
*/
else
mode[chn] |= 0x08; /*
* Enable loop
*/
if (pcm_datasize[this_one] != pcm_bsize)
{
/*
* Incomplete block. Possibly the last one.
*/
if (chn == 0)
{
mode[chn] &= ~0x08; /*
* Disable loop
*/
mode[chn] |= 0x20; /*
* Enable loop IRQ
*/
voices[0].loop_irq_mode = LMODE_PCM_STOP;
ramp_mode[chn] = 0x03; /*
* No rollover bit
*/
}
else
{
gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
* Loop
* end
* location
*/
mode[chn] &= ~0x08; /*
* Disable loop
*/
}
}
RESTORE_INTR (flags);
}
for (chn = 0; chn < gus_sampling_channels; chn++)
{
DISABLE_INTR (flags);
gus_select_voice (chn);
gus_write8 (0x0d, ramp_mode[chn]);
gus_voice_on (mode[chn]);
RESTORE_INTR (flags);
}
pcm_active = 1;
}
static void
gus_transfer_output_block (int dev, unsigned long buf,
int total_count, int intrflag, int chn)
{
/*
* This routine transfers one block of audio data to the DRAM. In mono mode
* it's called just once. When in stereo mode, this_one routine is called
* once for both channels.
*
* The left/mono channel data is transferred to the beginning of dram and the
* right data to the area pointed by gus_page_size.
*/
int this_one, count;
unsigned long flags;
unsigned char dma_command;
unsigned long address, hold_address;
DISABLE_INTR (flags);
count = total_count / gus_sampling_channels;
if (chn == 0)
{
if (pcm_qlen >= pcm_nblk)
printk ("GUS Warning: PCM buffers out of sync\n");
this_one = pcm_current_block = pcm_tail;
pcm_qlen++;
pcm_tail = (pcm_tail + 1) % pcm_nblk;
pcm_datasize[this_one] = count;
}
else
this_one = pcm_current_block;
gus_write8 (0x41, 0); /*
* Disable GF1 DMA
*/
DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
address = this_one * pcm_bsize;
address += chn * pcm_banksize;
if (sound_dsp_dmachan[dev] > 3)
{
hold_address = address;
address = address >> 1;
address &= 0x0001ffffL;
address |= (hold_address & 0x000c0000L);
}
gus_write16 (0x42, (address >> 4) & 0xffff); /*
* DRAM DMA address
*/
dma_command = 0x21; /*
* IRQ enable, DMA start
*/
if (gus_sampling_bits != 8)
dma_command |= 0x40; /*
* 16 bit _DATA_
*/
else
dma_command |= 0x80; /*
* Invert MSB
*/
if (sound_dsp_dmachan[dev] > 3)
dma_command |= 0x04; /*
* 16 bit DMA channel
*/
gus_write8 (0x41, dma_command); /*
* Kick on
*/
if (chn == (gus_sampling_channels - 1)) /*
* Last channel
*/
{
/*
* Last (right or mono) channel data
*/
active_device = GUS_DEV_PCM_DONE;
if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
{
play_next_pcm_block ();
}
}
else /*
* * * Left channel data. The right channel
* is * * * transferred after DMA interrupt */
active_device = GUS_DEV_PCM_CONTINUE;
RESTORE_INTR (flags);
}
static void
gus_sampling_output_block (int dev, unsigned long buf, int total_count,
int intrflag, int restart_dma)
{
pcm_current_buf = buf;
pcm_current_count = total_count;
pcm_current_intrflag = intrflag;
pcm_current_dev = dev;
gus_transfer_output_block (dev, buf, total_count, intrflag, 0);
}
static void
gus_sampling_start_input (int dev, unsigned long buf, int count,
int intrflag, int restart_dma)
{
unsigned long flags;
unsigned char mode;
DISABLE_INTR (flags);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
mode = 0xa0; /*
* DMA IRQ enable, invert MSB
*/
if (sound_dsp_dmachan[dev] > 3)
mode |= 0x04; /*
* 16 bit DMA channel
*/
if (gus_sampling_channels > 1)
mode |= 0x02; /*
* Stereo
*/
mode |= 0x01; /*
* DMA enable
*/
gus_write8 (0x49, mode);
RESTORE_INTR (flags);
}
static int
gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
{
unsigned int rate;
rate = (9878400 / (gus_sampling_speed + 2)) / 16;
gus_write8 (0x48, rate & 0xff); /*
* Set sampling frequency
*/
if (gus_sampling_bits != 8)
{
printk ("GUS Error: 16 bit recording not supported\n");
return RET_ERROR (EINVAL);
}
return 0;
}
static int
gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
{
int i;
long mem_ptr, mem_size;
mem_ptr = 0;
mem_size = gus_mem_size / gus_sampling_channels;
if (mem_size > (256 * 1024))
mem_size = 256 * 1024;
pcm_bsize = bsize / gus_sampling_channels;
pcm_head = pcm_tail = pcm_qlen = 0;
pcm_nblk = MAX_PCM_BUFFERS;
if ((pcm_bsize * pcm_nblk) > mem_size)
pcm_nblk = mem_size / pcm_bsize;
for (i = 0; i < pcm_nblk; i++)
pcm_datasize[i] = 0;
pcm_banksize = pcm_nblk * pcm_bsize;
if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
pcm_nblk--;
return 0;
}
static int
gus_has_output_drained (int dev)
{
return !pcm_qlen;
}
static void
gus_copy_from_user (int dev, char *localbuf, int localoffs,
snd_rw_buf * userbuf, int useroffs, int len)
{
if (gus_sampling_channels == 1)
{
COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
}
else if (gus_sampling_bits == 8)
{
int in_left = useroffs;
int in_right = useroffs + 1;
char *out_left, *out_right;
int i;
len /= 2;
localoffs /= 2;
out_left = &localbuf[localoffs];
out_right = out_left + pcm_bsize;
for (i = 0; i < len; i++)
{
GET_BYTE_FROM_USER (*out_left++, userbuf, in_left);
in_left += 2;
GET_BYTE_FROM_USER (*out_right++, userbuf, in_right);
in_right += 2;
}
}
else
{
int in_left = useroffs;
int in_right = useroffs + 1;
short *out_left, *out_right;
int i;
len /= 4;
localoffs /= 4;
out_left = (short *) &localbuf[localoffs];
out_right = out_left + (pcm_bsize / 2);
for (i = 0; i < len; i++)
{
GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left);
in_left += 2;
GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right);
in_right += 2;
}
}
}
static struct audio_operations gus_sampling_operations =
{
"Gravis UltraSound",
gus_sampling_open,
gus_sampling_close,
gus_sampling_output_block,
gus_sampling_start_input,
gus_sampling_ioctl,
gus_sampling_prepare_for_input,
gus_sampling_prepare_for_output,
gus_sampling_reset,
gus_sampling_reset,
gus_has_output_drained,
gus_copy_from_user
};
#ifdef FUTURE_VERSION
static void
guswave_bender (int dev, int voice, int value)
{
int freq;
unsigned long flags;
voices[voice].bender = value - 8192;
freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
voices[voice].current_freq = freq;
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_freq (freq);
RESTORE_INTR (flags);
}
#endif
static int
guswave_patchmgr (int dev, struct patmgr_info *rec)
{
int i, n;
switch (rec->command)
{
case PM_GET_DEVTYPE:
rec->parm1 = PMTYPE_WAVE;
return 0;
break;
case PM_GET_NRPGM:
rec->parm1 = MAX_PATCH;
return 0;
break;
case PM_GET_PGMMAP:
rec->parm1 = MAX_PATCH;
for (i = 0; i < MAX_PATCH; i++)
{
int ptr = patch_table[i];
rec->data.data8[i] = 0;
while (ptr >= 0 && ptr < free_sample)
{
rec->data.data8[i]++;
ptr = samples[ptr].key; /*
* Follow link
*/
}
}
return 0;
break;
case PM_GET_PGM_PATCHES:
{
int ptr = patch_table[rec->parm1];
n = 0;
while (ptr >= 0 && ptr < free_sample)
{
rec->data.data32[n++] = ptr;
ptr = samples[ptr].key; /*
* Follow link
*/
}
}
rec->parm1 = n;
return 0;
break;
case PM_GET_PATCH:
{
int ptr = rec->parm1;
struct patch_info *pat;
if (ptr < 0 || ptr >= free_sample)
return RET_ERROR (EINVAL);
memcpy (rec->data.data8, (char *) &samples[ptr],
sizeof (struct patch_info));
pat = (struct patch_info *) rec->data.data8;
pat->key = GUS_PATCH; /*
* Restore patch type
*/
rec->parm1 = sample_ptrs[ptr]; /*
* DRAM address
*/
rec->parm2 = sizeof (struct patch_info);
}
return 0;
break;
case PM_SET_PATCH:
{
int ptr = rec->parm1;
struct patch_info *pat;
if (ptr < 0 || ptr >= free_sample)
return RET_ERROR (EINVAL);
pat = (struct patch_info *) rec->data.data8;
if (pat->len > samples[ptr].len) /*
* Cannot expand sample
*/
return RET_ERROR (EINVAL);
pat->key = samples[ptr].key; /*
* Ensure the link is correct
*/
memcpy ((char *) &samples[ptr], rec->data.data8,
sizeof (struct patch_info));
pat->key = GUS_PATCH;
}
return 0;
break;
case PM_READ_PATCH: /*
* Returns a block of wave data from the DRAM
*/
{
int sample = rec->parm1;
int n;
long offs = rec->parm2;
int l = rec->parm3;
if (sample < 0 || sample >= free_sample)
return RET_ERROR (EINVAL);
if (offs < 0 || offs >= samples[sample].len)
return RET_ERROR (EINVAL); /*
* Invalid offset
*/
n = samples[sample].len - offs; /*
* Nr of bytes left
*/
if (l > n)
l = n;
if (l > sizeof (rec->data.data8))
l = sizeof (rec->data.data8);
if (l <= 0)
return RET_ERROR (EINVAL); /*
* Was there a bug?
*/
offs += sample_ptrs[sample]; /*
* Begin offsess + offset to DRAM
*/
for (n = 0; n < l; n++)
rec->data.data8[n] = gus_peek (offs++);
rec->parm1 = n; /*
* Nr of bytes copied
*/
}
return 0;
break;
case PM_WRITE_PATCH: /*
* Writes a block of wave data to the DRAM
*/
{
int sample = rec->parm1;
int n;
long offs = rec->parm2;
int l = rec->parm3;
if (sample < 0 || sample >= free_sample)
return RET_ERROR (EINVAL);
if (offs < 0 || offs >= samples[sample].len)
return RET_ERROR (EINVAL); /*
* Invalid offset
*/
n = samples[sample].len - offs; /*
* Nr of bytes left
*/
if (l > n)
l = n;
if (l > sizeof (rec->data.data8))
l = sizeof (rec->data.data8);
if (l <= 0)
return RET_ERROR (EINVAL); /*
* Was there a bug?
*/
offs += sample_ptrs[sample]; /*
* Begin offsess + offset to DRAM
*/
for (n = 0; n < l; n++)
gus_poke (offs++, rec->data.data8[n]);
rec->parm1 = n; /*
* Nr of bytes copied
*/
}
return 0;
break;
default:
return RET_ERROR (EINVAL);
}
}
static struct synth_operations guswave_operations =
{
&gus_info,
#ifdef FUTURE_VERSION
0,
#endif
SYNTH_TYPE_SAMPLE,
SAMPLE_TYPE_GUS,
guswave_open,
guswave_close,
guswave_ioctl,
guswave_kill_note,
guswave_start_note,
guswave_set_instr,
guswave_reset,
gus
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -