/* * 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)
/* * get more voice for pcm * * terminate most inactive voice and give it as a pcm voice. * * voice_lock is already held.
*/ int
snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
{ struct snd_emux *emu; struct snd_emux_voice *vp; struct best_voice best[V_END]; int i;
emu = hw->synth;
lookup_voices(emu, hw, best, 1); /* no OFF voices */ for (i = 0; i < V_END; i++) { if (best[i].voice >= 0) { int ch;
vp = &emu->voices[best[i].voice];
ch = vp->ch; if (ch < 0) { /* dev_warn(emu->card->dev, "synth_get_voice: ch < 0 (%d) ??", i);
*/ continue;
}
vp->emu->num_voices--;
vp->ch = -1;
vp->state = SNDRV_EMUX_ST_OFF; return ch;
}
}
/* not found */ return -ENOMEM;
}
/* * turn off the voice (not terminated)
*/ staticvoid
release_voice(struct snd_emux_voice *vp)
{ struct snd_emu10k1 *hw;
/* * release the voice to system
*/ staticvoid
free_voice(struct snd_emux_voice *vp)
{ struct snd_emu10k1 *hw;
hw = vp->hw; /* FIXME: emu10k1_synth is broken. */ /* This can get called with hw == 0 */ /* Problem apparent on plug, unplug then plug */ /* on the Audigy 2 ZS Notebook. */ if (hw && (vp->ch >= 0)) {
snd_emu10k1_voice_free(hw, &hw->voices[vp->ch]);
vp->emu->num_voices--;
vp->ch = -1;
}
}
hw = vp->hw; if (update & SNDRV_EMUX_UPDATE_VOLUME)
snd_emu10k1_ptr_write(hw, IFATN_ATTENUATION, vp->ch, vp->avol); if (update & SNDRV_EMUX_UPDATE_PITCH)
snd_emu10k1_ptr_write(hw, IP, vp->ch, vp->apitch); if (update & SNDRV_EMUX_UPDATE_PAN) {
snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_A, vp->ch, vp->apan);
snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_B, vp->ch, vp->aaux);
} if (update & SNDRV_EMUX_UPDATE_FMMOD)
snd_emu10k1_ptr_write(hw, FMMOD, vp->ch, make_fmmod(vp)); if (update & SNDRV_EMUX_UPDATE_TREMFREQ)
snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq); if (update & SNDRV_EMUX_UPDATE_FM2FRQ2)
snd_emu10k1_ptr_write(hw, FM2FRQ2, vp->ch, make_fm2frq2(vp)); if (update & SNDRV_EMUX_UPDATE_Q)
snd_emu10k1_ptr_write(hw, CCCA_RESONANCE, vp->ch, vp->reg.parm.filterQ);
}
/* * look up voice table - get the best voice in order of preference
*/ /* spinlock held! */ staticvoid
lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw, struct best_voice *best, int active_only)
{ struct snd_emux_voice *vp; struct best_voice *bp; int i;
for (i = 0; i < V_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. * NOTE: could also look at volume and pick the quietest one.
*/ for (i = 0; i < emu->max_voices; i++) { int state, val;
vp = &emu->voices[i];
state = vp->state; if (state == SNDRV_EMUX_ST_OFF) { if (vp->ch < 0) { if (active_only) continue;
bp = best + V_FREE;
} else
bp = best + V_OFF;
} elseif (state == SNDRV_EMUX_ST_RELEASED ||
state == SNDRV_EMUX_ST_PENDING) {
bp = best + V_RELEASED; #if 1
val = snd_emu10k1_ptr_read(hw, CVCF_CURRENTVOL, vp->ch); if (! val)
bp = best + V_OFF; #endif
} elseif (state == SNDRV_EMUX_ST_STANDBY) continue; elseif (state & SNDRV_EMUX_ST_ON)
bp = best + V_PLAYING; else continue;
/* check if sample is finished playing (non-looping only) */ if (bp != best + V_OFF && bp != best + V_FREE &&
(vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) {
val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64 + 3; if (val >= vp->reg.loopstart)
bp = best + V_OFF;
}
snd_emu10k1_ptr_write_multiple(hw, ch, /* channel to be silent and idle */
DCYSUSV, 0,
VTFT, VTFT_FILTERTARGET_MASK,
CVCF, CVCF_CURRENTFILTER_MASK,
PTRX, 0,
CPF, 0,
/* set pitch offset */
IP, vp->apitch,
/* set envelope parameters */
ENVVAL, vp->reg.parm.moddelay,
ATKHLDM, vp->reg.parm.modatkhld,
DCYSUSM, vp->reg.parm.moddcysus,
ENVVOL, vp->reg.parm.voldelay,
ATKHLDV, vp->reg.parm.volatkhld, /* decay/sustain parameter for volume envelope is used
for triggerg the voice */
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.