📄 gus_wave.c
字号:
address = address >> 1; address &= 0x0001ffffL; address |= (hold_address & 0x000c0000L); } gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ /* * Start the DMA transfer */ dma_command = 0x21; /* IRQ enable, DMA start */ if (patch.mode & WAVE_UNSIGNED) dma_command |= 0x80; /* Invert MSB */ if (patch.mode & WAVE_16_BITS) dma_command |= 0x40; /* 16 bit _DATA_ */ if (audio_devs[gus_devnum]->dmachan > 3) dma_command |= 0x04; /* 16 bit DMA _channel_ */ gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */ /* * Sleep here until the DRAM DMA done interrupt is served */ active_device = GUS_DEV_WAVE; DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ); if (TIMED_OUT (dram_sleeper, dram_sleep_flag)) printk ("GUS: DMA Transfer timed out\n"); RESTORE_INTR (flags); }#endif /* GUS_NO_DMA */ /* * Now the next part */ left -= blk_size; src_offs += blk_size; target += blk_size; gus_write8 (0x41, 0); /* Stop DMA */ } free_mem_ptr += patch.len; if (!pmgr_flag) pmgr_inform (gus_devnum, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); free_sample++; return 0;}static voidguswave_hw_control (int dev, unsigned char *event){ int voice, cmd; unsigned short p1, p2; unsigned long plong, flags; cmd = event[2]; voice = event[3]; p1 = *(unsigned short *) &event[4]; p2 = *(unsigned short *) &event[6]; plong = *(unsigned long *) &event[4]; if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) do_volume_irq (voice); switch (cmd) { case _GUS_NUMVOICES: DISABLE_INTR (flags); gus_select_voice (voice); gus_select_max_voices (p1); RESTORE_INTR (flags); break; case _GUS_VOICESAMPLE: guswave_set_instr (dev, voice, p1); break; case _GUS_VOICEON: DISABLE_INTR (flags); gus_select_voice (voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_voice_on (p1); RESTORE_INTR (flags); break; case _GUS_VOICEOFF: DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_off (); RESTORE_INTR (flags); break; case _GUS_VOICEFADE: gus_voice_fade (voice); break; case _GUS_VOICEMODE: DISABLE_INTR (flags); gus_select_voice (voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_voice_mode (p1); RESTORE_INTR (flags); break; case _GUS_VOICEBALA: DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_balance (p1); RESTORE_INTR (flags); break; case _GUS_VOICEFREQ: DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_freq (plong); RESTORE_INTR (flags); break; case _GUS_VOICEVOL: DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_volume (p1); RESTORE_INTR (flags); break; case _GUS_VOICEVOL2: /* Just update the software voice level */ voices[voice].initial_volume = voices[voice].current_volume = p1; break; case _GUS_RAMPRANGE: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NO-NO */ DISABLE_INTR (flags); gus_select_voice (voice); gus_ramp_range (p1, p2); RESTORE_INTR (flags); break; case _GUS_RAMPRATE: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NJET-NJET */ DISABLE_INTR (flags); gus_select_voice (voice); gus_ramp_rate (p1, p2); RESTORE_INTR (flags); break; case _GUS_RAMPMODE: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NO-NO */ DISABLE_INTR (flags); gus_select_voice (voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_ramp_mode (p1); RESTORE_INTR (flags); break; case _GUS_RAMPON: if (voices[voice].mode & WAVE_ENVELOPES) break; /* EI-EI */ DISABLE_INTR (flags); gus_select_voice (voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_rampon (p1); RESTORE_INTR (flags); break; case _GUS_RAMPOFF: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NEJ-NEJ */ DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); RESTORE_INTR (flags); break; case _GUS_VOLUME_SCALE: volume_base = p1; volume_scale = p2; break; case _GUS_VOICE_POS: DISABLE_INTR (flags); gus_select_voice (voice); gus_set_voice_pos (voice, plong); RESTORE_INTR (flags); break; default:; }}static intgus_sampling_set_speed (int speed){ if (speed <= 0) speed = gus_sampling_speed; if (speed < 4000) speed = 4000; if (speed > 44100) speed = 44100; gus_sampling_speed = speed; if (only_read_access) { /* Compute nearest valid recording speed and return it */ speed = (9878400 / (gus_sampling_speed + 2)) / 16; speed = (9878400 / (speed * 16)) - 2; } return speed;}static intgus_sampling_set_channels (int channels){ if (!channels) return gus_sampling_channels; if (channels > 2) channels = 2; if (channels < 1) channels = 1; gus_sampling_channels = channels; return channels;}static intgus_sampling_set_bits (int bits){ if (!bits) return gus_sampling_bits; if (bits != 8 && bits != 16) bits = 8; gus_sampling_bits = bits; return bits;}static intgus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local){ switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) return gus_sampling_set_speed (arg); return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg))); break; case SOUND_PCM_READ_RATE: if (local) return gus_sampling_speed; return IOCTL_OUT (arg, gus_sampling_speed); break; case SNDCTL_DSP_STEREO: if (local) return gus_sampling_set_channels (arg + 1) - 1; return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1); break; case SOUND_PCM_WRITE_CHANNELS: if (local) return gus_sampling_set_channels (arg); return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg))); break; case SOUND_PCM_READ_CHANNELS: if (local) return gus_sampling_channels; return IOCTL_OUT (arg, gus_sampling_channels); break; case SNDCTL_DSP_SETFMT: if (local) return gus_sampling_set_bits (arg); return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg))); break; case SOUND_PCM_READ_BITS: if (local) return gus_sampling_bits; return IOCTL_OUT (arg, gus_sampling_bits); case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; case SOUND_PCM_READ_FILTER: return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; } return RET_ERROR (EINVAL);}static voidgus_sampling_reset (int dev){}static intgus_sampling_open (int dev, int mode){ int dev_flag; int init_flag;#ifdef GUS_NO_DMA printk ("GUS: DMA mode not enabled. Device not supported\n"); return RET_ERROR (ENXIO);#endif dev_flag = 0; init_flag = (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0); if(mode & OPEN_WRITE) { if (gus_busy[gus_devnum]) return RET_ERROR(EBUSY); if(dev != gus_devnum) return RET_ERROR(ENXIO); dev_flag = gus_busy[gus_devnum] = 1; } if(mode & OPEN_READ) { if(gus_busy[gus_dspnum]) { if (dev_flag) gus_busy[gus_devnum] = 0; return RET_ERROR(EBUSY); } if(dev != gus_dspnum) { if (dev_flag) gus_busy[gus_devnum] = 0; return RET_ERROR(ENXIO); } } if(init_flag) { gus_initialize (); active_device = 0; gus_reset (); reset_sample_memory (); gus_select_max_voices (14); pcm_active = 0; dma_active = 0; pcm_opened = 1; } if (mode & OPEN_READ) { recording_active = 1; set_input_volumes (); } only_read_access = !(mode & OPEN_WRITE); return 0;}static voidgus_sampling_close (int dev){ gus_busy[dev] = 0; if (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0) { active_device = 0; gus_reset(); pcm_opened = 0; } if (recording_active) set_input_volumes (); recording_active = 0;}static voidgus_sampling_update_volume (void){ unsigned long flags; int voice; if (pcm_active && pcm_opened) for (voice = 0; voice < gus_sampling_channels; voice++) { DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); gus_voice_volume (1530 + (25 * gus_pcm_volume)); gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); RESTORE_INTR (flags); }}static voidplay_next_pcm_block (void){ unsigned long flags; int speed = gus_sampling_speed; int this_one, is16bits, chn; unsigned long dram_loc; unsigned char mode[2], ramp_mode[2]; if (!pcm_qlen) return; this_one = pcm_head; for (chn = 0; chn < gus_sampling_channels; chn++) { mode[chn] = 0x00; ramp_mode[chn] = 0x03; /* Ramping and rollover off */ if (chn == 0) { mode[chn] |= 0x20; /* Loop IRQ */ voices[chn].loop_irq_mode = LMODE_PCM; } if (gus_sampling_bits != 8) { is16bits = 1; mode[chn] |= 0x04; /* 16 bit data */ } else is16bits = 0; dram_loc = this_one * pcm_bsize; dram_loc += chn * pcm_banksize; if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ { mode[chn] |= 0x08; /* Enable loop */ ramp_mode[chn] = 0x03; /* Disable rollover bit */ } else { if (chn == 0) ramp_mode[chn] = 0x04; /* Enable rollover bit */ } DISABLE_INTR (flags); gus_select_voice (chn); gus_voice_freq (speed); if (gus_sampling_channels == 1) gus_voice_balance (7); /* mono */ else if (chn == 0) gus_voice_balance (0); /* left */ else gus_voice_balance (15); /* right */ if (!pcm_active) /* Playback not already active */ { /* * 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 (); 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 */ if (chn != 0) gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, is16bits); /* Loop end location */ } if (chn == 0) gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1, is16bits); /* Loop end location */ else mode[chn] |= 0x08; /* Enable looping */ if (pcm_datasize[this_one] != pcm_bsize) { /* * Incompletely filled block. Possibly the last one. */ if (chn == 0) { mode[chn] &= ~0x08; /* Disable looping */ mode[chn] |= 0x20; /* Enable IRQ at the end */ 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 looping */ } } 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 voidgus_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 (gus_devnum, buf + (chn * count), count, DMA_MODE_WRITE); address = this_one * pcm_bsize; address += chn * pcm_banksize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -