?? gus_wave.c
字號:
{ 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 voidguswave_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 intguswave_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 intguswave_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 voidguswave_reset (int dev){ int i; for (i = 0; i < 32; i++) { gus_voice_init (i); gus_voice_init2 (i); }}static intguswave_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 voidguswave_close (int dev){ gus_busy = 0; active_device = 0; gus_reset (); DMAbuf_close_dma (gus_devnum);}static intguswave_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) 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
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -