📄 awe_wave.c
字号:
addr = 0; if (FX_ON(voice, hi)) { addr = (short)voices[voice].fx[hi]; addr = addr << 15; } if (FX_ON(voice, lo)) addr += (short)voices[voice].fx[lo]; if (!(vp->mode & (AWE_SAMPLE_8BITS<<6))) addr /= 2; return addr;}/* converter function table for realtime paramter change */typedef void (*fx_affect_func)(int voice);static fx_affect_func fx_realtime[] = { /* env1: delay, attack, hold, decay, release, sustain, pitch, cutoff*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* env2: delay, attack, hold, decay, release, sustain */ NULL, NULL, NULL, NULL, NULL, NULL, /* lfo1: delay, freq, volume, pitch, cutoff */ NULL, awe_fx_tremfrq, awe_fx_tremfrq, awe_fx_fmmod, awe_fx_fmmod, /* lfo2: delay, freq, pitch */ NULL, awe_fx_fm2frq2, awe_fx_fm2frq2, /* global: initpitch, chorus, reverb, cutoff, filterQ */ awe_fx_initpitch, NULL, NULL, awe_fx_cutoff, NULL, /* sample: start, loopstart, loopend */ NULL, NULL, NULL,};/*================================================================ * turn on/off sample *================================================================*/static voidawe_note_on(int voice){ unsigned long temp; long addr; unsigned short tmp2; awe_voice_info *vp; /* A voice sample must assigned before calling */ if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; /* channel to be silent and idle */ awe_poke(AWE_DCYSUSV(voice), 0x0080); awe_poke(AWE_VTFT(voice), 0); awe_poke(AWE_CVCF(voice), 0); awe_poke(AWE_PTRX(voice), 0); awe_poke(AWE_CPF(voice), 0); /* modulation & volume envelope */ awe_poke(AWE_ENVVAL(voice), FX_WORD(voice, AWE_FX_ENV1_DELAY, vp->parm.moddelay)); awe_poke(AWE_ATKHLD(voice), FX_COMB(voice, AWE_FX_ENV1_ATTACK, AWE_FX_ENV1_HOLD, vp->parm.modatkhld)); awe_poke(AWE_DCYSUS(voice), FX_COMB(voice, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY, vp->parm.moddcysus)); awe_poke(AWE_ENVVOL(voice), FX_WORD(voice, AWE_FX_ENV2_DELAY, vp->parm.voldelay)); awe_poke(AWE_ATKHLDV(voice), FX_COMB(voice, AWE_FX_ENV2_ATTACK, AWE_FX_ENV2_HOLD, vp->parm.volatkhld)); /* decay/sustain parameter for volume envelope must be set at last */ /* pitch offset */ awe_poke(AWE_IP(voice), voices[voice].apitch); DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch)); /* cutoff and volume */ tmp2 = FX_BYTE(voice, AWE_FX_CUTOFF, vp->parm.cutoff); tmp2 = (tmp2 << 8) | voices[voice].avol; awe_poke(AWE_IFATN(voice), tmp2); /* modulation envelope heights */ awe_poke(AWE_PEFE(voice), FX_COMB(voice, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF, vp->parm.pefe)); /* lfo1/2 delay */ awe_poke(AWE_LFO1VAL(voice), FX_WORD(voice, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay)); awe_poke(AWE_LFO2VAL(voice), FX_WORD(voice, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay)); /* lfo1 pitch & cutoff shift */ awe_poke(AWE_FMMOD(voice), FX_COMB(voice, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF, vp->parm.fmmod)); /* lfo1 volume & freq */ awe_poke(AWE_TREMFRQ(voice), FX_COMB(voice, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ, vp->parm.tremfrq)); /* lfo2 pitch & freq */ awe_poke(AWE_FM2FRQ2(voice), FX_COMB(voice, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ, vp->parm.fm2frq2)); /* pan & loop start */ awe_set_pan(voice, 1); /* chorus & loop end (chorus 8bit, MSB) */ addr = vp->loopend - 1; addr += FX_OFFSET(voice, AWE_FX_LOOP_END, AWE_FX_COARSE_LOOP_END); temp = FX_BYTE(voice, AWE_FX_CHORUS, vp->parm.chorus); temp = (temp <<24) | (unsigned long)addr; awe_poke_dw(AWE_CSL(voice), temp); /* Q & current address (Q 4bit value, MSB) */ addr = vp->start - 1; addr += FX_OFFSET(voice, AWE_FX_SAMPLE_START, AWE_FX_COARSE_SAMPLE_START); temp = FX_BYTE(voice, AWE_FX_FILTERQ, vp->parm.filterQ); temp = (temp<<28) | (unsigned long)addr; awe_poke_dw(AWE_CCCA(voice), temp); /* reset volume */ awe_poke_dw(AWE_VTFT(voice), 0x0000FFFF); awe_poke_dw(AWE_CVCF(voice), 0x0000FFFF); /* turn on envelope */ awe_poke(AWE_DCYSUSV(voice), FX_COMB(voice, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY, vp->parm.voldcysus)); /* set chorus */ temp = FX_BYTE(voice, AWE_FX_REVERB, vp->parm.reverb); temp = (awe_peek_dw(AWE_PTRX(voice)) & 0xffff0000) | (temp<<8); awe_poke_dw(AWE_PTRX(voice), temp); awe_poke_dw(AWE_CPF(voice), 0x40000000); DEBUG(3,printk("AWE32: [-- start=%x loop=%x]\n", (int)vp->start, (int)vp->loopstart));}/* turn off the voice */static voidawe_note_off(int voice){ awe_voice_info *vp; unsigned short tmp; if ((vp = voices[voice].sample) == NULL || !voices[voice].state) return; if (FX_ON(voice, AWE_FX_ENV1_RELEASE)) tmp = 0x8000 | voices[voice].fx[AWE_FX_ENV1_RELEASE]; else tmp = vp->parm.modrelease; awe_poke(AWE_DCYSUS(voice), tmp); if (FX_ON(voice, AWE_FX_ENV2_RELEASE)) tmp = 0x8000 | voices[voice].fx[AWE_FX_ENV2_RELEASE]; else tmp = vp->parm.volrelease; awe_poke(AWE_DCYSUSV(voice), tmp);}/* force to terminate the voice (no releasing echo) */static voidawe_terminate(int voice){ awe_poke(AWE_DCYSUSV(voice), 0x807F);}/* turn off other voices with the same exclusive class (for drums) */static voidawe_exclusive_off(int voice){ int i, excls; if (voices[voice].sample == NULL) /* no sample */ return; excls = voices[voice].sample->exclusiveClass; if (excls == 0) /* not exclusive */ return; /* turn off voices with the same class */ for (i = 0; i < awe_max_voices; i++) { if (i != voice && voices[voice].state && voices[i].sample && voices[i].sample->exclusiveClass == excls) { DEBUG(4,printk("AWE32: [exoff(%d)]\n", i)); awe_note_off(i); awe_voice_init(i, 1); } }}/*================================================================ * change the parameters of an audible voice *================================================================*//* change pitch */static voidawe_set_pitch(int voice){ if (!voices[voice].state) return; awe_poke(AWE_IP(voice), voices[voice].apitch);}/* change volume */static voidawe_set_volume(int voice){ awe_voice_info *vp; unsigned short tmp2; if (!voices[voice].state) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; tmp2 = FX_BYTE(voice, AWE_FX_CUTOFF, vp->parm.cutoff); tmp2 = (tmp2 << 8) | voices[voice].avol; awe_poke(AWE_IFATN(voice), tmp2);}/* change pan; this could make a click noise.. */static voidawe_set_pan(int voice, int forced){ unsigned long temp; long addr; awe_voice_info *vp; if (!voices[voice].state && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */ if (vp->fixpan > 0) /* 0-127 */ temp = 255 - (int)vp->fixpan * 2; else { int pos = 0; if (vp->pan >= 0) /* 0-127 */ pos = (int)vp->pan * 2 - 128; pos += voices[voice].panning; /* -128 - 127 */ pos = 127 - pos; if (pos < 0) temp = 0; else if (pos > 255) temp = 255; else temp = pos; } addr = vp->loopstart - 1; addr += FX_OFFSET(voice, AWE_FX_LOOP_START, AWE_FX_COARSE_LOOP_START); temp = (temp<<24) | (unsigned long)addr; awe_poke_dw(AWE_PSST(voice), temp);}/* effects change during playing */static voidawe_fx_fmmod(int voice){ awe_voice_info *vp; if (!voices[voice].state) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; awe_poke(AWE_FMMOD(voice), FX_COMB(voice, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF, vp->parm.fmmod));}static voidawe_fx_tremfrq(int voice){ awe_voice_info *vp; if (!voices[voice].state) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; awe_poke(AWE_TREMFRQ(voice), FX_COMB(voice, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ, vp->parm.tremfrq));}static voidawe_fx_fm2frq2(int voice){ awe_voice_info *vp; if (!voices[voice].state) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; awe_poke(AWE_FM2FRQ2(voice), FX_COMB(voice, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ, vp->parm.fm2frq2));}static voidawe_fx_cutoff(int voice){ unsigned short tmp2; awe_voice_info *vp; if (!voices[voice].state) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; tmp2 = FX_BYTE(voice, AWE_FX_CUTOFF, vp->parm.cutoff); tmp2 = (tmp2 << 8) | voices[voice].avol; awe_poke(AWE_IFATN(voice), tmp2);}static voidawe_fx_initpitch(int voice){ if (!voices[voice].state) return; if (FX_ON(voice, AWE_FX_INIT_PITCH)) { DEBUG(3,printk("AWE32: initpitch ok\n")); } else { DEBUG(3,printk("AWE32: BAD initpitch %d\n", AWE_FX_INIT_PITCH)); } awe_calc_pitch(voice); awe_poke(AWE_IP(voice), voices[voice].apitch);}/*================================================================ * calculate pitch offset *---------------------------------------------------------------- * 0xE000 is no pitch offset at 44100Hz sample. * Every 4096 is one octave. *================================================================*/static voidawe_calc_pitch(int voice){ voice_info *vp = &voices[voice]; awe_voice_info *ap; int offset; /* search voice information */ if ((ap = vp->sample) == NULL) return; if (ap->index < 0) { if (awe_set_sample(ap) < 0) return; } /* calculate offset */ if (ap->fixkey >= 0) { DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune)); offset = (ap->fixkey - ap->root) * 4096 / 12; } else { DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune)); offset = (vp->note - ap->root) * 4096 / 12; DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset)); } offset += ap->tune * 4096 / 1200; DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset)); if (vp->bender != 0) { DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, vp->bender)); /* (819200: 1 semitone) ==> (4096: 12 semitones) */ offset += vp->bender * vp->bender_range / 2400; } offset = (offset * ap->scaleTuning) / 100; DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset)); /* add initial pitch correction */ if (FX_ON(voice, AWE_FX_INIT_PITCH)) { DEBUG(3,printk("AWE32: fx_pitch(%d) %d\n", voice, vp->fx[AWE_FX_INIT_PITCH])); offset += vp->fx[AWE_FX_INIT_PITCH]; } /* 0xe000: root pitch */ vp->apitch = 0xe000 + ap->rate_offset + offset; DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset)); if (vp->apitch > 0xffff) vp->apitch = 0xffff; if (vp->apitch < 0) vp->apitch = 0;}static voidawe_calc_pitch_from_freq(int voice, int freq){ voice_info *vp = &voices[voice]; awe_voice_info *ap; int offset; int note; /* search voice information */ if ((ap = vp->sample) == NULL) return; if (ap->index < 0) { if (awe_set_sample(ap) < 0) return; } note = freq_to_note(freq); offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200; offset = (offset * ap->scaleTuning) / 100; if (FX_ON(voice, AWE_FX_INIT_PITCH)) offset += vp->fx[AWE_FX_INIT_PITCH]; vp->apitch = 0xe000 + ap->rate_offset + offset; if (vp->apitch > 0xffff) vp->apitch = 0xffff; if (vp->apitch < 0) vp->apitch = 0;}/*================================================================ * calculate volume attenuation *---------------------------------------------------------------- * Voice volume is controlled by volume attenuation parameter. * So volume becomes maximum when avol is 0 (no attenuation), and * minimum when 255 (-96dB or silence). *================================================================*/static int vol_table[128] = { 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49, 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32, 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22, 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16, 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10, 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6, 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3, 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,};static voidawe_calc_volume(int voice){ voice_info *vp = &voices[voice]; awe_voice_info *ap; int vol; /* search voice information */ if ((ap = vp->sample) == NULL) return; ap = vp->sample; if (ap->index < 0) { if (awe_set_sample(ap) < 0) return; } if (vp->velocity < ap->vellow) vp->velocity = ap->vellow; else if (vp->velocity > ap->velhigh) vp->velocity = ap->velhigh; /* 0 - 127 */ vol = (vp->velocity * vp->main_vol * vp->expression_vol) / (127*127); vol = vol * ap->amplitude / 127; if (vol < 0) vol = 0; if (vol > 127) vol = 127; /* calc to attenuation */ vol = vol_table[vol]; vol = vol + (int)ap->attenuation + init_atten; if (vol > 255) vol = 255; vp->avol = vol; DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));}/*================================================================ * synth operation routines *================================================================*//* initialize the voice */static voidawe_voice_init(int voice, int inst_only){ if (! inst_only) { /* clear voice parameters */ voices[voice].note = -1; voices[voice].velocity = 0; voices[voice].panning = 0; /* zero center */ voices[voice].bender = 0; /* zero tune skew */ voices[voice].bender_range = 200; /* sense * 100 */ voices[voice].main_vol = 127; voices[voice].expression_vol = 127; voices[voice].bank = AWE_DEFAULT_BANK; voices[voice].instr = -1; voices[voice].vrec = NULL; voices[voice].sample = NULL; } /* clear voice mapping */ voices[voice].state = 0; voice_alloc->map[voice] = 0; /* emu8000 parameters */ voices[voice].apitch = 0; voices[voice].avol = 255; /* clear effects */ BZERO(voices[voice].fx_flags, sizeof(voices[voice].fx_flags));}/*---------------------------------------------------------------- * device open / close *----------------------------------------------------------------*//* open device:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -