2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for control of LFO generators (tremolo & vibrato) for
4 * GF1/InterWave chips...
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <sound/driver.h>
24 #include <sound/core.h>
25 #include <sound/gus.h>
28 * called by engine routines
31 static signed char snd_gf1_lfo_compute_value(snd_gus_card_t
* gus
,
34 unsigned int twaveinc
, depth_delta
;
36 unsigned short control
, twave
, depth
, depth_final
;
39 control
= *(unsigned short *) (ptr
+ 0x00);
40 ptr1
= ptr
+ ((control
& 0x4000) >> 12);
41 /* 1. add TWAVEINC to TWAVE and write the result back */
42 /* LFO update rate is 689Hz, effect timer is in ms */
43 if (gus
->gf1
.timer_slave
)
44 twaveinc
= (689 * gus
->gf1
.timer_master_gus
->gf1
.effect_timer
) / 1000;
46 twaveinc
= (689 * gus
->gf1
.effect_timer
) / 1000;
50 printk("twaveinc = 0x%x, effect_timer = %i\n", twaveinc
, gus
->gf1
.effect_timer
);
53 depth
= *(unsigned short *) (ptr1
+ 0x0a);
54 depth_final
= *(unsigned char *) (ptr
+ 0x02) << 5;
55 if (depth
!= depth_final
) {
56 depth_delta
= ((twaveinc
* *(ptr
+ 0x03)) + *(unsigned short *) (ptr
+ 0x04));
57 *(unsigned short *) (ptr
+ 0x04) = depth_delta
% 8000;
59 if (depth
< depth_final
) {
60 if (depth
+ depth_delta
> depth_final
)
65 if (depth
> depth_final
) {
66 if (depth
- depth_delta
< depth_final
)
71 *(unsigned short *) (ptr1
+ 0x0a) = depth
;
73 twaveinc
*= (unsigned int) control
& 0x7ff;
74 twaveinc
+= *(unsigned short *) (ptr
+ 0x06);
75 *(unsigned short *) (ptr
+ 0x06) = twaveinc
% 1000;
77 twave
= *(unsigned short *) (ptr1
+ 0x08);
78 twave
+= (unsigned short) (twaveinc
/ (unsigned int) 1000);
79 *(unsigned short *) (ptr1
+ 0x08) = twave
;
81 if (!(control
& 0x2000)) {
82 /* 2. if shift is low */
83 if (twave
& 0x4000) { /* bit 14 high -> invert TWAVE 13-0 */
87 /* TWAVE bit 15 is exclusive or'd with the invert bit (12) */
88 twave
^= (control
& 0x1000) << 3;
90 /* 2. if shift is high */
91 if (twave
& 0x8000) /* bit 15 high -> invert TWAVE 14-0 */
93 /* the invert bit (12) is used as sign bit */
99 /* 3. multiply the 14-bit LFO waveform magnitude by 13-bit DEPTH */
101 printk("c=0x%x,tw=0x%x,to=0x%x,d=0x%x,df=0x%x,di=0x%x,r=0x%x,r1=%i\n",
103 *(unsigned short *) (ptr1
+ 0x08),
104 depth
, depth_final
, *(ptr
+ 0x03),
105 (twave
& 0x7fff) * depth
, ((twave
& 0x7fff) * depth
) >> 21);
107 result
= (twave
& 0x7fff) * depth
;
117 printk("lfo final value = %i\n", result
);
122 static void snd_gf1_lfo_register_setup(snd_gus_card_t
* gus
,
123 snd_gf1_voice_t
* voice
,
128 if (gus
->gf1
.enh_mode
) {
130 gf1_select_voice(gus
, voice
->number
);
132 snd_gf1_write8(gus
, GF1_VB_FREQUENCY_LFO
, voice
->lfo_fc
);
136 snd_gf1_write8(gus
, GF1_VB_VOLUME_LFO
, voice
->lfo_volume
);
137 voice
->lfo_volume
= 0;
142 * ok.. with old GF1 chip can be only vibrato emulated...
143 * volume register can be in volume ramp state, so tremolo isn't simple..
149 printk("setup - %i = %i\n", voice
->number
, voice
->lfo_fc
);
152 gf1_select_voice(gus
, voice
->number
);
153 snd_gf1_write16(gus
, GF1_VW_FREQUENCY
, voice
->fc_register
+ voice
->lfo_fc
);
158 void snd_gf1_lfo_effect_interrupt(snd_gus_card_t
* gus
, snd_gf1_voice_t
* voice
)
163 if (voice
->number
!= 0)
166 ptr
= gus
->gf1
.lfos
+ ((voice
->number
) << 5);
168 if (*(unsigned short *) (ptr
+ 0x00) & 0x8000)
169 voice
->lfo_fc
= snd_gf1_lfo_compute_value(gus
, ptr
);
172 if (*(unsigned short *) (ptr
+ 0x00) & 0x8000)
173 voice
->lfo_volume
= snd_gf1_lfo_compute_value(gus
, ptr
);
174 /* 3. register setup */
175 snd_gf1_lfo_register_setup(gus
, voice
, 3);
182 void snd_gf1_lfo_init(snd_gus_card_t
* gus
)
184 if (gus
->gf1
.hw_lfo
) {
185 snd_gf1_i_write16(gus
, GF1_GW_LFO_BASE
, 0x0000);
186 snd_gf1_dram_setmem(gus
, 0, 0x0000, 1024);
188 snd_gf1_i_write8(gus
, GF1_GB_GLOBAL_MODE
, snd_gf1_i_look8(gus
, GF1_GB_GLOBAL_MODE
) | 0x02);
190 if (gus
->gf1
.sw_lfo
) {
192 gus
->gf1
.lfos
= snd_calloc(1024);
199 void snd_gf1_lfo_done(snd_gus_card_t
* gus
)
201 if (gus
->gf1
.sw_lfo
) {
203 snd_gf1_free(gus
->gf1
.lfos
, 1024);
204 gus
->gf1
.lfos
= NULL
;
209 void snd_gf1_lfo_program(snd_gus_card_t
* gus
, int voice
, int lfo_type
,
210 struct ULTRA_STRU_IW_LFO_PROGRAM
*program
)
212 unsigned int lfo_addr
, wave_select
;
214 wave_select
= (program
->freq_and_control
& 0x4000) >> 12;
215 lfo_addr
= (voice
<< 5) | (lfo_type
<< 4);
216 if (gus
->gf1
.hw_lfo
) {
218 printk("LMCI = 0x%x\n", snd_gf1_i_look8(gus
, 0x53));
219 printk("lfo_program: lfo_addr=0x%x,wave_sel=0x%x,fac=0x%x,df=0x%x,di=0x%x,twave=0x%x,depth=0x%x\n",
220 lfo_addr
, wave_select
,
221 program
->freq_and_control
,
222 program
->depth_final
,
227 snd_gf1_poke(gus
, lfo_addr
+ 0x02, program
->depth_final
);
228 snd_gf1_poke(gus
, lfo_addr
+ 0x03, program
->depth_inc
);
229 snd_gf1_pokew(gus
, lfo_addr
+ 0x08 + wave_select
, program
->twave
);
230 snd_gf1_pokew(gus
, lfo_addr
+ 0x0a + wave_select
, program
->depth
);
231 snd_gf1_pokew(gus
, lfo_addr
+ 0x00, program
->freq_and_control
);
235 for (i
= 0; i
< 16; i
++)
236 printk("%02x:", snd_gf1_peek(gus
, lfo_addr
+ i
));
241 if (gus
->gf1
.sw_lfo
) {
242 unsigned char *ptr
= gus
->gf1
.lfos
+ lfo_addr
;
244 *(ptr
+ 0x02) = program
->depth_final
;
245 *(ptr
+ 0x03) = program
->depth_inc
;
246 *(unsigned short *) (ptr
+ 0x08 + wave_select
) = program
->twave
;
247 *(unsigned short *) (ptr
+ 0x0a + wave_select
) = program
->depth
;
248 *(unsigned short *) (ptr
+ 0x00) = program
->freq_and_control
;
252 void snd_gf1_lfo_enable(snd_gus_card_t
* gus
, int voice
, int lfo_type
)
254 unsigned int lfo_addr
;
256 lfo_addr
= (voice
<< 5) | (lfo_type
<< 4);
258 snd_gf1_pokew(gus
, lfo_addr
+ 0x00, snd_gf1_peekw(gus
, lfo_addr
+ 0x00) | 0x8000);
259 if (gus
->gf1
.sw_lfo
) {
260 unsigned char *ptr
= gus
->gf1
.lfos
+ lfo_addr
;
262 *(unsigned short *) (ptr
+ 0x00) |= 0x8000;
266 void snd_gf1_lfo_disable(snd_gus_card_t
* gus
, int voice
, int lfo_type
)
268 unsigned int lfo_addr
;
270 lfo_addr
= (voice
<< 5) | (lfo_type
<< 4);
272 snd_gf1_pokew(gus
, lfo_addr
+ 0x00,
273 snd_gf1_peekw(gus
, lfo_addr
+ 0x00) & ~0x8000);
274 if (gus
->gf1
.sw_lfo
) {
275 unsigned char *ptr
= gus
->gf1
.lfos
+ lfo_addr
;
277 *(unsigned short *) (ptr
+ 0x00) &= ~0x8000;
281 void snd_gf1_lfo_change_freq(snd_gus_card_t
* gus
, int voice
,
282 int lfo_type
, int freq
)
284 unsigned int lfo_addr
;
286 lfo_addr
= (voice
<< 5) | (lfo_type
<< 4);
288 snd_gf1_pokew(gus
, lfo_addr
+ 0x00,
289 (snd_gf1_peekw(gus
, lfo_addr
+ 0x00) & ~0x7ff) | (freq
& 0x7ff));
290 if (gus
->gf1
.sw_lfo
) {
292 unsigned char *ptr
= gus
->gf1
.lfos
+ lfo_addr
;
295 *(unsigned short *) (ptr
+ 0x00) &= ~0x7ff;
296 *(unsigned short *) (ptr
+ 0x00) |= freq
& 0x7ff;
301 void snd_gf1_lfo_change_depth(snd_gus_card_t
* gus
, int voice
,
302 int lfo_type
, int depth
)
305 unsigned int lfo_addr
;
306 unsigned short control
= 0;
309 lfo_addr
= (voice
<< 5) | (lfo_type
<< 4);
310 ptr
= gus
->gf1
.lfos
+ lfo_addr
;
312 control
= snd_gf1_peekw(gus
, lfo_addr
+ 0x00);
314 control
= *(unsigned short *) (ptr
+ 0x00);
320 if (gus
->gf1
.hw_lfo
) {
322 snd_gf1_poke(gus
, lfo_addr
+ 0x02, (unsigned char) depth
);
323 snd_gf1_pokew(gus
, lfo_addr
+ 0x0a + ((control
& 0x4000) >> 12), depth
<< 5);
324 snd_gf1_pokew(gus
, lfo_addr
+ 0x00, control
);
327 if (gus
->gf1
.sw_lfo
) {
328 unsigned char *ptr
= gus
->gf1
.lfos
+ lfo_addr
;
331 *(ptr
+ 0x02) = (unsigned char) depth
;
332 *(unsigned short *) (ptr
+ 0x0a + ((control
& 0x4000) >> 12)) = depth
<< 5;
333 *(unsigned short *) (ptr
+ 0x00) = control
;
338 void snd_gf1_lfo_setup(snd_gus_card_t
* gus
, int voice
, int lfo_type
,
339 int freq
, int current_depth
, int depth
, int sweep
,
342 struct ULTRA_STRU_IW_LFO_PROGRAM program
;
344 program
.freq_and_control
= 0x8000 | (freq
& 0x7ff);
345 if (shape
& ULTRA_STRU_IW_LFO_SHAPE_POSTRIANGLE
)
346 program
.freq_and_control
|= 0x2000;
348 program
.freq_and_control
|= 0x1000;
352 program
.depth
= current_depth
;
353 program
.depth_final
= depth
;
355 program
.depth_inc
= (unsigned char) (((int) ((depth
<< 5) - current_depth
) << 9) / (sweep
* 4410L));
356 if (!program
.depth_inc
)
359 program
.depth
= (unsigned short) (depth
<< 5);
360 snd_gf1_lfo_program(gus
, voice
, lfo_type
, &program
);
363 void snd_gf1_lfo_shutdown(snd_gus_card_t
* gus
, int voice
, int lfo_type
)
366 unsigned int lfo_addr
;
368 lfo_addr
= (voice
<< 5) | (lfo_type
<< 4);
369 if (gus
->gf1
.hw_lfo
) {
370 snd_gf1_pokew(gus
, lfo_addr
+ 0x00, 0x0000);
372 gf1_select_voice(gus
, voice
);
373 snd_gf1_write8(gus
, lfo_type
== ULTRA_LFO_VIBRATO
? GF1_VB_FREQUENCY_LFO
: GF1_VB_VOLUME_LFO
, 0);
376 if (gus
->gf1
.sw_lfo
) {
377 unsigned char *ptr
= gus
->gf1
.lfos
+ lfo_addr
;
378 snd_gf1_voice_t
*pvoice
;
380 *(unsigned short *) (ptr
+ 0x00) = 0;
381 *(unsigned short *) (ptr
+ 0x04) = 0;
382 *(unsigned short *) (ptr
+ 0x06) = 0;
383 if (gus
->gf1
.syn_voices
) {
384 pvoice
= gus
->gf1
.syn_voices
+ voice
;
385 if (lfo_type
== ULTRA_LFO_VIBRATO
)
388 pvoice
->lfo_volume
= 0;
389 snd_gf1_lfo_register_setup(gus
, pvoice
, lfo_type
== ULTRA_LFO_VIBRATO
? 1 : 2);
390 } else if (gus
->gf1
.enh_mode
) {
392 gf1_select_voice(gus
, voice
);
393 snd_gf1_write8(gus
, lfo_type
== ULTRA_LFO_VIBRATO
? GF1_VB_FREQUENCY_LFO
: GF1_VB_VOLUME_LFO
, 0);
399 void snd_gf1_lfo_command(snd_gus_card_t
* gus
, int voice
, unsigned char *data
)
405 lfo_type
= *data
>> 7;
406 lfo_command
= *data
& 0x7f;
407 switch (lfo_command
) {
408 case ULTRA_LFO_SETUP
: /* setup */
409 temp1
= snd_gf1_get_word(data
, 2);
410 temp2
= snd_gf1_get_word(data
, 4);
411 snd_gf1_lfo_setup(gus
, voice
, lfo_type
, temp1
& 0x7ff, 0, temp2
> 255 ? 255 : temp2
, snd_gf1_get_byte(data
, 1), (temp1
& 0x2000) >> 13);
413 case ULTRA_LFO_FREQ
: /* freq */
414 snd_gf1_lfo_change_depth(gus
, voice
, lfo_type
, snd_gf1_get_word(data
, 2));
416 case ULTRA_LFO_DEPTH
: /* depth */
417 snd_gf1_lfo_change_freq(gus
, voice
, lfo_type
, snd_gf1_get_word(data
, 2));
419 case ULTRA_LFO_ENABLE
: /* enable */
420 snd_gf1_lfo_enable(gus
, voice
, lfo_type
);
422 case ULTRA_LFO_DISABLE
: /* disable */
423 snd_gf1_lfo_disable(gus
, voice
, lfo_type
);
425 case ULTRA_LFO_SHUTDOWN
: /* shutdown */
426 snd_gf1_lfo_shutdown(gus
, voice
, lfo_type
);