387 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * NRPN / SYSEX callbacks for Emu8k/Emu10k14 *5 * Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de>6 */7 8#include "emux_voice.h"9#include <sound/asoundef.h>10 11/*12 * conversion from NRPN/control parameters to Emu8000 raw parameters13 */14 15/* NRPN / CC -> Emu8000 parameter converter */16struct nrpn_conv_table {17 int control;18 int effect;19 int (*convert)(int val);20};21 22/* effect sensitivity */23 24#define FX_CUTOFF 025#define FX_RESONANCE 126#define FX_ATTACK 227#define FX_RELEASE 328#define FX_VIBRATE 429#define FX_VIBDEPTH 530#define FX_VIBDELAY 631#define FX_NUMS 732 33/*34 * convert NRPN/control values35 */36 37static int send_converted_effect(const struct nrpn_conv_table *table,38 int num_tables,39 struct snd_emux_port *port,40 struct snd_midi_channel *chan,41 int type, int val, int mode)42{43 int i, cval;44 for (i = 0; i < num_tables; i++) {45 if (table[i].control == type) {46 cval = table[i].convert(val);47 snd_emux_send_effect(port, chan, table[i].effect,48 cval, mode);49 return 1;50 }51 }52 return 0;53}54 55#define DEF_FX_CUTOFF 17056#define DEF_FX_RESONANCE 657#define DEF_FX_ATTACK 5058#define DEF_FX_RELEASE 5059#define DEF_FX_VIBRATE 3060#define DEF_FX_VIBDEPTH 461#define DEF_FX_VIBDELAY 150062 63/* effect sensitivities for GS NRPN:64 * adjusted for chaos 8MB soundfonts65 */66static const int gs_sense[] =67{68 DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,69 DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY70};71 72/* effect sensitivities for XG controls:73 * adjusted for chaos 8MB soundfonts74 */75static const int xg_sense[] =76{77 DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,78 DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY79};80 81 82/*83 * AWE32 NRPN effects84 */85 86static int fx_delay(int val);87static int fx_attack(int val);88static int fx_hold(int val);89static int fx_decay(int val);90static int fx_the_value(int val);91static int fx_twice_value(int val);92static int fx_conv_pitch(int val);93static int fx_conv_Q(int val);94 95/* function for each NRPN */ /* [range] units */96#define fx_env1_delay fx_delay /* [0,5900] 4msec */97#define fx_env1_attack fx_attack /* [0,5940] 1msec */98#define fx_env1_hold fx_hold /* [0,8191] 1msec */99#define fx_env1_decay fx_decay /* [0,5940] 4msec */100#define fx_env1_release fx_decay /* [0,5940] 4msec */101#define fx_env1_sustain fx_the_value /* [0,127] 0.75dB */102#define fx_env1_pitch fx_the_value /* [-127,127] 9.375cents */103#define fx_env1_cutoff fx_the_value /* [-127,127] 56.25cents */104 105#define fx_env2_delay fx_delay /* [0,5900] 4msec */106#define fx_env2_attack fx_attack /* [0,5940] 1msec */107#define fx_env2_hold fx_hold /* [0,8191] 1msec */108#define fx_env2_decay fx_decay /* [0,5940] 4msec */109#define fx_env2_release fx_decay /* [0,5940] 4msec */110#define fx_env2_sustain fx_the_value /* [0,127] 0.75dB */111 112#define fx_lfo1_delay fx_delay /* [0,5900] 4msec */113#define fx_lfo1_freq fx_twice_value /* [0,127] 84mHz */114#define fx_lfo1_volume fx_twice_value /* [0,127] 0.1875dB */115#define fx_lfo1_pitch fx_the_value /* [-127,127] 9.375cents */116#define fx_lfo1_cutoff fx_twice_value /* [-64,63] 56.25cents */117 118#define fx_lfo2_delay fx_delay /* [0,5900] 4msec */119#define fx_lfo2_freq fx_twice_value /* [0,127] 84mHz */120#define fx_lfo2_pitch fx_the_value /* [-127,127] 9.375cents */121 122#define fx_init_pitch fx_conv_pitch /* [-8192,8192] cents */123#define fx_chorus fx_the_value /* [0,255] -- */124#define fx_reverb fx_the_value /* [0,255] -- */125#define fx_cutoff fx_twice_value /* [0,127] 62Hz */126#define fx_filterQ fx_conv_Q /* [0,127] -- */127 128static int fx_delay(int val)129{130 return (unsigned short)snd_sf_calc_parm_delay(val);131}132 133static int fx_attack(int val)134{135 return (unsigned short)snd_sf_calc_parm_attack(val);136}137 138static int fx_hold(int val)139{140 return (unsigned short)snd_sf_calc_parm_hold(val);141}142 143static int fx_decay(int val)144{145 return (unsigned short)snd_sf_calc_parm_decay(val);146}147 148static int fx_the_value(int val)149{150 return (unsigned short)(val & 0xff);151}152 153static int fx_twice_value(int val)154{155 return (unsigned short)((val * 2) & 0xff);156}157 158static int fx_conv_pitch(int val)159{160 return (short)(val * 4096 / 1200);161}162 163static int fx_conv_Q(int val)164{165 return (unsigned short)((val / 8) & 0xff);166}167 168 169static const struct nrpn_conv_table awe_effects[] =170{171 { 0, EMUX_FX_LFO1_DELAY, fx_lfo1_delay},172 { 1, EMUX_FX_LFO1_FREQ, fx_lfo1_freq},173 { 2, EMUX_FX_LFO2_DELAY, fx_lfo2_delay},174 { 3, EMUX_FX_LFO2_FREQ, fx_lfo2_freq},175 176 { 4, EMUX_FX_ENV1_DELAY, fx_env1_delay},177 { 5, EMUX_FX_ENV1_ATTACK,fx_env1_attack},178 { 6, EMUX_FX_ENV1_HOLD, fx_env1_hold},179 { 7, EMUX_FX_ENV1_DECAY, fx_env1_decay},180 { 8, EMUX_FX_ENV1_SUSTAIN, fx_env1_sustain},181 { 9, EMUX_FX_ENV1_RELEASE, fx_env1_release},182 183 {10, EMUX_FX_ENV2_DELAY, fx_env2_delay},184 {11, EMUX_FX_ENV2_ATTACK, fx_env2_attack},185 {12, EMUX_FX_ENV2_HOLD, fx_env2_hold},186 {13, EMUX_FX_ENV2_DECAY, fx_env2_decay},187 {14, EMUX_FX_ENV2_SUSTAIN, fx_env2_sustain},188 {15, EMUX_FX_ENV2_RELEASE, fx_env2_release},189 190 {16, EMUX_FX_INIT_PITCH, fx_init_pitch},191 {17, EMUX_FX_LFO1_PITCH, fx_lfo1_pitch},192 {18, EMUX_FX_LFO2_PITCH, fx_lfo2_pitch},193 {19, EMUX_FX_ENV1_PITCH, fx_env1_pitch},194 {20, EMUX_FX_LFO1_VOLUME, fx_lfo1_volume},195 {21, EMUX_FX_CUTOFF, fx_cutoff},196 {22, EMUX_FX_FILTERQ, fx_filterQ},197 {23, EMUX_FX_LFO1_CUTOFF, fx_lfo1_cutoff},198 {24, EMUX_FX_ENV1_CUTOFF, fx_env1_cutoff},199 {25, EMUX_FX_CHORUS, fx_chorus},200 {26, EMUX_FX_REVERB, fx_reverb},201};202 203 204/*205 * GS(SC88) NRPN effects; still experimental206 */207 208/* cutoff: quarter semitone step, max=255 */209static int gs_cutoff(int val)210{211 return (val - 64) * gs_sense[FX_CUTOFF] / 50;212}213 214/* resonance: 0 to 15(max) */215static int gs_filterQ(int val)216{217 return (val - 64) * gs_sense[FX_RESONANCE] / 50;218}219 220/* attack: */221static int gs_attack(int val)222{223 return -(val - 64) * gs_sense[FX_ATTACK] / 50;224}225 226/* decay: */227static int gs_decay(int val)228{229 return -(val - 64) * gs_sense[FX_RELEASE] / 50;230}231 232/* release: */233static int gs_release(int val)234{235 return -(val - 64) * gs_sense[FX_RELEASE] / 50;236}237 238/* vibrato freq: 0.042Hz step, max=255 */239static int gs_vib_rate(int val)240{241 return (val - 64) * gs_sense[FX_VIBRATE] / 50;242}243 244/* vibrato depth: max=127, 1 octave */245static int gs_vib_depth(int val)246{247 return (val - 64) * gs_sense[FX_VIBDEPTH] / 50;248}249 250/* vibrato delay: -0.725msec step */251static int gs_vib_delay(int val)252{253 return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;254}255 256static const struct nrpn_conv_table gs_effects[] =257{258 {32, EMUX_FX_CUTOFF, gs_cutoff},259 {33, EMUX_FX_FILTERQ, gs_filterQ},260 {99, EMUX_FX_ENV2_ATTACK, gs_attack},261 {100, EMUX_FX_ENV2_DECAY, gs_decay},262 {102, EMUX_FX_ENV2_RELEASE, gs_release},263 {8, EMUX_FX_LFO1_FREQ, gs_vib_rate},264 {9, EMUX_FX_LFO1_VOLUME, gs_vib_depth},265 {10, EMUX_FX_LFO1_DELAY, gs_vib_delay},266};267 268 269/*270 * NRPN events271 */272void273snd_emux_nrpn(void *p, struct snd_midi_channel *chan,274 struct snd_midi_channel_set *chset)275{276 struct snd_emux_port *port;277 278 port = p;279 if (snd_BUG_ON(!port || !chan))280 return;281 282 if (chan->control[MIDI_CTL_NONREG_PARM_NUM_MSB] == 127 &&283 chan->control[MIDI_CTL_NONREG_PARM_NUM_LSB] <= 26) {284 int val;285 /* Win/DOS AWE32 specific NRPNs */286 /* both MSB/LSB necessary */287 val = (chan->control[MIDI_CTL_MSB_DATA_ENTRY] << 7) |288 chan->control[MIDI_CTL_LSB_DATA_ENTRY]; 289 val -= 8192;290 send_converted_effect291 (awe_effects, ARRAY_SIZE(awe_effects),292 port, chan, chan->control[MIDI_CTL_NONREG_PARM_NUM_LSB],293 val, EMUX_FX_FLAG_SET);294 return;295 }296 297 if (port->chset.midi_mode == SNDRV_MIDI_MODE_GS &&298 chan->control[MIDI_CTL_NONREG_PARM_NUM_MSB] == 1) {299 int val;300 /* GS specific NRPNs */301 /* only MSB is valid */302 val = chan->control[MIDI_CTL_MSB_DATA_ENTRY];303 send_converted_effect304 (gs_effects, ARRAY_SIZE(gs_effects),305 port, chan, chan->control[MIDI_CTL_NONREG_PARM_NUM_LSB],306 val, EMUX_FX_FLAG_ADD);307 return;308 }309}310 311 312/*313 * XG control effects; still experimental314 */315 316/* cutoff: quarter semitone step, max=255 */317static int xg_cutoff(int val)318{319 return (val - 64) * xg_sense[FX_CUTOFF] / 64;320}321 322/* resonance: 0(open) to 15(most nasal) */323static int xg_filterQ(int val)324{325 return (val - 64) * xg_sense[FX_RESONANCE] / 64;326}327 328/* attack: */329static int xg_attack(int val)330{331 return -(val - 64) * xg_sense[FX_ATTACK] / 64;332}333 334/* release: */335static int xg_release(int val)336{337 return -(val - 64) * xg_sense[FX_RELEASE] / 64;338}339 340static const struct nrpn_conv_table xg_effects[] =341{342 {71, EMUX_FX_CUTOFF, xg_cutoff},343 {74, EMUX_FX_FILTERQ, xg_filterQ},344 {72, EMUX_FX_ENV2_RELEASE, xg_release},345 {73, EMUX_FX_ENV2_ATTACK, xg_attack},346};347 348int349snd_emux_xg_control(struct snd_emux_port *port, struct snd_midi_channel *chan,350 int param)351{352 if (param >= ARRAY_SIZE(chan->control))353 return -EINVAL;354 355 return send_converted_effect(xg_effects, ARRAY_SIZE(xg_effects),356 port, chan, param,357 chan->control[param],358 EMUX_FX_FLAG_ADD);359}360 361/*362 * receive sysex363 */364void365snd_emux_sysex(void *p, unsigned char *buf, int len, int parsed,366 struct snd_midi_channel_set *chset)367{368 struct snd_emux_port *port;369 struct snd_emux *emu;370 371 port = p;372 if (snd_BUG_ON(!port || !chset))373 return;374 emu = port->emu;375 376 switch (parsed) {377 case SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME:378 snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME);379 break;380 default:381 if (emu->ops.sysex)382 emu->ops.sysex(emu, buf, len, parsed, chset);383 break;384 }385}386 387