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