?? gus_wave.c
字號:
target = voices[voice].initial_volume;
if (ramp_time == INSTANT_RAMP)
{
gus_rampoff ();
gus_voice_volume (target);
RESTORE_INTR (flags);
return;
}
if (ramp_time == FAST_RAMP)
rate = 63;
else
rate = 16;
gus_ramp_rate (0, rate);
if ((target - current) / 64 == 0) /*
* Too close
*/
{
gus_rampoff ();
gus_voice_volume (target);
RESTORE_INTR (flags);
return;
}
if (target > current)
{
if (target > (4095 - 65))
target = 4095 - 65;
gus_ramp_range (current, target);
gus_rampon (0x00); /*
* Ramp up, once, no irq
*/
}
else
{
if (target < 65)
target = 65;
gus_ramp_range (target, current);
gus_rampon (0x40); /*
* Ramp down, once, no irq
*/
}
RESTORE_INTR (flags);
}
static void
dynamic_volume_change (int voice)
{
unsigned char status;
unsigned long flags;
DISABLE_INTR (flags);
gus_select_voice (voice);
status = gus_read8 (0x00); /*
* Voice status
*/
RESTORE_INTR (flags);
if (status & 0x03)
return; /*
* Voice not started
*/
if (!(voices[voice].mode & WAVE_ENVELOPES))
{
compute_and_set_volume (voice, voices[voice].midi_volume, 1);
return;
}
/*
* Voice is running and has envelopes.
*/
DISABLE_INTR (flags);
gus_select_voice (voice);
status = gus_read8 (0x0d); /*
* Ramping status
*/
RESTORE_INTR (flags);
if (status & 0x03) /*
* Sustain phase?
*/
{
compute_and_set_volume (voice, voices[voice].midi_volume, 1);
return;
}
if (voices[voice].env_phase < 0)
return;
compute_volume (voice, voices[voice].midi_volume);
#if 0 /*
* * * Is this really required */
voices[voice].current_volume =
gus_read16 (0x09) >> 4; /*
* Get current volume
*/
voices[voice].env_phase--;
step_envelope (voice);
#endif
}
static void
guswave_controller (int dev, int voice, int ctrl_num, int value)
{
unsigned long flags;
unsigned long freq;
if (voice < 0 || voice > 31)
return;
switch (ctrl_num)
{
case CTRL_PITCH_BENDER:
voices[voice].bender = value;
if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
{
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);
}
break;
case CTRL_PITCH_BENDER_RANGE:
voices[voice].bender_range = value;
break;
#ifdef FUTURE_VERSION
case CTL_EXPRESSION:
value /= 128;
#endif
case CTRL_EXPRESSION:
volume_method = VOL_METHOD_ADAGIO;
voices[voice].expression_vol = value;
if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
dynamic_volume_change (voice);
break;
#ifdef FUTURE_VERSION
case CTL_PAN:
voices[voice].panning = (value * 2) - 128;
break;
case CTL_MAIN_VOLUME:
value = (value * 100) / 16383;
#endif
case CTRL_MAIN_VOLUME:
volume_method = VOL_METHOD_ADAGIO;
voices[voice].main_vol = value;
if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
dynamic_volume_change (voice);
break;
default: /*
* Ignore
*/
break;
}
}
static int
guswave_start_note2 (int dev, int voice, int note_num, int volume)
{
int sample, best_sample, best_delta, delta_freq;
int is16bits, samplep, patch, pan;
unsigned long note_freq, base_note, freq, flags;
unsigned char mode = 0;
if (voice < 0 || voice > 31)
{
printk ("GUS: Invalid voice\n");
return RET_ERROR (EINVAL);
}
if (note_num == 255)
{
if (voices[voice].mode & WAVE_ENVELOPES)
{
voices[voice].midi_volume = volume;
dynamic_volume_change (voice);
return 0;
}
compute_and_set_volume (voice, volume, 1);
return 0;
}
if ((patch = patch_map[voice]) == -1)
{
return RET_ERROR (EINVAL);
}
if ((samplep = patch_table[patch]) == -1)
{
return RET_ERROR (EINVAL);
}
note_freq = note_to_freq (note_num);
/*
* Find a sample within a patch so that the note_freq is between low_note
* and high_note.
*/
sample = -1;
best_sample = samplep;
best_delta = 1000000;
while (samplep >= 0 && sample == -1)
{
delta_freq = note_freq - samples[samplep].base_note;
if (delta_freq < 0)
delta_freq = -delta_freq;
if (delta_freq < best_delta)
{
best_sample = samplep;
best_delta = delta_freq;
}
if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
sample = samplep;
else
samplep = samples[samplep].key; /*
* Follow link
*/
}
if (sample == -1)
sample = best_sample;
if (sample == -1)
{
printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
return 0; /*
* Should play default patch ???
*/
}
is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /*
* 8 or 16
* bit
* samples
*/
voices[voice].mode = samples[sample].mode;
voices[voice].patch_vol = samples[sample].volume;
if (voices[voice].mode & WAVE_ENVELOPES)
{
int i;
for (i = 0; i < 6; i++)
{
voices[voice].env_rate[i] = samples[sample].env_rate[i];
voices[voice].env_offset[i] = samples[sample].env_offset[i];
}
}
sample_map[voice] = sample;
base_note = samples[sample].base_note / 100; /*
* To avoid overflows
*/
note_freq /= 100;
freq = samples[sample].base_freq * note_freq / base_note;
voices[voice].orig_freq = freq;
/*
* Since the pitch bender may have been set before playing the note, we
* have to calculate the bending now.
*/
freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
voices[voice].current_freq = freq;
pan = (samples[sample].panning + voices[voice].panning) / 32;
pan += 7;
if (pan < 0)
pan = 0;
if (pan > 15)
pan = 15;
if (samples[sample].mode & WAVE_16_BITS)
{
mode |= 0x04; /*
* 16 bits
*/
if ((sample_ptrs[sample] >> 18) !=
((sample_ptrs[sample] + samples[sample].len) >> 18))
printk ("GUS: Sample address error\n");
}
/*************************************************************************
* CAUTION! Interrupts disabled. Don't return before enabling
*************************************************************************/
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_voice_off (); /*
* It may still be running
*/
gus_rampoff ();
if (voices[voice].mode & WAVE_ENVELOPES)
{
compute_volume (voice, volume);
init_envelope (voice);
}
else
compute_and_set_volume (voice, volume, 0);
if (samples[sample].mode & WAVE_LOOP_BACK)
gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
voices[voice].offset_pending, is16bits); /* Sample
* start=end */
else
gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
is16bits); /* Sample start=begin */
if (samples[sample].mode & WAVE_LOOPING)
{
mode |= 0x08; /*
* Looping on
*/
if (samples[sample].mode & WAVE_BIDIR_LOOP)
mode |= 0x10; /*
* Bidirectional looping on
*/
if (samples[sample].mode & WAVE_LOOP_BACK)
{
gus_write_addr (0x0a,
sample_ptrs[sample] + samples[sample].loop_end -
voices[voice].offset_pending, is16bits);
mode |= 0x40;
}
gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /*
* Loop
* start
* location
*/
gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /*
* Loop
* end
* location
*/
}
else
{
mode |= 0x20; /*
* Loop irq at the end
*/
voices[voice].loop_irq_mode = LMODE_FINISH; /*
* Ramp it down at
* the * end
*/
voices[voice].loop_irq_parm = 1;
gus_write_addr (0x02, sample_ptrs[sample], is16bits); /*
* Loop start
* location
*/
gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len-1, is16bits); /*
* Loop
* end
* location
*/
}
gus_voice_freq (freq);
gus_voice_balance (pan);
gus_voice_on (mode);
RESTORE_INTR (flags);
return 0;
}
/*
* * New guswave_start_note by Andrew J. Robinson attempts to minimize
* clicking * when the note playing on the voice is changed. It uses volume
* ramping. */
static int
guswave_start_note (int dev, int voice, int note_num, int volume)
{
long int flags;
int mode;
int ret_val = 0;
DISABLE_INTR (flags);
if (note_num == 255)
{
if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
voices[voice].volume_pending = volume;
else
ret_val = guswave_start_note2 (dev, voice, note_num, volume);
}
else
{
gus_select_voice (voice);
mode = gus_read8 (0x00);
if (mode & 0x20)
gus_write8 (0x00, mode & 0xdf); /* No interrupt! */
voices[voice].offset_pending = 0;
voices[voice].kill_pending = 0;
voices[voice].volume_irq_mode = 0;
voices[voice].loop_irq_mode = 0;
if (voices[voice].sample_pending >= 0)
{
guswave_set_instr (voices[voice].dev_pending, voice,
voices[voice].sample_pending);
voices[voice].sample_pending = -1;
}
if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
{
ret_val = guswave_start_note2 (dev, voice, note_num, volume);
}
else
{
voices[voice].dev_pending = dev;
voices[voice].note_pending = note_num;
voices[voice].volume_pending = volume;
voices[voice].volume_irq_mode = VMODE_START_NOTE;
gus_rampoff ();
gus_ramp_range (2000, 4065);
gus_ramp_rate (0, 63); /* Fastest possible rate */
gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
}
}
RESTORE_INTR (flags);
return ret_val;
}
static void
guswave_reset (int dev)
{
int i;
for (i = 0; i < 32; i++)
{
gus_voice_init (i);
gus_voice_init2 (i);
}
}
static int
guswave_open (int dev, int mode)
{
int err;
if (gus_busy)
return RET_ERROR (EBUSY);
gus_initialize ();
if ((err = DMAbuf_open_dma (gus_devnum)))
return err;
RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
gus_busy = 1;
active_device = GUS_DEV_WAVE;
gus_reset ();
return 0;
}
static void
guswave_close (int dev)
{
gus_busy = 0;
active_device = 0;
gus_reset ();
DMAbuf_close_dma (gus_devnum);
}
static int
guswave_load_patch (int dev, int format, snd_rw_buf * addr,
int offs, int count, int pmgr_flag)
{
struct patch_info patch;
int instr;
long sizeof_patch;
unsigned long blk_size, blk_end, left, src_offs, target;
sizeof_patch = (long) &patch.data[0] - (long) &patch; /*
* Size of
* the header
* * info
*/
if (format != GUS_PATCH)
{
printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
return RET_ERROR (EINVAL);
}
if (count < sizeof_patch)
{
printk ("GUS Error: Patch header too short\n");
return RET_ERROR (EINVAL);
}
count -= sizeof_patch;
if (free_sample >= MAX_SAMPLE)
{
printk ("GUS: Sample table full\n");
return RET_ERROR (ENOSPC);
}
/*
* Copy the header from user space but ignore the first bytes which have
* been transferred already.
*/
COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);
instr = patch.instr_no;
if (instr < 0 || instr > MAX_PATCH)
{
printk ("GUS: Invalid patch number %d\n", instr);
return RET_ERROR (EINVAL);
}
if (count < patch.len)
{
printk ("GUS Warning: Patch record too short (%d<%d)\n",
count, (int) patch.len);
patch.len = count;
}
if (patch.len <= 0 || patch.len > gus_mem_size)
{
printk ("GUS: Invalid sample length %d\n", (int) patch.len);
return RET_ERROR (EINVAL);
}
if (patch.mode & WAVE_LOOPING)
{
if (patch.loop_start < 0 || patch.loop_start >= patch.len)
{
printk ("GUS: Invalid loop start\n");
return RET_ERROR (EINVAL);
}
if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
{
printk ("GUS: Invalid loop end\n");
return RET_ERROR (EINVAL);
}
}
free_mem_ptr = (free_mem_ptr + 31) & ~31; /*
* Alignment 32 bytes
*/
#define GUS_BANK_SIZE (256*1024)
if (patch.mode & WAVE_16_BITS)
{
/*
* 16 bit samples must fit one 256k bank.
*/
if (patch.len >= GUS_BANK_SIZE)
{
printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
return RET_ERROR (ENOSPC);
}
if ((free_mem_ptr / GUS_BANK_SIZE) !=
((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
{
unsigned long tmp_mem = /*
* Align to 256K*N
*/
((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
if ((tmp_mem + patch.len) > gus_mem_size)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -