emux_effect.c (8943B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Midi synth routines for the Emu8k/Emu10k1 4 * 5 * Copyright (C) 1999 Steve Ratcliffe 6 * Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de> 7 * 8 * Contains code based on awe_wave.c by Takashi Iwai 9 */ 10 11#include "emux_voice.h" 12#include <linux/slab.h> 13 14#ifdef SNDRV_EMUX_USE_RAW_EFFECT 15/* 16 * effects table 17 */ 18 19#define xoffsetof(type,tag) ((long)(&((type)NULL)->tag) - (long)(NULL)) 20 21#define parm_offset(tag) xoffsetof(struct soundfont_voice_parm *, tag) 22 23#define PARM_IS_BYTE (1 << 0) 24#define PARM_IS_WORD (1 << 1) 25#define PARM_IS_ALIGNED (3 << 2) 26#define PARM_IS_ALIGN_HI (1 << 2) 27#define PARM_IS_ALIGN_LO (2 << 2) 28#define PARM_IS_SIGNED (1 << 4) 29 30#define PARM_WORD (PARM_IS_WORD) 31#define PARM_BYTE_LO (PARM_IS_BYTE|PARM_IS_ALIGN_LO) 32#define PARM_BYTE_HI (PARM_IS_BYTE|PARM_IS_ALIGN_HI) 33#define PARM_BYTE (PARM_IS_BYTE) 34#define PARM_SIGN_LO (PARM_IS_BYTE|PARM_IS_ALIGN_LO|PARM_IS_SIGNED) 35#define PARM_SIGN_HI (PARM_IS_BYTE|PARM_IS_ALIGN_HI|PARM_IS_SIGNED) 36 37static struct emux_parm_defs { 38 int type; /* byte or word */ 39 int low, high; /* value range */ 40 long offset; /* offset in parameter record (-1 = not written) */ 41 int update; /* flgas for real-time update */ 42} parm_defs[EMUX_NUM_EFFECTS] = { 43 {PARM_WORD, 0, 0x8000, parm_offset(moddelay), 0}, /* env1 delay */ 44 {PARM_BYTE_LO, 1, 0x80, parm_offset(modatkhld), 0}, /* env1 attack */ 45 {PARM_BYTE_HI, 0, 0x7e, parm_offset(modatkhld), 0}, /* env1 hold */ 46 {PARM_BYTE_LO, 1, 0x7f, parm_offset(moddcysus), 0}, /* env1 decay */ 47 {PARM_BYTE_LO, 1, 0x7f, parm_offset(modrelease), 0}, /* env1 release */ 48 {PARM_BYTE_HI, 0, 0x7f, parm_offset(moddcysus), 0}, /* env1 sustain */ 49 {PARM_BYTE_HI, 0, 0xff, parm_offset(pefe), 0}, /* env1 pitch */ 50 {PARM_BYTE_LO, 0, 0xff, parm_offset(pefe), 0}, /* env1 fc */ 51 52 {PARM_WORD, 0, 0x8000, parm_offset(voldelay), 0}, /* env2 delay */ 53 {PARM_BYTE_LO, 1, 0x80, parm_offset(volatkhld), 0}, /* env2 attack */ 54 {PARM_BYTE_HI, 0, 0x7e, parm_offset(volatkhld), 0}, /* env2 hold */ 55 {PARM_BYTE_LO, 1, 0x7f, parm_offset(voldcysus), 0}, /* env2 decay */ 56 {PARM_BYTE_LO, 1, 0x7f, parm_offset(volrelease), 0}, /* env2 release */ 57 {PARM_BYTE_HI, 0, 0x7f, parm_offset(voldcysus), 0}, /* env2 sustain */ 58 59 {PARM_WORD, 0, 0x8000, parm_offset(lfo1delay), 0}, /* lfo1 delay */ 60 {PARM_BYTE_LO, 0, 0xff, parm_offset(tremfrq), SNDRV_EMUX_UPDATE_TREMFREQ}, /* lfo1 freq */ 61 {PARM_SIGN_HI, -128, 127, parm_offset(tremfrq), SNDRV_EMUX_UPDATE_TREMFREQ}, /* lfo1 vol */ 62 {PARM_SIGN_HI, -128, 127, parm_offset(fmmod), SNDRV_EMUX_UPDATE_FMMOD}, /* lfo1 pitch */ 63 {PARM_BYTE_LO, 0, 0xff, parm_offset(fmmod), SNDRV_EMUX_UPDATE_FMMOD}, /* lfo1 cutoff */ 64 65 {PARM_WORD, 0, 0x8000, parm_offset(lfo2delay), 0}, /* lfo2 delay */ 66 {PARM_BYTE_LO, 0, 0xff, parm_offset(fm2frq2), SNDRV_EMUX_UPDATE_FM2FRQ2}, /* lfo2 freq */ 67 {PARM_SIGN_HI, -128, 127, parm_offset(fm2frq2), SNDRV_EMUX_UPDATE_FM2FRQ2}, /* lfo2 pitch */ 68 69 {PARM_WORD, 0, 0xffff, -1, SNDRV_EMUX_UPDATE_PITCH}, /* initial pitch */ 70 {PARM_BYTE, 0, 0xff, parm_offset(chorus), 0}, /* chorus */ 71 {PARM_BYTE, 0, 0xff, parm_offset(reverb), 0}, /* reverb */ 72 {PARM_BYTE, 0, 0xff, parm_offset(cutoff), SNDRV_EMUX_UPDATE_VOLUME}, /* cutoff */ 73 {PARM_BYTE, 0, 15, parm_offset(filterQ), SNDRV_EMUX_UPDATE_Q}, /* resonance */ 74 75 {PARM_WORD, 0, 0xffff, -1, 0}, /* sample start */ 76 {PARM_WORD, 0, 0xffff, -1, 0}, /* loop start */ 77 {PARM_WORD, 0, 0xffff, -1, 0}, /* loop end */ 78 {PARM_WORD, 0, 0xffff, -1, 0}, /* coarse sample start */ 79 {PARM_WORD, 0, 0xffff, -1, 0}, /* coarse loop start */ 80 {PARM_WORD, 0, 0xffff, -1, 0}, /* coarse loop end */ 81 {PARM_BYTE, 0, 0xff, -1, SNDRV_EMUX_UPDATE_VOLUME}, /* initial attenuation */ 82}; 83 84/* set byte effect value */ 85static void 86effect_set_byte(unsigned char *valp, struct snd_midi_channel *chan, int type) 87{ 88 short effect; 89 struct snd_emux_effect_table *fx = chan->private; 90 91 effect = fx->val[type]; 92 if (fx->flag[type] == EMUX_FX_FLAG_ADD) { 93 if (parm_defs[type].type & PARM_IS_SIGNED) 94 effect += *(char*)valp; 95 else 96 effect += *valp; 97 } 98 if (effect < parm_defs[type].low) 99 effect = parm_defs[type].low; 100 else if (effect > parm_defs[type].high) 101 effect = parm_defs[type].high; 102 *valp = (unsigned char)effect; 103} 104 105/* set word effect value */ 106static void 107effect_set_word(unsigned short *valp, struct snd_midi_channel *chan, int type) 108{ 109 int effect; 110 struct snd_emux_effect_table *fx = chan->private; 111 112 effect = *(unsigned short*)&fx->val[type]; 113 if (fx->flag[type] == EMUX_FX_FLAG_ADD) 114 effect += *valp; 115 if (effect < parm_defs[type].low) 116 effect = parm_defs[type].low; 117 else if (effect > parm_defs[type].high) 118 effect = parm_defs[type].high; 119 *valp = (unsigned short)effect; 120} 121 122/* address offset */ 123static int 124effect_get_offset(struct snd_midi_channel *chan, int lo, int hi, int mode) 125{ 126 int addr = 0; 127 struct snd_emux_effect_table *fx = chan->private; 128 129 if (fx->flag[hi]) 130 addr = (short)fx->val[hi]; 131 addr = addr << 15; 132 if (fx->flag[lo]) 133 addr += (short)fx->val[lo]; 134 if (!(mode & SNDRV_SFNT_SAMPLE_8BITS)) 135 addr /= 2; 136 return addr; 137} 138 139#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) 140/* change effects - for OSS sequencer compatibility */ 141void 142snd_emux_send_effect_oss(struct snd_emux_port *port, 143 struct snd_midi_channel *chan, int type, int val) 144{ 145 int mode; 146 147 if (type & 0x40) 148 mode = EMUX_FX_FLAG_OFF; 149 else if (type & 0x80) 150 mode = EMUX_FX_FLAG_ADD; 151 else 152 mode = EMUX_FX_FLAG_SET; 153 type &= 0x3f; 154 155 snd_emux_send_effect(port, chan, type, val, mode); 156} 157#endif 158 159/* Modify the effect value. 160 * if update is necessary, call emu8000_control 161 */ 162void 163snd_emux_send_effect(struct snd_emux_port *port, struct snd_midi_channel *chan, 164 int type, int val, int mode) 165{ 166 int i; 167 int offset; 168 unsigned char *srcp, *origp; 169 struct snd_emux *emu; 170 struct snd_emux_effect_table *fx; 171 unsigned long flags; 172 173 emu = port->emu; 174 fx = chan->private; 175 if (emu == NULL || fx == NULL) 176 return; 177 if (type < 0 || type >= EMUX_NUM_EFFECTS) 178 return; 179 180 fx->val[type] = val; 181 fx->flag[type] = mode; 182 183 /* do we need to modify the register in realtime ? */ 184 if (!parm_defs[type].update) 185 return; 186 offset = parm_defs[type].offset; 187 if (offset < 0) 188 return; 189 190#ifdef SNDRV_LITTLE_ENDIAN 191 if (parm_defs[type].type & PARM_IS_ALIGN_HI) 192 offset++; 193#else 194 if (parm_defs[type].type & PARM_IS_ALIGN_LO) 195 offset++; 196#endif 197 /* modify the register values */ 198 spin_lock_irqsave(&emu->voice_lock, flags); 199 for (i = 0; i < emu->max_voices; i++) { 200 struct snd_emux_voice *vp = &emu->voices[i]; 201 if (!STATE_IS_PLAYING(vp->state) || vp->chan != chan) 202 continue; 203 srcp = (unsigned char*)&vp->reg.parm + offset; 204 origp = (unsigned char*)&vp->zone->v.parm + offset; 205 if (parm_defs[i].type & PARM_IS_BYTE) { 206 *srcp = *origp; 207 effect_set_byte(srcp, chan, type); 208 } else { 209 *(unsigned short*)srcp = *(unsigned short*)origp; 210 effect_set_word((unsigned short*)srcp, chan, type); 211 } 212 } 213 spin_unlock_irqrestore(&emu->voice_lock, flags); 214 215 /* activate them */ 216 snd_emux_update_channel(port, chan, parm_defs[type].update); 217} 218 219 220/* copy wavetable registers to voice table */ 221void 222snd_emux_setup_effect(struct snd_emux_voice *vp) 223{ 224 struct snd_midi_channel *chan = vp->chan; 225 struct snd_emux_effect_table *fx; 226 unsigned char *srcp; 227 int i; 228 229 fx = chan->private; 230 if (!fx) 231 return; 232 233 /* modify the register values via effect table */ 234 for (i = 0; i < EMUX_FX_END; i++) { 235 int offset; 236 if (!fx->flag[i]) 237 continue; 238 offset = parm_defs[i].offset; 239 if (offset < 0) 240 continue; 241#ifdef SNDRV_LITTLE_ENDIAN 242 if (parm_defs[i].type & PARM_IS_ALIGN_HI) 243 offset++; 244#else 245 if (parm_defs[i].type & PARM_IS_ALIGN_LO) 246 offset++; 247#endif 248 srcp = (unsigned char*)&vp->reg.parm + offset; 249 if (parm_defs[i].type & PARM_IS_BYTE) 250 effect_set_byte(srcp, chan, i); 251 else 252 effect_set_word((unsigned short*)srcp, chan, i); 253 } 254 255 /* correct sample and loop points */ 256 vp->reg.start += effect_get_offset(chan, EMUX_FX_SAMPLE_START, 257 EMUX_FX_COARSE_SAMPLE_START, 258 vp->reg.sample_mode); 259 260 vp->reg.loopstart += effect_get_offset(chan, EMUX_FX_LOOP_START, 261 EMUX_FX_COARSE_LOOP_START, 262 vp->reg.sample_mode); 263 264 vp->reg.loopend += effect_get_offset(chan, EMUX_FX_LOOP_END, 265 EMUX_FX_COARSE_LOOP_END, 266 vp->reg.sample_mode); 267} 268 269/* 270 * effect table 271 */ 272void 273snd_emux_create_effect(struct snd_emux_port *p) 274{ 275 int i; 276 p->effect = kcalloc(p->chset.max_channels, 277 sizeof(struct snd_emux_effect_table), GFP_KERNEL); 278 if (p->effect) { 279 for (i = 0; i < p->chset.max_channels; i++) 280 p->chset.channels[i].private = p->effect + i; 281 } else { 282 for (i = 0; i < p->chset.max_channels; i++) 283 p->chset.channels[i].private = NULL; 284 } 285} 286 287void 288snd_emux_delete_effect(struct snd_emux_port *p) 289{ 290 kfree(p->effect); 291 p->effect = NULL; 292} 293 294void 295snd_emux_clear_effect(struct snd_emux_port *p) 296{ 297 if (p->effect) { 298 memset(p->effect, 0, sizeof(struct snd_emux_effect_table) * 299 p->chset.max_channels); 300 } 301} 302 303#endif /* SNDRV_EMUX_USE_RAW_EFFECT */