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