523 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * synth callback routines for Emu10k14 *5 * Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>6 */7 8#include <linux/export.h>9#include "emu10k1_synth_local.h"10#include <sound/asoundef.h>11 12/* voice status */13enum {14 V_FREE=0, V_OFF, V_RELEASED, V_PLAYING, V_END15};16 17/* Keeps track of what we are finding */18struct best_voice {19 unsigned int time;20 int voice;21};22 23/*24 * prototypes25 */26static void lookup_voices(struct snd_emux *emux, struct snd_emu10k1 *hw,27 struct best_voice *best, int active_only);28static struct snd_emux_voice *get_voice(struct snd_emux *emux,29 struct snd_emux_port *port);30static int start_voice(struct snd_emux_voice *vp);31static void trigger_voice(struct snd_emux_voice *vp);32static void release_voice(struct snd_emux_voice *vp);33static void update_voice(struct snd_emux_voice *vp, int update);34static void terminate_voice(struct snd_emux_voice *vp);35static void free_voice(struct snd_emux_voice *vp);36static u32 make_fmmod(struct snd_emux_voice *vp);37static u32 make_fm2frq2(struct snd_emux_voice *vp);38static int get_pitch_shift(struct snd_emux *emu);39 40/*41 * Ensure a value is between two points42 * macro evaluates its args more than once, so changed to upper-case.43 */44#define LIMITVALUE(x, a, b) do { if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b); } while (0)45#define LIMITMAX(x, a) do {if ((x) > (a)) (x) = (a); } while (0)46 47 48/*49 * set up operators50 */51static const struct snd_emux_operators emu10k1_ops = {52 .owner = THIS_MODULE,53 .get_voice = get_voice,54 .prepare = start_voice,55 .trigger = trigger_voice,56 .release = release_voice,57 .update = update_voice,58 .terminate = terminate_voice,59 .free_voice = free_voice,60 .sample_new = snd_emu10k1_sample_new,61 .sample_free = snd_emu10k1_sample_free,62 .get_pitch_shift = get_pitch_shift,63};64 65void66snd_emu10k1_ops_setup(struct snd_emux *emux)67{68 emux->ops = emu10k1_ops;69}70 71 72/*73 * get more voice for pcm74 *75 * terminate most inactive voice and give it as a pcm voice.76 *77 * voice_lock is already held.78 */79int80snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)81{82 struct snd_emux *emu;83 struct snd_emux_voice *vp;84 struct best_voice best[V_END];85 int i;86 87 emu = hw->synth;88 89 lookup_voices(emu, hw, best, 1); /* no OFF voices */90 for (i = 0; i < V_END; i++) {91 if (best[i].voice >= 0) {92 int ch;93 vp = &emu->voices[best[i].voice];94 ch = vp->ch;95 if (ch < 0) {96 /*97 dev_warn(emu->card->dev,98 "synth_get_voice: ch < 0 (%d) ??", i);99 */100 continue;101 }102 vp->emu->num_voices--;103 vp->ch = -1;104 vp->state = SNDRV_EMUX_ST_OFF;105 return ch;106 }107 }108 109 /* not found */110 return -ENOMEM;111}112 113 114/*115 * turn off the voice (not terminated)116 */117static void118release_voice(struct snd_emux_voice *vp)119{120 struct snd_emu10k1 *hw;121 122 hw = vp->hw;123 snd_emu10k1_ptr_write_multiple(hw, vp->ch,124 DCYSUSM, (unsigned char)vp->reg.parm.modrelease | DCYSUSM_PHASE1_MASK,125 DCYSUSV, (unsigned char)vp->reg.parm.volrelease | DCYSUSV_PHASE1_MASK | DCYSUSV_CHANNELENABLE_MASK,126 REGLIST_END);127}128 129 130/*131 * terminate the voice132 */133static void134terminate_voice(struct snd_emux_voice *vp)135{136 struct snd_emu10k1 *hw;137 138 if (snd_BUG_ON(!vp))139 return;140 hw = vp->hw;141 snd_emu10k1_ptr_write_multiple(hw, vp->ch,142 DCYSUSV, 0,143 VTFT, VTFT_FILTERTARGET_MASK,144 CVCF, CVCF_CURRENTFILTER_MASK,145 PTRX, 0,146 CPF, 0,147 REGLIST_END);148 if (vp->block) {149 struct snd_emu10k1_memblk *emem;150 emem = (struct snd_emu10k1_memblk *)vp->block;151 if (emem->map_locked > 0)152 emem->map_locked--;153 }154}155 156/*157 * release the voice to system158 */159static void160free_voice(struct snd_emux_voice *vp)161{162 struct snd_emu10k1 *hw;163 164 hw = vp->hw;165 /* FIXME: emu10k1_synth is broken. */166 /* This can get called with hw == 0 */167 /* Problem apparent on plug, unplug then plug */168 /* on the Audigy 2 ZS Notebook. */169 if (hw && (vp->ch >= 0)) {170 snd_emu10k1_voice_free(hw, &hw->voices[vp->ch]);171 vp->emu->num_voices--;172 vp->ch = -1;173 }174}175 176 177/*178 * update registers179 */180static void181update_voice(struct snd_emux_voice *vp, int update)182{183 struct snd_emu10k1 *hw;184 185 hw = vp->hw;186 if (update & SNDRV_EMUX_UPDATE_VOLUME)187 snd_emu10k1_ptr_write(hw, IFATN_ATTENUATION, vp->ch, vp->avol);188 if (update & SNDRV_EMUX_UPDATE_PITCH)189 snd_emu10k1_ptr_write(hw, IP, vp->ch, vp->apitch);190 if (update & SNDRV_EMUX_UPDATE_PAN) {191 snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_A, vp->ch, vp->apan);192 snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_B, vp->ch, vp->aaux);193 }194 if (update & SNDRV_EMUX_UPDATE_FMMOD)195 snd_emu10k1_ptr_write(hw, FMMOD, vp->ch, make_fmmod(vp));196 if (update & SNDRV_EMUX_UPDATE_TREMFREQ)197 snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq);198 if (update & SNDRV_EMUX_UPDATE_FM2FRQ2)199 snd_emu10k1_ptr_write(hw, FM2FRQ2, vp->ch, make_fm2frq2(vp));200 if (update & SNDRV_EMUX_UPDATE_Q)201 snd_emu10k1_ptr_write(hw, CCCA_RESONANCE, vp->ch, vp->reg.parm.filterQ);202}203 204 205/*206 * look up voice table - get the best voice in order of preference207 */208/* spinlock held! */209static void210lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw,211 struct best_voice *best, int active_only)212{213 struct snd_emux_voice *vp;214 struct best_voice *bp;215 int i;216 217 for (i = 0; i < V_END; i++) {218 best[i].time = (unsigned int)-1; /* XXX MAX_?INT really */219 best[i].voice = -1;220 }221 222 /*223 * Go through them all and get a best one to use.224 * NOTE: could also look at volume and pick the quietest one.225 */226 for (i = 0; i < emu->max_voices; i++) {227 int state, val;228 229 vp = &emu->voices[i];230 state = vp->state;231 if (state == SNDRV_EMUX_ST_OFF) {232 if (vp->ch < 0) {233 if (active_only)234 continue;235 bp = best + V_FREE;236 } else237 bp = best + V_OFF;238 }239 else if (state == SNDRV_EMUX_ST_RELEASED ||240 state == SNDRV_EMUX_ST_PENDING) {241 bp = best + V_RELEASED;242#if 1243 val = snd_emu10k1_ptr_read(hw, CVCF_CURRENTVOL, vp->ch);244 if (! val)245 bp = best + V_OFF;246#endif247 }248 else if (state == SNDRV_EMUX_ST_STANDBY)249 continue;250 else if (state & SNDRV_EMUX_ST_ON)251 bp = best + V_PLAYING;252 else253 continue;254 255 /* check if sample is finished playing (non-looping only) */256 if (bp != best + V_OFF && bp != best + V_FREE &&257 (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) {258 val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64 + 3;259 if (val >= vp->reg.loopstart)260 bp = best + V_OFF;261 }262 263 if (vp->time < bp->time) {264 bp->time = vp->time;265 bp->voice = i;266 }267 }268}269 270/*271 * get an empty voice272 *273 * emu->voice_lock is already held.274 */275static struct snd_emux_voice *276get_voice(struct snd_emux *emu, struct snd_emux_port *port)277{278 struct snd_emu10k1 *hw;279 struct snd_emux_voice *vp;280 struct best_voice best[V_END];281 int i;282 283 hw = emu->hw;284 285 lookup_voices(emu, hw, best, 0);286 for (i = 0; i < V_END; i++) {287 if (best[i].voice >= 0) {288 vp = &emu->voices[best[i].voice];289 if (vp->ch < 0) {290 /* allocate a voice */291 struct snd_emu10k1_voice *hwvoice;292 if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 1, 1, NULL, &hwvoice) < 0)293 continue;294 vp->ch = hwvoice->number;295 emu->num_voices++;296 }297 return vp;298 }299 }300 301 /* not found */302 return NULL;303}304 305/*306 * prepare envelopes and LFOs307 */308static int309start_voice(struct snd_emux_voice *vp)310{311 unsigned int temp;312 int ch;313 bool w_16;314 u32 psst, dsl, map, ccca, vtarget;315 unsigned int addr, mapped_offset;316 struct snd_midi_channel *chan;317 struct snd_emu10k1 *hw;318 struct snd_emu10k1_memblk *emem;319 320 hw = vp->hw;321 ch = vp->ch;322 if (snd_BUG_ON(ch < 0))323 return -EINVAL;324 chan = vp->chan;325 w_16 = !(vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS);326 327 emem = (struct snd_emu10k1_memblk *)vp->block;328 if (emem == NULL)329 return -EINVAL;330 emem->map_locked++;331 if (snd_emu10k1_memblk_map(hw, emem) < 0) {332 /* dev_err(hw->card->devK, "emu: cannot map!\n"); */333 return -ENOMEM;334 }335 mapped_offset = snd_emu10k1_memblk_offset(emem) >> w_16;336 vp->reg.start += mapped_offset;337 vp->reg.end += mapped_offset;338 vp->reg.loopstart += mapped_offset;339 vp->reg.loopend += mapped_offset;340 341 /* set channel routing */342 /* A = left(0), B = right(1), C = reverb(c), D = chorus(d) */343 if (hw->audigy) {344 temp = FXBUS_MIDI_LEFT | (FXBUS_MIDI_RIGHT << 8) | 345 (FXBUS_MIDI_REVERB << 16) | (FXBUS_MIDI_CHORUS << 24);346 snd_emu10k1_ptr_write(hw, A_FXRT1, ch, temp);347 } else {348 temp = (FXBUS_MIDI_LEFT << 16) | (FXBUS_MIDI_RIGHT << 20) | 349 (FXBUS_MIDI_REVERB << 24) | (FXBUS_MIDI_CHORUS << 28);350 snd_emu10k1_ptr_write(hw, FXRT, ch, temp);351 }352 353 temp = vp->reg.parm.reverb;354 temp += (int)vp->chan->control[MIDI_CTL_E1_REVERB_DEPTH] * 9 / 10;355 LIMITMAX(temp, 255);356 addr = vp->reg.loopstart;357 psst = (temp << 24) | addr;358 359 addr = vp->reg.loopend;360 temp = vp->reg.parm.chorus;361 temp += (int)chan->control[MIDI_CTL_E3_CHORUS_DEPTH] * 9 / 10;362 LIMITMAX(temp, 255);363 dsl = (temp << 24) | addr;364 365 map = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);366 367 addr = vp->reg.start + 64 - 3;368 temp = vp->reg.parm.filterQ;369 ccca = (temp << 28) | addr;370 if (vp->apitch < 0xe400)371 ccca |= CCCA_INTERPROM_0;372 else {373 unsigned int shift = (vp->apitch - 0xe000) >> 10;374 ccca |= shift << 25;375 }376 if (!w_16)377 ccca |= CCCA_8BITSELECT;378 379 vtarget = (unsigned int)vp->vtarget << 16;380 381 snd_emu10k1_ptr_write_multiple(hw, ch,382 /* channel to be silent and idle */383 DCYSUSV, 0,384 VTFT, VTFT_FILTERTARGET_MASK,385 CVCF, CVCF_CURRENTFILTER_MASK,386 PTRX, 0,387 CPF, 0,388 389 /* set pitch offset */390 IP, vp->apitch,391 392 /* set envelope parameters */393 ENVVAL, vp->reg.parm.moddelay,394 ATKHLDM, vp->reg.parm.modatkhld,395 DCYSUSM, vp->reg.parm.moddcysus,396 ENVVOL, vp->reg.parm.voldelay,397 ATKHLDV, vp->reg.parm.volatkhld,398 /* decay/sustain parameter for volume envelope is used399 for triggerg the voice */400 401 /* cutoff and volume */402 IFATN, (unsigned int)vp->acutoff << 8 | (unsigned char)vp->avol,403 404 /* modulation envelope heights */405 PEFE, vp->reg.parm.pefe,406 407 /* lfo1/2 delay */408 LFOVAL1, vp->reg.parm.lfo1delay,409 LFOVAL2, vp->reg.parm.lfo2delay,410 411 /* lfo1 pitch & cutoff shift */412 FMMOD, make_fmmod(vp),413 /* lfo1 volume & freq */414 TREMFRQ, vp->reg.parm.tremfrq,415 /* lfo2 pitch & freq */416 FM2FRQ2, make_fm2frq2(vp),417 418 /* reverb and loop start (reverb 8bit, MSB) */419 PSST, psst,420 421 /* chorus & loop end (chorus 8bit, MSB) */422 DSL, dsl,423 424 /* clear filter delay memory */425 Z1, 0,426 Z2, 0,427 428 /* invalidate maps */429 MAPA, map,430 MAPB, map,431 432 /* Q & current address (Q 4bit value, MSB) */433 CCCA, ccca,434 435 /* cache */436 CCR, REG_VAL_PUT(CCR_CACHEINVALIDSIZE, 64),437 438 /* reset volume */439 VTFT, vtarget | vp->ftarget,440 CVCF, vtarget | CVCF_CURRENTFILTER_MASK,441 442 REGLIST_END);443 444 hw->voices[ch].dirty = 1;445 return 0;446}447 448/*449 * Start envelope450 */451static void452trigger_voice(struct snd_emux_voice *vp)453{454 unsigned int ptarget;455 struct snd_emu10k1 *hw;456 struct snd_emu10k1_memblk *emem;457 458 hw = vp->hw;459 460 emem = (struct snd_emu10k1_memblk *)vp->block;461 if (! emem || emem->mapped_page < 0)462 return; /* not mapped */463 464#if 0465 ptarget = (unsigned int)vp->ptarget << 16;466#else467 ptarget = IP_TO_CP(vp->apitch);468#endif469 snd_emu10k1_ptr_write_multiple(hw, vp->ch,470 /* set pitch target and pan (volume) */471 PTRX, ptarget | (vp->apan << 8) | vp->aaux,472 473 /* current pitch and fractional address */474 CPF, ptarget,475 476 /* enable envelope engine */477 DCYSUSV, vp->reg.parm.voldcysus | DCYSUSV_CHANNELENABLE_MASK,478 479 REGLIST_END);480}481 482#define MOD_SENSE 18483 484/* calculate lfo1 modulation height and cutoff register */485static u32486make_fmmod(struct snd_emux_voice *vp)487{488 short pitch;489 unsigned char cutoff;490 int modulation;491 492 pitch = (char)(vp->reg.parm.fmmod>>8);493 cutoff = (vp->reg.parm.fmmod & 0xff);494 modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;495 pitch += (MOD_SENSE * modulation) / 1200;496 LIMITVALUE(pitch, -128, 127);497 return ((unsigned char)pitch << 8) | cutoff;498}499 500/* calculate set lfo2 pitch & frequency register */501static u32502make_fm2frq2(struct snd_emux_voice *vp)503{504 short pitch;505 unsigned char freq;506 int modulation;507 508 pitch = (char)(vp->reg.parm.fm2frq2>>8);509 freq = vp->reg.parm.fm2frq2 & 0xff;510 modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;511 pitch += (MOD_SENSE * modulation) / 1200;512 LIMITVALUE(pitch, -128, 127);513 return ((unsigned char)pitch << 8) | freq;514}515 516static int get_pitch_shift(struct snd_emux *emu)517{518 struct snd_emu10k1 *hw = emu->hw;519 520 return (hw->card_capabilities->emu_model &&521 hw->emu1010.word_clock == 44100) ? 0 : -501;522}523