📄 trident_synth.c
字号:
voice->Delta = (((freq << 12) + freq) / 48000) & 0x0000ffff; outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); if (trident->device == TRIDENT_DEVICE_ID_NX) { outb((unsigned char) voice->Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3)); outb((unsigned char) (voice->Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3)); } else { outw((unsigned short) voice->Delta, TRID_REG(trident, CH_DX_ESO_DELTA)); } spin_unlock_irqrestore(&trident->reg_lock, flags);}static void sample_volume(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_volume_t * volume){ unsigned long flags; unsigned short value; spin_lock_irqsave(&trident->reg_lock, flags); voice->GVSel = 0; /* use global music volume */ voice->FMC = 0x03; /* fixme: can we do something useful with FMC? */ if (volume->volume >= 0) { volume->volume &= 0x3fff; /* linear volume -> logarithmic attenuation conversion * uses EC register for greater resolution (6.6 bits) than Vol register (5.3 bits) * Vol register used when additional attenuation is required */ voice->RVol = 0; voice->CVol = 0; value = log_from_linear( volume->volume ); voice->Vol = 0; voice->EC = (value & 0x3fff) >> 2; if (value > 0x3fff) { voice->EC |= 0xfc0; if (value < 0x5f00 ) voice->Vol = ((value >> 8) - 0x3f) << 5; else { voice->Vol = 0x3ff; voice->EC = 0xfff; } } } if (volume->lr >= 0) { volume->lr &= 0x3fff; /* approximate linear pan by attenuating channels */ if (volume->lr >= 0x2000) { /* attenuate left (pan right) */ value = 0x3fff - volume->lr; for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) if (value >= pan_table[voice->Pan] ) break; } else { /* attenuate right (pan left) */ for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) if ((unsigned int)volume->lr >= pan_table[voice->Pan] ) break; voice->Pan |= 0x40; } } outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); outl((voice->GVSel << 31) | ((voice->Pan & 0x0000007f) << 24) | ((voice->Vol & 0x000000ff) << 16) | ((voice->CTRL & 0x0000000f) << 12) | (voice->EC & 0x00000fff), TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC)); value = ((voice->FMC & 0x03) << 14) | ((voice->RVol & 0x7f) << 7) | (voice->CVol & 0x7f); outw(value, TRID_REG(trident, CH_DX_FMC_RVOL_CVOL)); spin_unlock_irqrestore(&trident->reg_lock, flags);}static void sample_loop(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_loop_t * loop){ unsigned long flags; simple_instrument_t *simple; snd_seq_kinstr_t *instr; unsigned int loop_start, loop_end; instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); if (instr == NULL) return; voice->instr = instr->instr; /* copy ID to speedup aliases */ simple = KINSTR_DATA(instr); loop_start = loop->start >> 4; loop_end = loop->end >> 4; spin_lock_irqsave(&trident->reg_lock, flags); voice->LBA = simple->address.memory + loop_start; voice->CSO = 0; voice->ESO = loop_end - loop_start - 1; outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); outb((voice->LBA >> 16), TRID_REG(trident, CH_LBA + 2)); outw((voice->LBA & 0xffff), TRID_REG(trident, CH_LBA)); if (trident->device == TRIDENT_DEVICE_ID_NX) { outb((voice->ESO >> 16), TRID_REG(trident, CH_NX_DELTA_ESO + 2)); outw((voice->ESO & 0xffff), TRID_REG(trident, CH_NX_DELTA_ESO)); outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); } else { outw((voice->ESO & 0xffff), TRID_REG(trident, CH_DX_ESO_DELTA + 2)); outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2)); } spin_unlock_irqrestore(&trident->reg_lock, flags); snd_seq_instr_free_use(trident->synth.ilist, instr);}static void sample_pos(trident_t * trident, snd_trident_voice_t * voice, snd_seq_position_t position){ unsigned long flags; simple_instrument_t *simple; snd_seq_kinstr_t *instr; unsigned int value; instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); if (instr == NULL) return; voice->instr = instr->instr; /* copy ID to speedup aliases */ simple = KINSTR_DATA(instr); spin_lock_irqsave(&trident->reg_lock, flags); if (simple->format & SIMPLE_WAVE_LOOP) { if( position >= simple->loop_start ) { voice->CSO = (position - simple->loop_start) >> 4; voice->negCSO = 0; } else { voice->CSO = (simple->loop_start - position) >> 4; voice->negCSO = 1; } } else { voice->CSO = position >> 4; voice->negCSO = 0; } /* set CSO sign */ value = inl(TRID_REG(trident, T4D_SIGN_CSO_A)); if( voice->negCSO ) { value |= 1 << (voice->number&31); } else { value &= ~(1 << (voice->number&31)); } outl(value,TRID_REG(trident, T4D_SIGN_CSO_A)); outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); if (trident->device == TRIDENT_DEVICE_ID_NX) { outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); } else { outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2); } spin_unlock_irqrestore(&trident->reg_lock, flags); snd_seq_instr_free_use(trident->synth.ilist, instr);}static void sample_private1(trident_t * trident, snd_trident_voice_t * voice, unsigned char *data){}/* * Memory management / sample loading */static int snd_trident_simple_put_sample(void *private_data, simple_instrument_t * instr, char __user *data, long len, int atomic){ trident_t *trident = private_data; int size = instr->size; int shift = 0; if (instr->format & SIMPLE_WAVE_BACKWARD || instr->format & SIMPLE_WAVE_BIDIR || instr->format & SIMPLE_WAVE_ULAW) return -EINVAL; /* not supported */ if (instr->format & SIMPLE_WAVE_16BIT) shift++; if (instr->format & SIMPLE_WAVE_STEREO) shift++; size <<= shift; if (trident->synth.current_size + size > trident->synth.max_size) return -ENOMEM; if (!access_ok(VERIFY_READ, data, size)) return -EFAULT; if (trident->tlb.entries) { snd_util_memblk_t *memblk; memblk = snd_trident_synth_alloc(trident, size); if (memblk == NULL) return -ENOMEM; if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) { snd_trident_synth_free(trident, memblk); return -EFAULT; } instr->address.ptr = (unsigned char*)memblk; instr->address.memory = memblk->offset; } else { struct snd_dma_buffer dmab; if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), size, &dmab) < 0) return -ENOMEM; if (copy_from_user(dmab.area, data, size)) { snd_dma_free_pages(&dmab); return -EFAULT; } instr->address.ptr = dmab.area; instr->address.memory = dmab.addr; } trident->synth.current_size += size; return 0;}static int snd_trident_simple_get_sample(void *private_data, simple_instrument_t * instr, char __user *data, long len, int atomic){ //trident_t *trident = private_data; int size = instr->size; int shift = 0; if (instr->format & SIMPLE_WAVE_16BIT) shift++; if (instr->format & SIMPLE_WAVE_STEREO) shift++; size <<= shift; if (!access_ok(VERIFY_WRITE, data, size)) return -EFAULT; /* FIXME: not implemented yet */ return -EBUSY;}static int snd_trident_simple_remove_sample(void *private_data, simple_instrument_t * instr, int atomic){ trident_t *trident = private_data; int size = instr->size; if (instr->format & SIMPLE_WAVE_16BIT) size <<= 1; if (instr->format & SIMPLE_WAVE_STEREO) size <<= 1; if (trident->tlb.entries) { snd_util_memblk_t *memblk = (snd_util_memblk_t*)instr->address.ptr; if (memblk) snd_trident_synth_free(trident, memblk); else return -EFAULT; } else { struct snd_dma_buffer dmab; dmab.dev.type = SNDRV_DMA_TYPE_DEV; dmab.dev.dev = snd_dma_pci_data(trident->pci); dmab.area = instr->address.ptr; dmab.addr = instr->address.memory; dmab.bytes = size; snd_dma_free_pages(&dmab); } trident->synth.current_size -= size; if (trident->synth.current_size < 0) /* shouldn't need this check... */ trident->synth.current_size = 0; return 0;}static void select_instrument(trident_t * trident, snd_trident_voice_t * v){ snd_seq_kinstr_t *instr; instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1); if (instr != NULL) { if (instr->ops) { if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE)) snd_trident_simple_init(v); } snd_seq_instr_free_use(trident->synth.ilist, instr); }}/* */static void event_sample(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_stop) v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); v->instr.std = ev->data.sample.param.sample.std; if (v->instr.std & 0xff000000) { /* private instrument */ v->instr.std &= 0x00ffffff; v->instr.std |= (unsigned int)ev->source.client << 24; } v->instr.bank = ev->data.sample.param.sample.bank; v->instr.prg = ev->data.sample.param.sample.prg; select_instrument(p->trident, v);}static void event_cluster(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_stop) v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); v->instr.cluster = ev->data.sample.param.cluster.cluster; select_instrument(p->trident, v);}static void event_start(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_start) v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position);}static void event_stop(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_stop) v->sample_ops->sample_stop(p->trident, v, ev->data.sample.param.stop_mode);}static void event_freq(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_freq) v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency);}static void event_volume(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_volume) v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume);}static void event_loop(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_loop) v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop);}static void event_position(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v){ if (v->sample_ops && v->sample_ops->sample_pos) v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -