Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
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 | |
1da177e4 LT |
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 | ||
03da312a | 21 | #define parm_offset(tag) xoffsetof(struct soundfont_voice_parm *, tag) |
1da177e4 LT |
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 | ||
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 */ | |
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 */ | |
85 | static void | |
03da312a | 86 | effect_set_byte(unsigned char *valp, struct snd_midi_channel *chan, int type) |
1da177e4 LT |
87 | { |
88 | short effect; | |
03da312a | 89 | struct snd_emux_effect_table *fx = chan->private; |
1da177e4 LT |
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 */ | |
106 | static void | |
03da312a | 107 | effect_set_word(unsigned short *valp, struct snd_midi_channel *chan, int type) |
1da177e4 LT |
108 | { |
109 | int effect; | |
03da312a | 110 | struct snd_emux_effect_table *fx = chan->private; |
1da177e4 LT |
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 */ | |
123 | static int | |
03da312a | 124 | effect_get_offset(struct snd_midi_channel *chan, int lo, int hi, int mode) |
1da177e4 LT |
125 | { |
126 | int addr = 0; | |
03da312a | 127 | struct snd_emux_effect_table *fx = chan->private; |
1da177e4 LT |
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 | ||
3d774d5e | 139 | #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) |
1da177e4 LT |
140 | /* change effects - for OSS sequencer compatibility */ |
141 | void | |
03da312a TI |
142 | snd_emux_send_effect_oss(struct snd_emux_port *port, |
143 | struct snd_midi_channel *chan, int type, int val) | |
1da177e4 LT |
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 | */ | |
162 | void | |
03da312a TI |
163 | snd_emux_send_effect(struct snd_emux_port *port, struct snd_midi_channel *chan, |
164 | int type, int val, int mode) | |
1da177e4 LT |
165 | { |
166 | int i; | |
167 | int offset; | |
168 | unsigned char *srcp, *origp; | |
03da312a TI |
169 | struct snd_emux *emu; |
170 | struct snd_emux_effect_table *fx; | |
1da177e4 LT |
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 ? */ | |
dd1fc3c5 TI |
184 | if (!parm_defs[type].update) |
185 | return; | |
186 | offset = parm_defs[type].offset; | |
187 | if (offset < 0) | |
1da177e4 LT |
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++) { | |
03da312a | 200 | struct snd_emux_voice *vp = &emu->voices[i]; |
1da177e4 LT |
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 */ | |
221 | void | |
03da312a | 222 | snd_emux_setup_effect(struct snd_emux_voice *vp) |
1da177e4 | 223 | { |
03da312a TI |
224 | struct snd_midi_channel *chan = vp->chan; |
225 | struct snd_emux_effect_table *fx; | |
1da177e4 LT |
226 | unsigned char *srcp; |
227 | int i; | |
228 | ||
dd1fc3c5 TI |
229 | fx = chan->private; |
230 | if (!fx) | |
1da177e4 LT |
231 | return; |
232 | ||
233 | /* modify the register values via effect table */ | |
234 | for (i = 0; i < EMUX_FX_END; i++) { | |
235 | int offset; | |
dd1fc3c5 TI |
236 | if (!fx->flag[i]) |
237 | continue; | |
238 | offset = parm_defs[i].offset; | |
239 | if (offset < 0) | |
1da177e4 LT |
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 | */ | |
272 | void | |
03da312a | 273 | snd_emux_create_effect(struct snd_emux_port *p) |
1da177e4 LT |
274 | { |
275 | int i; | |
03da312a TI |
276 | p->effect = kcalloc(p->chset.max_channels, |
277 | sizeof(struct snd_emux_effect_table), GFP_KERNEL); | |
1da177e4 LT |
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 | ||
287 | void | |
03da312a | 288 | snd_emux_delete_effect(struct snd_emux_port *p) |
1da177e4 | 289 | { |
4d572776 JJ |
290 | kfree(p->effect); |
291 | p->effect = NULL; | |
1da177e4 LT |
292 | } |
293 | ||
294 | void | |
03da312a | 295 | snd_emux_clear_effect(struct snd_emux_port *p) |
1da177e4 LT |
296 | { |
297 | if (p->effect) { | |
03da312a TI |
298 | memset(p->effect, 0, sizeof(struct snd_emux_effect_table) * |
299 | p->chset.max_channels); | |
1da177e4 LT |
300 | } |
301 | } | |
302 | ||
303 | #endif /* SNDRV_EMUX_USE_RAW_EFFECT */ |