📄 wavfront.c
字号:
i=0; while(n>=32*256) { n>>=8; i+=2048*8; } while(n>=32) { n>>=1; i+=2048; } i+=tbl[n]; return(i);}static intwavefront_load_gus_patch (int devno, int format, const char *addr, int offs, int count, int pmgr_flag){ struct patch_info guspatch; wavefront_patch_info samp, pat, prog; wavefront_patch *patp; wavefront_sample *sampp; wavefront_program *progp; int i,base_note; long sizeof_patch; /* Copy in the header of the GUS patch */ sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; copy_from_user (&((char *) &guspatch)[offs], &(addr)[offs], sizeof_patch - offs); if ((i = wavefront_find_free_patch ()) == -1) { return -EBUSY; } pat.number = i; pat.subkey = WF_ST_PATCH; patp = &pat.hdr.p; if ((i = wavefront_find_free_sample ()) == -1) { return -EBUSY; } samp.number = i; samp.subkey = WF_ST_SAMPLE; samp.size = guspatch.len; sampp = &samp.hdr.s; prog.number = guspatch.instr_no; progp = &prog.hdr.pr; /* Setup the patch structure */ patp->amplitude_bias=guspatch.volume; patp->portamento=0; patp->sample_number= samp.number & 0xff; patp->sample_msb= samp.number>>8; patp->pitch_bend= /*12*/ 0; patp->mono=1; patp->retrigger=1; patp->nohold=(guspatch.mode & WAVE_SUSTAIN_ON) ? 0:1; patp->frequency_bias=0; patp->restart=0; patp->reuse=0; patp->reset_lfo=1; patp->fm_src2=0; patp->fm_src1=WF_MOD_MOD_WHEEL; patp->am_src=WF_MOD_PRESSURE; patp->am_amount=127; patp->fc1_mod_amount=0; patp->fc2_mod_amount=0; patp->fm_amount1=0; patp->fm_amount2=0; patp->envelope1.attack_level=127; patp->envelope1.decay1_level=127; patp->envelope1.decay2_level=127; patp->envelope1.sustain_level=127; patp->envelope1.release_level=0; patp->envelope2.attack_velocity=127; patp->envelope2.attack_level=127; patp->envelope2.decay1_level=127; patp->envelope2.decay2_level=127; patp->envelope2.sustain_level=127; patp->envelope2.release_level=0; patp->envelope2.attack_velocity=127; patp->randomizer=0; /* Program for this patch */ progp->layer[0].patch_number= pat.number; /* XXX is this right ? */ progp->layer[0].mute=1; progp->layer[0].pan_or_mod=1; progp->layer[0].pan=7; progp->layer[0].mix_level=127 /* guspatch.volume */; progp->layer[0].split_type=0; progp->layer[0].split_point=0; progp->layer[0].play_below=0; for (i = 1; i < 4; i++) { progp->layer[i].mute=0; } /* Sample data */ sampp->SampleResolution=((~guspatch.mode & WAVE_16_BITS)<<1); for (base_note=0; note_to_freq (base_note) < guspatch.base_note; base_note++); if ((guspatch.base_note-note_to_freq(base_note)) >(note_to_freq(base_note)-guspatch.base_note)) base_note++; printk(KERN_DEBUG "ref freq=%d,base note=%d\n", guspatch.base_freq, base_note); sampp->FrequencyBias = (29550 - log2_2048(guspatch.base_freq) + base_note*171); printk(KERN_DEBUG "Freq Bias is %d\n", sampp->FrequencyBias); sampp->Loop=(guspatch.mode & WAVE_LOOPING) ? 1:0; sampp->sampleStartOffset.Fraction=0; sampp->sampleStartOffset.Integer=0; sampp->loopStartOffset.Fraction=0; sampp->loopStartOffset.Integer=guspatch.loop_start >>((guspatch.mode&WAVE_16_BITS) ? 1:0); sampp->loopEndOffset.Fraction=0; sampp->loopEndOffset.Integer=guspatch.loop_end >>((guspatch.mode&WAVE_16_BITS) ? 1:0); sampp->sampleEndOffset.Fraction=0; sampp->sampleEndOffset.Integer=guspatch.len >> (guspatch.mode&1); sampp->Bidirectional=(guspatch.mode&WAVE_BIDIR_LOOP) ? 1:0; sampp->Reverse=(guspatch.mode&WAVE_LOOP_BACK) ? 1:0; /* Now ship it down */ wavefront_send_sample (&samp, (unsigned short *) &(addr)[sizeof_patch], (guspatch.mode & WAVE_UNSIGNED) ? 1:0); wavefront_send_patch (&pat); wavefront_send_program (&prog); /* Now pan as best we can ... use the slave/internal MIDI device number if it exists (since it talks to the WaveFront), or the master otherwise. */ if (dev.mididev > 0) { midi_synth_controller (dev.mididev, guspatch.instr_no, 10, ((guspatch.panning << 4) > 127) ? 127 : (guspatch.panning << 4)); } return(0);}static intwavefront_load_patch (const char *addr){ wavefront_patch_info header; if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) - sizeof(wavefront_any))) { printk (KERN_WARNING LOGNAME "bad address for load patch.\n"); return -(EINVAL); } DPRINT (WF_DEBUG_LOAD_PATCH, "download " "Sample type: %d " "Sample number: %d " "Sample size: %d\n", header.subkey, header.number, header.size); switch (header.subkey) { case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ copy_from_user ((unsigned char *) &header.hdr.s, (unsigned char *) header.hdrptr, sizeof (wavefront_sample)); return wavefront_send_sample (&header, header.dataptr, 0); case WF_ST_MULTISAMPLE: copy_from_user ((unsigned char *) &header.hdr.s, (unsigned char *) header.hdrptr, sizeof (wavefront_multisample)); return wavefront_send_multisample (&header); case WF_ST_ALIAS: copy_from_user ((unsigned char *) &header.hdr.a, (unsigned char *) header.hdrptr, sizeof (wavefront_alias)); return wavefront_send_alias (&header); case WF_ST_DRUM: copy_from_user ((unsigned char *) &header.hdr.d, (unsigned char *) header.hdrptr, sizeof (wavefront_drum)); return wavefront_send_drum (&header); case WF_ST_PATCH: copy_from_user ((unsigned char *) &header.hdr.p, (unsigned char *) header.hdrptr, sizeof (wavefront_patch)); return wavefront_send_patch (&header); case WF_ST_PROGRAM: copy_from_user ((unsigned char *) &header.hdr.pr, (unsigned char *) header.hdrptr, sizeof (wavefront_program)); return wavefront_send_program (&header); default: printk (KERN_ERR LOGNAME "unknown patch type %d.\n", header.subkey); return -(EINVAL); } return 0;}/***********************************************************************WaveFront: /dev/sequencer{,2} and other hardware-dependent interfaces***********************************************************************/static voidprocess_sample_hdr (UCHAR8 *buf){ wavefront_sample s; UCHAR8 *ptr; ptr = buf; /* The board doesn't send us an exact copy of a "wavefront_sample" in response to an Upload Sample Header command. Instead, we have to convert the data format back into our data structure, just as in the Download Sample command, where we have to do something very similar in the reverse direction. */ *((UINT32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4; *((UINT32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4; *((UINT32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4; *((UINT32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4; *((UINT32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3; s.SampleResolution = *ptr & 0x3; s.Loop = *ptr & 0x8; s.Bidirectional = *ptr & 0x10; s.Reverse = *ptr & 0x40; /* Now copy it back to where it came from */ memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample));}static intwavefront_synth_control (int cmd, wavefront_control *wc){ unsigned char patchnumbuf[2]; int i; DPRINT (WF_DEBUG_CMD, "synth control with " "cmd 0x%x\n", wc->cmd); /* Pre-handling of or for various commands */ switch (wc->cmd) { case WFC_DISABLE_INTERRUPTS: printk (KERN_INFO LOGNAME "interrupts disabled.\n"); outb (0x80|0x20, dev.control_port); dev.interrupts_on = 0; return 0; case WFC_ENABLE_INTERRUPTS: printk (KERN_INFO LOGNAME "interrupts enabled.\n"); outb (0x80|0x40|0x20, dev.control_port); dev.interrupts_on = 1; return 0; case WFC_INTERRUPT_STATUS: wc->rbuf[0] = dev.interrupts_on; return 0; case WFC_ROMSAMPLES_RDONLY: dev.rom_samples_rdonly = wc->wbuf[0]; wc->status = 0; return 0; case WFC_IDENTIFY_SLOT_TYPE: i = wc->wbuf[0] | (wc->wbuf[1] << 7); if (i <0 || i >= WF_MAX_SAMPLE) { printk (KERN_WARNING LOGNAME "invalid slot ID %d\n", i); wc->status = EINVAL; return 0; } wc->rbuf[0] = dev.sample_status[i]; wc->status = 0; return 0; case WFC_DEBUG_DRIVER: dev.debug = wc->wbuf[0]; printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug); return 0; case WFC_FX_IOCTL: wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]); return 0; case WFC_UPLOAD_PATCH: munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2); memcpy (wc->wbuf, patchnumbuf, 2); break; case WFC_UPLOAD_MULTISAMPLE: /* multisamples have to be handled differently, and cannot be dealt with properly by wavefront_cmd() alone. */ wc->status = wavefront_fetch_multisample ((wavefront_patch_info *) wc->rbuf); return 0; case WFC_UPLOAD_SAMPLE_ALIAS: printk (KERN_INFO LOGNAME "support for sample alias upload " "being considered.\n"); wc->status = EINVAL; return -EINVAL; } wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf); /* Post-handling of certain commands. In particular, if the command was an upload, demunge the data so that the user-level doesn't have to think about it. */ if (wc->status == 0) { switch (wc->cmd) { /* intercept any freemem requests so that we know we are always current with the user-level view of things. */ case WFC_REPORT_FREE_MEMORY: dev.freemem = demunge_int32 (wc->rbuf, 4); break; case WFC_UPLOAD_PATCH: demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); break; case WFC_UPLOAD_PROGRAM: demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); break; case WFC_UPLOAD_EDRUM_PROGRAM: demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); break; case WFC_UPLOAD_SAMPLE_HEADER: process_sample_hdr (wc->rbuf); break; case WFC_UPLOAD_SAMPLE_ALIAS: printk (KERN_INFO LOGNAME "support for " "sample aliases still " "being considered.\n"); break; case WFC_VMIDI_OFF: if (virtual_midi_disable () < 0) { return -(EIO); } break; case WFC_VMIDI_ON: if (virtual_midi_enable () < 0) { return -(EIO); } break; } } return 0;}/***********************************************************************//* WaveFront: Linux file system interface (for access via raw synth) *//***********************************************************************/static loff_twavefront_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}static int wavefront_open (struct inode *inode, struct file *file){ /* XXX fix me */ dev.opened = file->f_flags; return 0;}static intwavefront_release(struct inode *inode, struct file *file){ lock_kernel(); dev.opened = 0; dev.debug = 0; unlock_kernel(); return 0;}static intwavefront_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ wavefront_control wc; int err; switch (cmd) { case WFCTL_WFCMD: copy_from_user (&wc, (void *) arg, sizeof (wc)); if ((err = wavefront_synth_control (cmd, &wc)) == 0) { copy_to_user ((void *) arg, &wc, sizeof (wc)); } return err; case WFCTL_LOAD_SPP: return wavefront_load_patch ((const char *) arg); default: printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd); return -(EINVAL); } return 0;}static /*const*/ struct file_operations wavefront_fops = { owner: THIS_MODULE, llseek: wavefront_llseek, ioctl: wavefront_ioctl, open: wavefront_open, release: wavefront_release,};/***********************************************************************//* WaveFront: OSS installation and support interface *//***********************************************************************/#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQstatic struct synth_info wavefront_info ={"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT, 0, 32, 0, 0, SYNTH_CAP_INPUT};static intwavefront_oss_open (int devno, int mode){ dev.opened = mode; return 0;}static voidwavefront_oss_close (int devno){ dev.opened = 0; dev.debug = 0; return;}static intwavefront_oss_ioctl (int devno, unsigned int cmd, caddr_t arg){ wavefront_control wc; int err; switch (cmd) { case SNDCTL_SYNTH_INFO: memcpy (&((char *) arg)[0], &wavefront_info, sizeof (wavefront_info)); return 0; break; case SNDCTL_SEQ_RESETSAMPLES: printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n"); return 0; /* don't force an error */ break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -