initial commit with v2.6.9
[linux-2.6.9-moxart.git] / sound / isa / gus / gus_lfo.c
blob94d0688502051fd374abe5b5d191fb2d7943e6ee
1 /*
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,
32 unsigned char *ptr)
34 unsigned int twaveinc, depth_delta;
35 signed int result;
36 unsigned short control, twave, depth, depth_final;
37 unsigned char *ptr1;
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;
45 else
46 twaveinc = (689 * gus->gf1.effect_timer) / 1000;
47 if (!twaveinc)
48 twaveinc++;
49 #if 0
50 printk("twaveinc = 0x%x, effect_timer = %i\n", twaveinc, gus->gf1.effect_timer);
51 #endif
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;
58 depth_delta /= 8000;
59 if (depth < depth_final) {
60 if (depth + depth_delta > depth_final)
61 depth = depth_final;
62 else
63 depth += depth_delta;
65 if (depth > depth_final) {
66 if (depth - depth_delta < depth_final)
67 depth = depth_final;
68 else
69 depth -= depth_delta;
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 */
84 twave ^= 0x3fff;
85 twave &= ~0x4000;
87 /* TWAVE bit 15 is exclusive or'd with the invert bit (12) */
88 twave ^= (control & 0x1000) << 3;
89 } else {
90 /* 2. if shift is high */
91 if (twave & 0x8000) /* bit 15 high -> invert TWAVE 14-0 */
92 twave ^= 0x7fff;
93 /* the invert bit (12) is used as sign bit */
94 if (control & 0x1000)
95 twave |= 0x8000;
96 else
97 twave &= ~0x8000;
99 /* 3. multiply the 14-bit LFO waveform magnitude by 13-bit DEPTH */
100 #if 0
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",
102 control, twave,
103 *(unsigned short *) (ptr1 + 0x08),
104 depth, depth_final, *(ptr + 0x03),
105 (twave & 0x7fff) * depth, ((twave & 0x7fff) * depth) >> 21);
106 #endif
107 result = (twave & 0x7fff) * depth;
108 if (result) {
109 /* shift */
110 result >>= 21;
111 result &= 0x3f;
113 /* add sign */
114 if (twave & 0x8000)
115 result = -result;
116 #if 0
117 printk("lfo final value = %i\n", result);
118 #endif
119 return result;
122 static void snd_gf1_lfo_register_setup(snd_gus_card_t * gus,
123 snd_gf1_voice_t * voice,
124 int lfo_type)
126 unsigned long flags;
128 if (gus->gf1.enh_mode) {
129 CLI(&flags);
130 gf1_select_voice(gus, voice->number);
131 if (lfo_type & 1) {
132 snd_gf1_write8(gus, GF1_VB_FREQUENCY_LFO, voice->lfo_fc);
133 voice->lfo_fc = 0;
135 if (lfo_type & 2) {
136 snd_gf1_write8(gus, GF1_VB_VOLUME_LFO, voice->lfo_volume);
137 voice->lfo_volume = 0;
139 STI(&flags);
140 } else {
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..
145 if (!(lfo_type & 1))
146 return;
147 #if 0
148 if (voice->lfo_fc)
149 printk("setup - %i = %i\n", voice->number, voice->lfo_fc);
150 #endif
151 CLI(&flags);
152 gf1_select_voice(gus, voice->number);
153 snd_gf1_write16(gus, GF1_VW_FREQUENCY, voice->fc_register + voice->lfo_fc);
154 STI(&flags);
158 void snd_gf1_lfo_effect_interrupt(snd_gus_card_t * gus, snd_gf1_voice_t * voice)
160 unsigned char *ptr;
162 #if 0
163 if (voice->number != 0)
164 return;
165 #endif
166 ptr = gus->gf1.lfos + ((voice->number) << 5);
167 /* 1. vibrato */
168 if (*(unsigned short *) (ptr + 0x00) & 0x8000)
169 voice->lfo_fc = snd_gf1_lfo_compute_value(gus, ptr);
170 /* 2. tremolo */
171 ptr += 16;
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);
187 /* now enable LFO */
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) {
191 #if 1
192 gus->gf1.lfos = snd_calloc(1024);
193 if (!gus->gf1.lfos)
194 #endif
195 gus->gf1.sw_lfo = 0;
199 void snd_gf1_lfo_done(snd_gus_card_t * gus)
201 if (gus->gf1.sw_lfo) {
202 if (gus->gf1.lfos) {
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) {
217 #if 0
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,
223 program->depth_inc,
224 program->twave,
225 program->depth);
226 #endif
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);
232 #if 0
234 int i = 0;
235 for (i = 0; i < 16; i++)
236 printk("%02x:", snd_gf1_peek(gus, lfo_addr + i));
237 printk("\n");
239 #endif
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);
257 if (gus->gf1.hw_lfo)
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);
271 if (gus->gf1.hw_lfo)
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);
287 if (gus->gf1.hw_lfo)
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) {
291 unsigned long flags;
292 unsigned char *ptr = gus->gf1.lfos + lfo_addr;
294 CLI(&flags);
295 *(unsigned short *) (ptr + 0x00) &= ~0x7ff;
296 *(unsigned short *) (ptr + 0x00) |= freq & 0x7ff;
297 STI(&flags);
301 void snd_gf1_lfo_change_depth(snd_gus_card_t * gus, int voice,
302 int lfo_type, int depth)
304 unsigned long flags;
305 unsigned int lfo_addr;
306 unsigned short control = 0;
307 unsigned char *ptr;
309 lfo_addr = (voice << 5) | (lfo_type << 4);
310 ptr = gus->gf1.lfos + lfo_addr;
311 if (gus->gf1.hw_lfo)
312 control = snd_gf1_peekw(gus, lfo_addr + 0x00);
313 if (gus->gf1.sw_lfo)
314 control = *(unsigned short *) (ptr + 0x00);
315 if (depth < 0) {
316 control |= 0x1000;
317 depth = -depth;
318 } else
319 control &= ~0x1000;
320 if (gus->gf1.hw_lfo) {
321 CLI(&flags);
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);
325 STI(&flags);
327 if (gus->gf1.sw_lfo) {
328 unsigned char *ptr = gus->gf1.lfos + lfo_addr;
330 CLI(&flags);
331 *(ptr + 0x02) = (unsigned char) depth;
332 *(unsigned short *) (ptr + 0x0a + ((control & 0x4000) >> 12)) = depth << 5;
333 *(unsigned short *) (ptr + 0x00) = control;
334 STI(&flags);
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,
340 int shape)
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;
347 if (depth < 0) {
348 program.freq_and_control |= 0x1000;
349 depth = -depth;
351 program.twave = 0;
352 program.depth = current_depth;
353 program.depth_final = depth;
354 if (sweep) {
355 program.depth_inc = (unsigned char) (((int) ((depth << 5) - current_depth) << 9) / (sweep * 4410L));
356 if (!program.depth_inc)
357 program.depth_inc++;
358 } else
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)
365 unsigned long flags;
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);
371 CLI(&flags);
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);
374 STI(&flags);
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)
386 pvoice->lfo_fc = 0;
387 else
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) {
391 CLI(&flags);
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);
394 STI(&flags);
399 void snd_gf1_lfo_command(snd_gus_card_t * gus, int voice, unsigned char *data)
401 int lfo_type;
402 int lfo_command;
403 int temp1, temp2;
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);
412 break;
413 case ULTRA_LFO_FREQ: /* freq */
414 snd_gf1_lfo_change_depth(gus, voice, lfo_type, snd_gf1_get_word(data, 2));
415 break;
416 case ULTRA_LFO_DEPTH: /* depth */
417 snd_gf1_lfo_change_freq(gus, voice, lfo_type, snd_gf1_get_word(data, 2));
418 break;
419 case ULTRA_LFO_ENABLE: /* enable */
420 snd_gf1_lfo_enable(gus, voice, lfo_type);
421 break;
422 case ULTRA_LFO_DISABLE: /* disable */
423 snd_gf1_lfo_disable(gus, voice, lfo_type);
424 break;
425 case ULTRA_LFO_SHUTDOWN: /* shutdown */
426 snd_gf1_lfo_shutdown(gus, voice, lfo_type);
427 break;