📄 awe_wave.c
字号:
* reset status of all voices, and clear sample position flag */static intawe_open(int dev, int mode){ if (awe_busy) return RET_ERROR(EBUSY); awe_busy = 1; awe_reset(dev); /* clear sample position flag */ loaded_once = 0; /* set GUS bank to default */ awe_gus_bank = AWE_DEFAULT_BANK; return 0;}/* close device: * reset all voices again (terminate sounds) */static voidawe_close(int dev){ awe_reset(dev); awe_busy = 0;}/* sequencer I/O control: */static intawe_ioctl(int dev, unsigned int cmd, caddr_t arg){ switch (cmd) { case SNDCTL_SYNTH_INFO: awe_info.nr_voices = awe_max_voices; IOCTL_TO_USER((char*)arg, 0, &awe_info, sizeof(awe_info)); return 0; break; case SNDCTL_SEQ_RESETSAMPLES: awe_reset_samples(); awe_reset(dev); /* better to reset emu8k chip... */ return 0; break; case SNDCTL_SEQ_PERCMODE: /* what's this? */ return 0; break; case SNDCTL_SYNTH_MEMAVL: DEBUG(0,printk("AWE32: [ioctl memavl = %d]\n", (int)free_mem_ptr)); return awe_mem_size - free_mem_ptr*2; default: ERRMSG(printk("AWE32: unsupported ioctl %d\n", cmd)); return RET_ERROR(EINVAL); }}/* kill a voice: * not terminate, just release the voice. */static intawe_kill_note(int dev, int voice, int note, int velocity){ awe_voice_info *vp; DECL_INTR_FLAGS(flags); DEBUG(2,printk("AWE32: [off(%d)]\n", voice)); if (voice < 0 || voice >= awe_max_voices) return RET_ERROR(EINVAL); if ((vp = voices[voice].sample) == NULL) return 0; if (!(vp->mode & AWE_MODE_NORELEASE)) { DISABLE_INTR(flags); awe_note_off(voice); RESTORE_INTR(flags); } awe_voice_init(voice, 1); return 0;}/* search the note with the specified key range */static awe_voice_info *awe_search_voice(int voice, int note){ awe_voice_list *rec; int maxc; for (rec = voices[voice].vrec, maxc = AWE_MAX_INFOS; rec && maxc; rec = rec->next_instr, maxc--) { if (rec->v.low <= note && note <= rec->v.high) return &rec->v; } return NULL;}/* start a voice: * if note is 255, identical with aftertouch function. * Otherwise, start a voice with specified not and volume. */static intawe_start_note(int dev, int v, int note_num, int volume){ DECL_INTR_FLAGS(flags); DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", v, note_num, volume)); if (v < 0 || v >= awe_max_voices) return RET_ERROR(EINVAL); /* an instrument must be set before starting a note */ if (voices[v].vrec == NULL) { DEBUG(1,printk("AWE32: [-- vrec is null]\n")); return 0; } if (note_num == 255) { /* dynamic volume change; sample is already assigned */ if (! voices[v].state || voices[v].sample == NULL) return 0; /* calculate volume parameter */ voices[v].velocity = volume; awe_calc_volume(v); DISABLE_INTR(flags); awe_set_volume(v); RESTORE_INTR(flags); return 0; } /* assign a sample with the corresponding note */ if ((voices[v].sample = awe_search_voice(v, note_num)) == NULL) { DEBUG(1,printk("AWE32: [-- sample is null]\n")); return 0; } /* calculate pitch & volume parameters */ voices[v].note = note_num; voices[v].velocity = volume; awe_calc_pitch(v); awe_calc_volume(v); DISABLE_INTR(flags); /* turn off other voices (for drums) */ awe_exclusive_off(v); /* turn on the voice */ awe_note_on(v); voices[v].state = 1; /* flag up */ RESTORE_INTR(flags); return 0;}/* search instrument from preset table with the specified bank */static awe_voice_list *awe_search_instr(int bank, int preset){ awe_voice_list *p; int maxc; for (maxc = AWE_MAX_INFOS, p = preset_table[preset]; p && maxc; p = p->next_bank, maxc--) { if (p->bank == bank) return p; } return NULL;}/* assign the instrument to a voice */static intawe_set_instr(int dev, int voice, int instr_no){ awe_voice_list *rec; if (voice < 0 || voice >= awe_max_voices) return RET_ERROR(EINVAL); if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS) return RET_ERROR(EINVAL); if ((rec = awe_search_instr(voices[voice].bank, instr_no)) == NULL) { /* if bank is not defined, use the default bank 0 */ if (voices[voice].bank != AWE_DEFAULT_BANK && (rec = awe_search_instr(AWE_DEFAULT_BANK, instr_no)) == NULL) { DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no)); return 0; } } voices[voice].instr = instr_no; voices[voice].vrec = rec; voices[voice].sample = NULL; /* not set yet */ return 0;}/* reset all voices; terminate sounds and initialize parameters */static voidawe_reset(int dev){ int i; /* don't turn off voice 31 and 32. they are used also for FM voices */ for (i = 0; i < AWE_NORMAL_VOICES; i++) { awe_terminate(i); awe_voice_init(i, 0); } awe_init_fm(); awe_tweak();}/* hardware specific control: * GUS specific and AWE32 specific controls are available. */static voidawe_hw_control(int dev, unsigned char *event){ int cmd = event[2]; if (cmd & _AWE_MODE_FLAG) awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event); else awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);}/* GUS compatible controls */static voidawe_hw_gus_control(int dev, int cmd, unsigned char *event){ int voice; unsigned short p1; short p2; int plong; DECL_INTR_FLAGS(flags); voice = event[3]; p1 = *(unsigned short *) &event[4]; p2 = *(short *) &event[6]; plong = *(int*) &event[4]; switch (cmd) { case _GUS_NUMVOICES: if (p1 >= awe_max_voices) printk("AWE32: num_voices: voices out of range %d\n", p1); break; case _GUS_VOICESAMPLE: if (voice < awe_max_voices) awe_set_instr(dev, voice, p1); break; case _GUS_VOICEON: if (voice < awe_max_voices) { DISABLE_INTR(flags); awe_note_on(voice); RESTORE_INTR(flags); } break; case _GUS_VOICEOFF: if (voice < awe_max_voices) { DISABLE_INTR(flags); awe_note_off(voice); RESTORE_INTR(flags); } break; case _GUS_VOICEMODE: /* not supported */ break; case _GUS_VOICEBALA: /* -128 to 127 */ if (voice < awe_max_voices) awe_panning(dev, voice, (short)p1); break; case _GUS_VOICEFREQ: if (voice < awe_max_voices) awe_calc_pitch_from_freq(voice, plong); break; case _GUS_VOICEVOL: case _GUS_VOICEVOL2: /* not supported yet */ break; case _GUS_RAMPRANGE: case _GUS_RAMPRATE: case _GUS_RAMPMODE: case _GUS_RAMPON: case _GUS_RAMPOFF: /* volume ramping not supported */ break; case _GUS_VOLUME_SCALE: break; case _GUS_VOICE_POS: if (voice < awe_max_voices) { FX_SET(voice, AWE_FX_SAMPLE_START, (short)(plong & 0x7fff)); FX_SET(voice, AWE_FX_COARSE_SAMPLE_START, (plong >> 15) & 0xffff); } break; }}/* AWE32 specific controls */static voidawe_hw_awe_control(int dev, int cmd, unsigned char *event){ int voice; unsigned short p1; short p2; int chn; chn = event[1]; voice = event[3]; p1 = *(unsigned short *) &event[4]; p2 = *(short *) &event[6]; #ifdef AWE_DEBUG_ON switch (cmd) { case _AWE_DEBUG_MODE: debug_mode = p1; printk("AWE32: debug mode = %d\n", debug_mode); break;#endif case _AWE_REVERB_MODE: if (p1 <= 7) { reverb_mode = p1; DEBUG(0,printk("AWE32: reverb mode %d\n", reverb_mode)); awe_set_reverb_mode(reverb_mode); } break; case _AWE_CHORUS_MODE: if (p1 <= 7) { chorus_mode = p1; DEBUG(0,printk("AWE32: chorus mode %d\n", chorus_mode)); awe_set_chorus_mode(chorus_mode); } break; case _AWE_REMOVE_LAST_SAMPLES: DEBUG(0,printk("AWE32: remove last samples\n")); awe_remove_samples(); break; case _AWE_INITIALIZE_CHIP: awe_initialize(); break; case _AWE_SEND_EFFECT: if (voice < awe_max_voices && p1 < AWE_FX_END) { FX_SET(voice, p1, p2); DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, voices[voice].fx[p1])); if (fx_realtime[p1]) { DEBUG(0,printk("AWE32: fx_realtime (%d)\n", voice)); fx_realtime[p1](voice); } } break; case _AWE_TERMINATE_CHANNEL: if (voice < awe_max_voices) { DEBUG(0,printk("AWE32: terminate (%d)\n", voice)); awe_terminate(voice); awe_voice_init(voice, 1); } break; case _AWE_TERMINATE_ALL: DEBUG(0,printk("AWE32: terminate all\n")); awe_reset(0); break; case _AWE_INITIAL_VOLUME: DEBUG(0,printk("AWE32: init attenuation %d\n", p1)); init_atten = p1; break; case _AWE_SET_GUS_BANK: DEBUG(0,printk("AWE32: set gus bank %d\n", p1)); awe_gus_bank = p1; break; default: DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice)); break; }}/*---------------------------------------------------------------- * load a sound patch: * three types of patches are accepted: AWE, GUS, and SYSEX. *----------------------------------------------------------------*/static intawe_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag){ awe_patch_info patch; int rc = 0; if (format == GUS_PATCH) { return awe_load_guspatch(addr, offs, count, pmgr_flag); } else if (format == SYSEX_PATCH) { /* no system exclusive message supported yet */ return 0; } else if (format != AWE_PATCH) { FATALERR(printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format)); return RET_ERROR(EINVAL); } if (count < sizeof(awe_patch_info)) { FATALERR(printk("AWE32 Error: Patch header too short\n")); return RET_ERROR(EINVAL); } COPY_FROM_USER(((char*)&patch) + offs, addr, offs, sizeof(awe_patch_info) - offs); count -= sizeof(awe_patch_info); if (count < patch.len) { FATALERR(printk("AWE32 Warning: Patch record too short (%d<%d)\n", count, (int)patch.len)); patch.len = count; } switch (patch.type) { case AWE_LOAD_INFO: rc = awe_load_info(&patch, addr); break; case AWE_LOAD_DATA: rc = awe_load_data(&patch, addr); /* if (!pmgr_flag && rc == 0) pmgr_inform(dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); */ break; default: FATALERR(printk("AWE32 Error: unknown patch format type %d\n", patch.type)); rc = RET_ERROR(EINVAL); } return rc;}/* load voice information data */static intawe_load_info(awe_patch_info *patch, const char *addr){ awe_voice_list *rec, *curp; long offset; short i, nvoices; unsigned char bank, instr; int total_size; if (patch->len < sizeof(awe_voice_rec)) { FATALERR(printk("AWE32 Error: invalid patch info length\n")); return RET_ERROR(EINVAL); } offset = sizeof(awe_patch_info); GET_BYTE_FROM_USER(bank, addr, offset); offset++; GET_BYTE_FROM_USER(instr, addr, offset); offset++; GET_SHORT_FROM_USER(nvoices, addr, offset); offset+=2; if (nvoices <= 0 || nvoices >= 100) { FATALERR(printk("AWE32 Error: Illegal voice number %d\n", nvoices)); return RET_ERROR(EINVAL); } if (free_info + nvoices > AWE_MAX_INFOS) { ERRMSG(printk("AWE32 Error: Too many voice informations\n")); return RET_ERROR(ENOSPC); } total_size = sizeof(awe_voice_rec) + sizeof(awe_voice_info) * nvoices; if (patch->len < total_size) { ERRMSG(printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n", (int)patch->len, nvoices)); return RET_ERROR(EINVAL); } curp = awe_search_instr(bank, instr); for (i = 0; i < nvoices; i++) { rec = &infos[free_info + i]; rec->bank = bank;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -