/* * Ensure a value is between two points * macro evaluates its args more than once, so changed to upper-case.
*/ #define LIMITVALUE(x, a, b) do { if ((x) < (a)) (x) = (a); elseif ((x) > (b)) (x) = (b); } while (0) #define LIMITMAX(x, a) do {if ((x) > (a)) (x) = (a); } while (0)
hw = vp->hw; if (update & SNDRV_EMUX_UPDATE_VOLUME)
set_volume(hw, vp); if (update & SNDRV_EMUX_UPDATE_PITCH)
set_pitch(hw, vp); if ((update & SNDRV_EMUX_UPDATE_PAN) &&
vp->port->ctrls[EMUX_MD_REALTIME_PAN])
set_pan(hw, vp); if (update & SNDRV_EMUX_UPDATE_FMMOD)
set_fmmod(hw, vp); if (update & SNDRV_EMUX_UPDATE_TREMFREQ)
set_tremfreq(hw, vp); if (update & SNDRV_EMUX_UPDATE_FM2FRQ2)
set_fm2frq2(hw, vp); if (update & SNDRV_EMUX_UPDATE_Q)
set_filterQ(hw, vp);
}
/* * Find a channel (voice) within the EMU that is not in use or at least * less in use than other channels. Always returns a valid pointer * no matter what. If there is a real shortage of voices then one * will be cut. Such is life. * * The channel index (vp->ch) must be initialized in this routine. * In Emu8k, it is identical with the array index.
*/ staticstruct snd_emux_voice *
get_voice(struct snd_emux *emu, struct snd_emux_port *port)
{ int i; struct snd_emux_voice *vp; struct snd_emu8000 *hw;
/* what we are looking for, in order of preference */ enum {
OFF=0, RELEASED, PLAYING, END
};
/* Keeps track of what we are finding */ struct best { unsignedint time; int voice;
} best[END]; struct best *bp;
hw = emu->hw;
for (i = 0; i < END; i++) {
best[i].time = (unsignedint)(-1); /* XXX MAX_?INT really */
best[i].voice = -1;
}
/* * Go through them all and get a best one to use.
*/ for (i = 0; i < emu->max_voices; i++) { int state, val;
vp = &emu->voices[i];
state = vp->state;
if (state == SNDRV_EMUX_ST_OFF)
bp = best + OFF; elseif (state == SNDRV_EMUX_ST_RELEASED ||
state == SNDRV_EMUX_ST_PENDING) {
bp = best + RELEASED;
val = (EMU8000_CVCF_READ(hw, vp->ch) >> 16) & 0xffff; if (! val)
bp = best + OFF;
} elseif (state & SNDRV_EMUX_ST_ON)
bp = best + PLAYING; else continue;
/* check if sample is finished playing (non-looping only) */ if (state != SNDRV_EMUX_ST_OFF &&
(vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) {
val = EMU8000_CCCA_READ(hw, vp->ch) & 0xffffff; if (val >= vp->reg.loopstart)
bp = best + OFF;
}
/* * Set the pitch of a possibly playing note.
*/ staticvoid
set_pitch(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
{
EMU8000_IP_WRITE(hw, vp->ch, vp->apitch);
}
/* * Set the volume of a possibly already playing note
*/ staticvoid
set_volume(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
{ int ifatn;
/* * set the envelope & LFO parameters to the default values
*/ staticvoid
snd_emu8000_tweak_voice(struct snd_emu8000 *emu, int i)
{ /* set all mod/vol envelope shape to minimum */
EMU8000_ENVVOL_WRITE(emu, i, 0x8000);
EMU8000_ENVVAL_WRITE(emu, i, 0x8000);
EMU8000_DCYSUS_WRITE(emu, i, 0x7F7F);
EMU8000_ATKHLDV_WRITE(emu, i, 0x7F7F);
EMU8000_ATKHLD_WRITE(emu, i, 0x7F7F);
EMU8000_PEFE_WRITE(emu, i, 0); /* mod envelope height to zero */
EMU8000_LFO1VAL_WRITE(emu, i, 0x8000); /* no delay for LFO1 */
EMU8000_LFO2VAL_WRITE(emu, i, 0x8000);
EMU8000_IP_WRITE(emu, i, 0xE000); /* no pitch shift */
EMU8000_IFATN_WRITE(emu, i, 0xFF00); /* volume to minimum */
EMU8000_FMMOD_WRITE(emu, i, 0);
EMU8000_TREMFRQ_WRITE(emu, i, 0);
EMU8000_FM2FRQ2_WRITE(emu, i, 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.