📄 gus_wave.c
字号:
return; } if (vol > prev_vol) { if (vol >= (4096 - 64)) vol = 4096 - 65; gus_ramp_range (0, vol); gus_rampon (0x20); /* Increasing volume, with IRQ */ } else { if (vol <= 64) vol = 65; gus_ramp_range (vol, 4030); gus_rampon (0x60); /* Decreasing volume, with IRQ */ } voices[voice].current_volume = vol; RESTORE_INTR (flags);}static voidinit_envelope (int voice){ voices[voice].env_phase = -1; voices[voice].current_volume = 64; step_envelope (voice);}static voidstart_release (int voice, long int flags){ 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 (); RESTORE_INTR (flags); step_envelope (voice);}static voidgus_voice_fade (int voice){ int instr_no = sample_map[voice], is16bits; long int flags; DISABLE_INTR (flags); gus_select_voice (voice); if (instr_no < 0 || instr_no > MAX_SAMPLE) { gus_write8 (0x00, 0x03); /* Hard stop */ voice_alloc->map[voice] = 0; RESTORE_INTR (flags); return; } is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ if (voices[voice].mode & WAVE_ENVELOPES) { start_release (voice, flags); return; } /* * Ramp the volume down but not too quickly. */ if ((int) (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, with IRQ */ voices[voice].volume_irq_mode = VMODE_HALT; RESTORE_INTR (flags);}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, 0, 3, 0, 2, 0, 4, 0, 1, 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 = gus_dma_map[gus_dma_read] << 3; if(!dma_image) printk ("Warning! GUS DMA read channel not selected.\n"); if(gus_dma_read == gus_dma) { dma_image = 0x40; /* dual dma inhibited 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 (INT_HANDLER_CALL (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 intguswave_kill_note (int dev, int voice, int note, int velocity){ unsigned long flags; DISABLE_INTR (flags); /* voice_alloc->map[voice] = 0xffff; */ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { voices[voice].kill_pending = 1; RESTORE_INTR (flags); } else { RESTORE_INTR (flags); gus_voice_fade (voice); } RESTORE_INTR (flags); return 0;}static voidguswave_aftertouch (int dev, int voice, int pressure){#if 0 short lo_limit, hi_limit; unsigned long flags; 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, dow, loop */ RESTORE_INTR (flags);#endif /* 0 */}static voidguswave_panning (int dev, int voice, int value){ if (voice >= 0 || voice < 32) voices[voice].panning = value;}static voidguswave_volume_method (int dev, int mode){ if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) volume_method = mode;}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; case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ voices[voice].initial_volume = gus_linear_vol (volume, voices[voice].main_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; compute_volume (voice, volume); voices[voice].current_volume = voices[voice].initial_volume; DISABLE_INTR (flags); /* * CAUTION! Interrupts disabled. Enable them before returning */ gus_select_voice (voice); 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) /* Close enough to target. */ { 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){ unsigned char status; unsigned long flags; DISABLE_INTR (flags); gus_select_voice (voice); status = gus_read8 (0x00); /* Get voice status */ RESTORE_INTR (flags); if (status & 0x03) return; /* Voice was not running */ 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -