linux/sound/isa/sb/emu8000_callback.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  synth callback routines for the emu8000 (AWE32/64)
   4 *
   5 *  Copyright (C) 1999 Steve Ratcliffe
   6 *  Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
   7 */
   8
   9#include "emu8000_local.h"
  10#include <linux/export.h>
  11#include <sound/asoundef.h>
  12
  13/*
  14 * prototypes
  15 */
  16static struct snd_emux_voice *get_voice(struct snd_emux *emu,
  17                                        struct snd_emux_port *port);
  18static int start_voice(struct snd_emux_voice *vp);
  19static void trigger_voice(struct snd_emux_voice *vp);
  20static void release_voice(struct snd_emux_voice *vp);
  21static void update_voice(struct snd_emux_voice *vp, int update);
  22static void reset_voice(struct snd_emux *emu, int ch);
  23static void terminate_voice(struct snd_emux_voice *vp);
  24static void sysex(struct snd_emux *emu, char *buf, int len, int parsed,
  25                  struct snd_midi_channel_set *chset);
  26#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
  27static int oss_ioctl(struct snd_emux *emu, int cmd, int p1, int p2);
  28#endif
  29static int load_fx(struct snd_emux *emu, int type, int mode,
  30                   const void __user *buf, long len);
  31
  32static void set_pitch(struct snd_emu8000 *hw, struct snd_emux_voice *vp);
  33static void set_volume(struct snd_emu8000 *hw, struct snd_emux_voice *vp);
  34static void set_pan(struct snd_emu8000 *hw, struct snd_emux_voice *vp);
  35static void set_fmmod(struct snd_emu8000 *hw, struct snd_emux_voice *vp);
  36static void set_tremfreq(struct snd_emu8000 *hw, struct snd_emux_voice *vp);
  37static void set_fm2frq2(struct snd_emu8000 *hw, struct snd_emux_voice *vp);
  38static void set_filterQ(struct snd_emu8000 *hw, struct snd_emux_voice *vp);
  39static void snd_emu8000_tweak_voice(struct snd_emu8000 *emu, int ch);
  40
  41/*
  42 * Ensure a value is between two points
  43 * macro evaluates its args more than once, so changed to upper-case.
  44 */
  45#define LIMITVALUE(x, a, b) do { if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b); } while (0)
  46#define LIMITMAX(x, a) do {if ((x) > (a)) (x) = (a); } while (0)
  47
  48
  49/*
  50 * set up operators
  51 */
  52static const struct snd_emux_operators emu8000_ops = {
  53        .owner =        THIS_MODULE,
  54        .get_voice =    get_voice,
  55        .prepare =      start_voice,
  56        .trigger =      trigger_voice,
  57        .release =      release_voice,
  58        .update =       update_voice,
  59        .terminate =    terminate_voice,
  60        .reset =        reset_voice,
  61        .sample_new =   snd_emu8000_sample_new,
  62        .sample_free =  snd_emu8000_sample_free,
  63        .sample_reset = snd_emu8000_sample_reset,
  64        .load_fx =      load_fx,
  65        .sysex =        sysex,
  66#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
  67        .oss_ioctl =    oss_ioctl,
  68#endif
  69};
  70
  71void
  72snd_emu8000_ops_setup(struct snd_emu8000 *hw)
  73{
  74        hw->emu->ops = emu8000_ops;
  75}
  76
  77
  78
  79/*
  80 * Terminate a voice
  81 */
  82static void
  83release_voice(struct snd_emux_voice *vp)
  84{
  85        int dcysusv;
  86        struct snd_emu8000 *hw;
  87
  88        hw = vp->hw;
  89        dcysusv = 0x8000 | (unsigned char)vp->reg.parm.modrelease;
  90        EMU8000_DCYSUS_WRITE(hw, vp->ch, dcysusv);
  91        dcysusv = 0x8000 | (unsigned char)vp->reg.parm.volrelease;
  92        EMU8000_DCYSUSV_WRITE(hw, vp->ch, dcysusv);
  93}
  94
  95
  96/*
  97 */
  98static void
  99terminate_voice(struct snd_emux_voice *vp)
 100{
 101        struct snd_emu8000 *hw; 
 102
 103        hw = vp->hw;
 104        EMU8000_DCYSUSV_WRITE(hw, vp->ch, 0x807F);
 105}
 106
 107
 108/*
 109 */
 110static void
 111update_voice(struct snd_emux_voice *vp, int update)
 112{
 113        struct snd_emu8000 *hw;
 114
 115        hw = vp->hw;
 116        if (update & SNDRV_EMUX_UPDATE_VOLUME)
 117                set_volume(hw, vp);
 118        if (update & SNDRV_EMUX_UPDATE_PITCH)
 119                set_pitch(hw, vp);
 120        if ((update & SNDRV_EMUX_UPDATE_PAN) &&
 121            vp->port->ctrls[EMUX_MD_REALTIME_PAN])
 122                set_pan(hw, vp);
 123        if (update & SNDRV_EMUX_UPDATE_FMMOD)
 124                set_fmmod(hw, vp);
 125        if (update & SNDRV_EMUX_UPDATE_TREMFREQ)
 126                set_tremfreq(hw, vp);
 127        if (update & SNDRV_EMUX_UPDATE_FM2FRQ2)
 128                set_fm2frq2(hw, vp);
 129        if (update & SNDRV_EMUX_UPDATE_Q)
 130                set_filterQ(hw, vp);
 131}
 132
 133
 134/*
 135 * Find a channel (voice) within the EMU that is not in use or at least
 136 * less in use than other channels.  Always returns a valid pointer
 137 * no matter what.  If there is a real shortage of voices then one
 138 * will be cut. Such is life.
 139 *
 140 * The channel index (vp->ch) must be initialized in this routine.
 141 * In Emu8k, it is identical with the array index.
 142 */
 143static struct snd_emux_voice *
 144get_voice(struct snd_emux *emu, struct snd_emux_port *port)
 145{
 146        int  i;
 147        struct snd_emux_voice *vp;
 148        struct snd_emu8000 *hw;
 149
 150        /* what we are looking for, in order of preference */
 151        enum {
 152                OFF=0, RELEASED, PLAYING, END
 153        };
 154
 155        /* Keeps track of what we are finding */
 156        struct best {
 157                unsigned int  time;
 158                int voice;
 159        } best[END];
 160        struct best *bp;
 161
 162        hw = emu->hw;
 163
 164        for (i = 0; i < END; i++) {
 165                best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */
 166                best[i].voice = -1;
 167        }
 168
 169        /*
 170         * Go through them all and get a best one to use.
 171         */
 172        for (i = 0; i < emu->max_voices; i++) {
 173                int state, val;
 174
 175                vp = &emu->voices[i];
 176                state = vp->state;
 177
 178                if (state == SNDRV_EMUX_ST_OFF)
 179                        bp = best + OFF;
 180                else if (state == SNDRV_EMUX_ST_RELEASED ||
 181                         state == SNDRV_EMUX_ST_PENDING) {
 182                        bp = best + RELEASED;
 183                        val = (EMU8000_CVCF_READ(hw, vp->ch) >> 16) & 0xffff;
 184                        if (! val)
 185                                bp = best + OFF;
 186                }
 187                else if (state & SNDRV_EMUX_ST_ON)
 188                        bp = best + PLAYING;
 189                else
 190                        continue;
 191
 192                /* check if sample is finished playing (non-looping only) */
 193                if (state != SNDRV_EMUX_ST_OFF &&
 194                    (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) {
 195                        val = EMU8000_CCCA_READ(hw, vp->ch) & 0xffffff;
 196                        if (val >= vp->reg.loopstart)
 197                                bp = best + OFF;
 198                }
 199
 200                if (vp->time < bp->time) {
 201                        bp->time = vp->time;
 202                        bp->voice = i;
 203                }
 204        }
 205
 206        for (i = 0; i < END; i++) {
 207                if (best[i].voice >= 0) {
 208                        vp = &emu->voices[best[i].voice];
 209                        vp->ch = best[i].voice;
 210                        return vp;
 211                }
 212        }
 213
 214        /* not found */
 215        return NULL;
 216}
 217
 218/*
 219 */
 220static int
 221start_voice(struct snd_emux_voice *vp)
 222{
 223        unsigned int temp;
 224        int ch;
 225        int addr;
 226        struct snd_midi_channel *chan;
 227        struct snd_emu8000 *hw;
 228
 229        hw = vp->hw;
 230        ch = vp->ch;
 231        chan = vp->chan;
 232
 233        /* channel to be silent and idle */
 234        EMU8000_DCYSUSV_WRITE(hw, ch, 0x0080);
 235        EMU8000_VTFT_WRITE(hw, ch, 0x0000FFFF);
 236        EMU8000_CVCF_WRITE(hw, ch, 0x0000FFFF);
 237        EMU8000_PTRX_WRITE(hw, ch, 0);
 238        EMU8000_CPF_WRITE(hw, ch, 0);
 239
 240        /* set pitch offset */
 241        set_pitch(hw, vp);
 242
 243        /* set envelope parameters */
 244        EMU8000_ENVVAL_WRITE(hw, ch, vp->reg.parm.moddelay);
 245        EMU8000_ATKHLD_WRITE(hw, ch, vp->reg.parm.modatkhld);
 246        EMU8000_DCYSUS_WRITE(hw, ch, vp->reg.parm.moddcysus);
 247        EMU8000_ENVVOL_WRITE(hw, ch, vp->reg.parm.voldelay);
 248        EMU8000_ATKHLDV_WRITE(hw, ch, vp->reg.parm.volatkhld);
 249        /* decay/sustain parameter for volume envelope is used
 250           for triggerg the voice */
 251
 252        /* cutoff and volume */
 253        set_volume(hw, vp);
 254
 255        /* modulation envelope heights */
 256        EMU8000_PEFE_WRITE(hw, ch, vp->reg.parm.pefe);
 257
 258        /* lfo1/2 delay */
 259        EMU8000_LFO1VAL_WRITE(hw, ch, vp->reg.parm.lfo1delay);
 260        EMU8000_LFO2VAL_WRITE(hw, ch, vp->reg.parm.lfo2delay);
 261
 262        /* lfo1 pitch & cutoff shift */
 263        set_fmmod(hw, vp);
 264        /* lfo1 volume & freq */
 265        set_tremfreq(hw, vp);
 266        /* lfo2 pitch & freq */
 267        set_fm2frq2(hw, vp);
 268        /* pan & loop start */
 269        set_pan(hw, vp);
 270
 271        /* chorus & loop end (chorus 8bit, MSB) */
 272        addr = vp->reg.loopend - 1;
 273        temp = vp->reg.parm.chorus;
 274        temp += (int)chan->control[MIDI_CTL_E3_CHORUS_DEPTH] * 9 / 10;
 275        LIMITMAX(temp, 255);
 276        temp = (temp <<24) | (unsigned int)addr;
 277        EMU8000_CSL_WRITE(hw, ch, temp);
 278
 279        /* Q & current address (Q 4bit value, MSB) */
 280        addr = vp->reg.start - 1;
 281        temp = vp->reg.parm.filterQ;
 282        temp = (temp<<28) | (unsigned int)addr;
 283        EMU8000_CCCA_WRITE(hw, ch, temp);
 284
 285        /* clear unknown registers */
 286        EMU8000_00A0_WRITE(hw, ch, 0);
 287        EMU8000_0080_WRITE(hw, ch, 0);
 288
 289        /* reset volume */
 290        temp = vp->vtarget << 16;
 291        EMU8000_VTFT_WRITE(hw, ch, temp | vp->ftarget);
 292        EMU8000_CVCF_WRITE(hw, ch, temp | 0xff00);
 293
 294        return 0;
 295}
 296
 297/*
 298 * Start envelope
 299 */
 300static void
 301trigger_voice(struct snd_emux_voice *vp)
 302{
 303        int ch = vp->ch;
 304        unsigned int temp;
 305        struct snd_emu8000 *hw;
 306
 307        hw = vp->hw;
 308
 309        /* set reverb and pitch target */
 310        temp = vp->reg.parm.reverb;
 311        temp += (int)vp->chan->control[MIDI_CTL_E1_REVERB_DEPTH] * 9 / 10;
 312        LIMITMAX(temp, 255);
 313        temp = (temp << 8) | (vp->ptarget << 16) | vp->aaux;
 314        EMU8000_PTRX_WRITE(hw, ch, temp);
 315        EMU8000_CPF_WRITE(hw, ch, vp->ptarget << 16);
 316        EMU8000_DCYSUSV_WRITE(hw, ch, vp->reg.parm.voldcysus);
 317}
 318
 319/*
 320 * reset voice parameters
 321 */
 322static void
 323reset_voice(struct snd_emux *emu, int ch)
 324{
 325        struct snd_emu8000 *hw;
 326
 327        hw = emu->hw;
 328        EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F);
 329        snd_emu8000_tweak_voice(hw, ch);
 330}
 331
 332/*
 333 * Set the pitch of a possibly playing note.
 334 */
 335static void
 336set_pitch(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
 337{
 338        EMU8000_IP_WRITE(hw, vp->ch, vp->apitch);
 339}
 340
 341/*
 342 * Set the volume of a possibly already playing note
 343 */
 344static void
 345set_volume(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
 346{
 347        int  ifatn;
 348
 349        ifatn = (unsigned char)vp->acutoff;
 350        ifatn = (ifatn << 8);
 351        ifatn |= (unsigned char)vp->avol;
 352        EMU8000_IFATN_WRITE(hw, vp->ch, ifatn);
 353}
 354
 355/*
 356 * Set pan and loop start address.
 357 */
 358static void
 359set_pan(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
 360{
 361        unsigned int temp;
 362
 363        temp = ((unsigned int)vp->apan<<24) | ((unsigned int)vp->reg.loopstart - 1);
 364        EMU8000_PSST_WRITE(hw, vp->ch, temp);
 365}
 366
 367#define MOD_SENSE 18
 368
 369static void
 370set_fmmod(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
 371{
 372        unsigned short fmmod;
 373        short pitch;
 374        unsigned char cutoff;
 375        int modulation;
 376
 377        pitch = (char)(vp->reg.parm.fmmod>>8);
 378        cutoff = (vp->reg.parm.fmmod & 0xff);
 379        modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;
 380        pitch += (MOD_SENSE * modulation) / 1200;
 381        LIMITVALUE(pitch, -128, 127);
 382        fmmod = ((unsigned char)pitch<<8) | cutoff;
 383        EMU8000_FMMOD_WRITE(hw, vp->ch, fmmod);
 384}
 385
 386/* set tremolo (lfo1) volume & frequency */
 387static void
 388set_tremfreq(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
 389{
 390        EMU8000_TREMFRQ_WRITE(hw, vp->ch, vp->reg.parm.tremfrq);
 391}
 392
 393/* set lfo2 pitch & frequency */
 394static void
 395set_fm2frq2(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
 396{
 397        unsigned short fm2frq2;
 398        short pitch;
 399        unsigned char freq;
 400        int modulation;
 401
 402        pitch = (char)(vp->reg.parm.fm2frq2>>8);
 403        freq = vp->reg.parm.fm2frq2 & 0xff;
 404        modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;
 405        pitch += (MOD_SENSE * modulation) / 1200;
 406        LIMITVALUE(pitch, -128, 127);
 407        fm2frq2 = ((unsigned char)pitch<<8) | freq;
 408        EMU8000_FM2FRQ2_WRITE(hw, vp->ch, fm2frq2);
 409}
 410
 411/* set filterQ */
 412static void
 413set_filterQ(struct snd_emu8000 *hw, struct snd_emux_voice *vp)
 414{
 415        unsigned int addr;
 416        addr = EMU8000_CCCA_READ(hw, vp->ch) & 0xffffff;
 417        addr |= (vp->reg.parm.filterQ << 28);
 418        EMU8000_CCCA_WRITE(hw, vp->ch, addr);
 419}
 420
 421/*
 422 * set the envelope & LFO parameters to the default values
 423 */
 424static void
 425snd_emu8000_tweak_voice(struct snd_emu8000 *emu, int i)
 426{
 427        /* set all mod/vol envelope shape to minimum */
 428        EMU8000_ENVVOL_WRITE(emu, i, 0x8000);
 429        EMU8000_ENVVAL_WRITE(emu, i, 0x8000);
 430        EMU8000_DCYSUS_WRITE(emu, i, 0x7F7F);
 431        EMU8000_ATKHLDV_WRITE(emu, i, 0x7F7F);
 432        EMU8000_ATKHLD_WRITE(emu, i, 0x7F7F);
 433        EMU8000_PEFE_WRITE(emu, i, 0);  /* mod envelope height to zero */
 434        EMU8000_LFO1VAL_WRITE(emu, i, 0x8000); /* no delay for LFO1 */
 435        EMU8000_LFO2VAL_WRITE(emu, i, 0x8000);
 436        EMU8000_IP_WRITE(emu, i, 0xE000);       /* no pitch shift */
 437        EMU8000_IFATN_WRITE(emu, i, 0xFF00);    /* volume to minimum */
 438        EMU8000_FMMOD_WRITE(emu, i, 0);
 439        EMU8000_TREMFRQ_WRITE(emu, i, 0);
 440        EMU8000_FM2FRQ2_WRITE(emu, i, 0);
 441}
 442
 443/*
 444 * sysex callback
 445 */
 446static void
 447sysex(struct snd_emux *emu, char *buf, int len, int parsed, struct snd_midi_channel_set *chset)
 448{
 449        struct snd_emu8000 *hw;
 450
 451        hw = emu->hw;
 452
 453        switch (parsed) {
 454        case SNDRV_MIDI_SYSEX_GS_CHORUS_MODE:
 455                hw->chorus_mode = chset->gs_chorus_mode;
 456                snd_emu8000_update_chorus_mode(hw);
 457                break;
 458
 459        case SNDRV_MIDI_SYSEX_GS_REVERB_MODE:
 460                hw->reverb_mode = chset->gs_reverb_mode;
 461                snd_emu8000_update_reverb_mode(hw);
 462                break;
 463        }
 464}
 465
 466
 467#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
 468/*
 469 * OSS ioctl callback
 470 */
 471static int
 472oss_ioctl(struct snd_emux *emu, int cmd, int p1, int p2)
 473{
 474        struct snd_emu8000 *hw;
 475
 476        hw = emu->hw;
 477
 478        switch (cmd) {
 479        case _EMUX_OSS_REVERB_MODE:
 480                hw->reverb_mode = p1;
 481                snd_emu8000_update_reverb_mode(hw);
 482                break;
 483
 484        case _EMUX_OSS_CHORUS_MODE:
 485                hw->chorus_mode = p1;
 486                snd_emu8000_update_chorus_mode(hw);
 487                break;
 488
 489        case _EMUX_OSS_INITIALIZE_CHIP:
 490                /* snd_emu8000_init(hw); */ /*ignored*/
 491                break;
 492
 493        case _EMUX_OSS_EQUALIZER:
 494                hw->bass_level = p1;
 495                hw->treble_level = p2;
 496                snd_emu8000_update_equalizer(hw);
 497                break;
 498        }
 499        return 0;
 500}
 501#endif
 502
 503
 504/*
 505 * additional patch keys
 506 */
 507
 508#define SNDRV_EMU8000_LOAD_CHORUS_FX    0x10    /* optarg=mode */
 509#define SNDRV_EMU8000_LOAD_REVERB_FX    0x11    /* optarg=mode */
 510
 511
 512/*
 513 * callback routine
 514 */
 515
 516static int
 517load_fx(struct snd_emux *emu, int type, int mode, const void __user *buf, long len)
 518{
 519        struct snd_emu8000 *hw;
 520        hw = emu->hw;
 521
 522        /* skip header */
 523        buf += 16;
 524        len -= 16;
 525
 526        switch (type) {
 527        case SNDRV_EMU8000_LOAD_CHORUS_FX:
 528                return snd_emu8000_load_chorus_fx(hw, mode, buf, len);
 529        case SNDRV_EMU8000_LOAD_REVERB_FX:
 530                return snd_emu8000_load_reverb_fx(hw, mode, buf, len);
 531        }
 532        return -EINVAL;
 533}
 534
 535