1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Midi synth routines for the Emu8k/Emu10k1
5 * Copyright (C) 1999 Steve Ratcliffe
6 * Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de>
8 * Contains code based on awe_wave.c by Takashi Iwai
11 #include "emux_voice.h"
12 #include <linux/slab.h>
14 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
19 #define xoffsetof(type,tag) ((long)(&((type)NULL)->tag) - (long)(NULL))
21 #define parm_offset(tag) xoffsetof(struct soundfont_voice_parm *, tag)
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)
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)
37 static 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 */
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 */
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 */
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 */
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 */
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 */
84 /* set byte effect value */
86 effect_set_byte(unsigned char *valp
, struct snd_midi_channel
*chan
, int type
)
89 struct snd_emux_effect_table
*fx
= chan
->private;
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
;
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
;
105 /* set word effect value */
107 effect_set_word(unsigned short *valp
, struct snd_midi_channel
*chan
, int type
)
110 struct snd_emux_effect_table
*fx
= chan
->private;
112 effect
= *(unsigned short*)&fx
->val
[type
];
113 if (fx
->flag
[type
] == EMUX_FX_FLAG_ADD
)
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
;
124 effect_get_offset(struct snd_midi_channel
*chan
, int lo
, int hi
, int mode
)
127 struct snd_emux_effect_table
*fx
= chan
->private;
130 addr
= (short)fx
->val
[hi
];
133 addr
+= (short)fx
->val
[lo
];
134 if (!(mode
& SNDRV_SFNT_SAMPLE_8BITS
))
139 #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
140 /* change effects - for OSS sequencer compatibility */
142 snd_emux_send_effect_oss(struct snd_emux_port
*port
,
143 struct snd_midi_channel
*chan
, int type
, int val
)
148 mode
= EMUX_FX_FLAG_OFF
;
149 else if (type
& 0x80)
150 mode
= EMUX_FX_FLAG_ADD
;
152 mode
= EMUX_FX_FLAG_SET
;
155 snd_emux_send_effect(port
, chan
, type
, val
, mode
);
159 /* Modify the effect value.
160 * if update is necessary, call emu8000_control
163 snd_emux_send_effect(struct snd_emux_port
*port
, struct snd_midi_channel
*chan
,
164 int type
, int val
, int mode
)
168 unsigned char *srcp
, *origp
;
169 struct snd_emux
*emu
;
170 struct snd_emux_effect_table
*fx
;
175 if (emu
== NULL
|| fx
== NULL
)
177 if (type
< 0 || type
>= EMUX_NUM_EFFECTS
)
181 fx
->flag
[type
] = mode
;
183 /* do we need to modify the register in realtime ? */
184 if (! parm_defs
[type
].update
|| (offset
= parm_defs
[type
].offset
) < 0)
187 #ifdef SNDRV_LITTLE_ENDIAN
188 if (parm_defs
[type
].type
& PARM_IS_ALIGN_HI
)
191 if (parm_defs
[type
].type
& PARM_IS_ALIGN_LO
)
194 /* modify the register values */
195 spin_lock_irqsave(&emu
->voice_lock
, flags
);
196 for (i
= 0; i
< emu
->max_voices
; i
++) {
197 struct snd_emux_voice
*vp
= &emu
->voices
[i
];
198 if (!STATE_IS_PLAYING(vp
->state
) || vp
->chan
!= chan
)
200 srcp
= (unsigned char*)&vp
->reg
.parm
+ offset
;
201 origp
= (unsigned char*)&vp
->zone
->v
.parm
+ offset
;
202 if (parm_defs
[i
].type
& PARM_IS_BYTE
) {
204 effect_set_byte(srcp
, chan
, type
);
206 *(unsigned short*)srcp
= *(unsigned short*)origp
;
207 effect_set_word((unsigned short*)srcp
, chan
, type
);
210 spin_unlock_irqrestore(&emu
->voice_lock
, flags
);
213 snd_emux_update_channel(port
, chan
, parm_defs
[type
].update
);
217 /* copy wavetable registers to voice table */
219 snd_emux_setup_effect(struct snd_emux_voice
*vp
)
221 struct snd_midi_channel
*chan
= vp
->chan
;
222 struct snd_emux_effect_table
*fx
;
226 if (! (fx
= chan
->private))
229 /* modify the register values via effect table */
230 for (i
= 0; i
< EMUX_FX_END
; i
++) {
232 if (! fx
->flag
[i
] || (offset
= parm_defs
[i
].offset
) < 0)
234 #ifdef SNDRV_LITTLE_ENDIAN
235 if (parm_defs
[i
].type
& PARM_IS_ALIGN_HI
)
238 if (parm_defs
[i
].type
& PARM_IS_ALIGN_LO
)
241 srcp
= (unsigned char*)&vp
->reg
.parm
+ offset
;
242 if (parm_defs
[i
].type
& PARM_IS_BYTE
)
243 effect_set_byte(srcp
, chan
, i
);
245 effect_set_word((unsigned short*)srcp
, chan
, i
);
248 /* correct sample and loop points */
249 vp
->reg
.start
+= effect_get_offset(chan
, EMUX_FX_SAMPLE_START
,
250 EMUX_FX_COARSE_SAMPLE_START
,
251 vp
->reg
.sample_mode
);
253 vp
->reg
.loopstart
+= effect_get_offset(chan
, EMUX_FX_LOOP_START
,
254 EMUX_FX_COARSE_LOOP_START
,
255 vp
->reg
.sample_mode
);
257 vp
->reg
.loopend
+= effect_get_offset(chan
, EMUX_FX_LOOP_END
,
258 EMUX_FX_COARSE_LOOP_END
,
259 vp
->reg
.sample_mode
);
266 snd_emux_create_effect(struct snd_emux_port
*p
)
269 p
->effect
= kcalloc(p
->chset
.max_channels
,
270 sizeof(struct snd_emux_effect_table
), GFP_KERNEL
);
272 for (i
= 0; i
< p
->chset
.max_channels
; i
++)
273 p
->chset
.channels
[i
].private = p
->effect
+ i
;
275 for (i
= 0; i
< p
->chset
.max_channels
; i
++)
276 p
->chset
.channels
[i
].private = NULL
;
281 snd_emux_delete_effect(struct snd_emux_port
*p
)
288 snd_emux_clear_effect(struct snd_emux_port
*p
)
291 memset(p
->effect
, 0, sizeof(struct snd_emux_effect_table
) *
292 p
->chset
.max_channels
);
296 #endif /* SNDRV_EMUX_USE_RAW_EFFECT */