📄 gus_wave.c
字号:
*/ 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 voidinit_envelope (int voice){ voices[voice].env_phase = -1; voices[voice].current_volume = 64; step_envelope (voice);}static voidstart_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 voidgus_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 voidgus_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 voidgus_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);}intgus_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 intguswave_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 intguswave_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_VERSIONguswave_kill_note (int dev, int voice, int note, int velocity)#elseguswave_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 voidguswave_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 voidguswave_panning (int dev, int voice, int value){ if (voice >= 0 || voice < 32) voices[voice].panning = value;}static voidcompute_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 voidcompute_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; 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 voiddynamic_volume_change (int voice)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -