ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / sound / isa / gus / gus_lfo.c
1 /*
2  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3  *  Routines for control of LFO generators (tremolo & vibrato) for
4  *  GF1/InterWave chips...
5  *
6  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #include <sound/driver.h>
24 #include <sound/core.h>
25 #include <sound/gus.h>
26
27 /*
28  *  called by engine routines
29  */
30
31 static signed char snd_gf1_lfo_compute_value(snd_gus_card_t * gus,
32                                              unsigned char *ptr)
33 {
34         unsigned int twaveinc, depth_delta;
35         signed int result;
36         unsigned short control, twave, depth, depth_final;
37         unsigned char *ptr1;
38
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
52
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;
64                 }
65                 if (depth > depth_final) {
66                         if (depth - depth_delta < depth_final)
67                                 depth = depth_final;
68                         else
69                                 depth -= depth_delta;
70                 }
71                 *(unsigned short *) (ptr1 + 0x0a) = depth;
72         }
73         twaveinc *= (unsigned int) control & 0x7ff;
74         twaveinc += *(unsigned short *) (ptr + 0x06);
75         *(unsigned short *) (ptr + 0x06) = twaveinc % 1000;
76
77         twave = *(unsigned short *) (ptr1 + 0x08);
78         twave += (unsigned short) (twaveinc / (unsigned int) 1000);
79         *(unsigned short *) (ptr1 + 0x08) = twave;
80
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;
86                 }
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;
98         }
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;
112         }
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;
120 }
121
122 static void snd_gf1_lfo_register_setup(snd_gus_card_t * gus,
123                                        snd_gf1_voice_t * voice,
124                                        int lfo_type)
125 {
126         unsigned long flags;
127
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;
134                 }
135                 if (lfo_type & 2) {
136                         snd_gf1_write8(gus, GF1_VB_VOLUME_LFO, voice->lfo_volume);
137                         voice->lfo_volume = 0;
138                 }
139                 STI(&flags);
140         } else {
141                 /*
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..
144                  */
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);
155         }
156 }
157
158 void snd_gf1_lfo_effect_interrupt(snd_gus_card_t * gus, snd_gf1_voice_t * voice)
159 {
160         unsigned char *ptr;
161
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);
176 }
177
178 /*
179
180  */
181
182 void snd_gf1_lfo_init(snd_gus_card_t * gus)
183 {
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);
189         }
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;
196         }
197 }
198
199 void snd_gf1_lfo_done(snd_gus_card_t * gus)
200 {
201         if (gus->gf1.sw_lfo) {
202                 if (gus->gf1.lfos) {
203                         snd_gf1_free(gus->gf1.lfos, 1024);
204                         gus->gf1.lfos = NULL;
205                 }
206         }
207 }
208
209 void snd_gf1_lfo_program(snd_gus_card_t * gus, int voice, int lfo_type,
210                          struct ULTRA_STRU_IW_LFO_PROGRAM *program)
211 {
212         unsigned int lfo_addr, wave_select;
213
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
233                 {
234                         int i = 0;
235                         for (i = 0; i < 16; i++)
236                                 printk("%02x:", snd_gf1_peek(gus, lfo_addr + i));
237                         printk("\n");
238                 }
239 #endif
240         }
241         if (gus->gf1.sw_lfo) {
242                 unsigned char *ptr = gus->gf1.lfos + lfo_addr;
243
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;
249         }
250 }
251
252 void snd_gf1_lfo_enable(snd_gus_card_t * gus, int voice, int lfo_type)
253 {
254         unsigned int lfo_addr;
255
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;
261
262                 *(unsigned short *) (ptr + 0x00) |= 0x8000;
263         }
264 }
265
266 void snd_gf1_lfo_disable(snd_gus_card_t * gus, int voice, int lfo_type)
267 {
268         unsigned int lfo_addr;
269
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;
276
277                 *(unsigned short *) (ptr + 0x00) &= ~0x8000;
278         }
279 }
280
281 void snd_gf1_lfo_change_freq(snd_gus_card_t * gus, int voice,
282                              int lfo_type, int freq)
283 {
284         unsigned int lfo_addr;
285
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;
293
294                 CLI(&flags);
295                 *(unsigned short *) (ptr + 0x00) &= ~0x7ff;
296                 *(unsigned short *) (ptr + 0x00) |= freq & 0x7ff;
297                 STI(&flags);
298         }
299 }
300
301 void snd_gf1_lfo_change_depth(snd_gus_card_t * gus, int voice,
302                               int lfo_type, int depth)
303 {
304         unsigned long flags;
305         unsigned int lfo_addr;
306         unsigned short control = 0;
307         unsigned char *ptr;
308
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);
326         }
327         if (gus->gf1.sw_lfo) {
328                 unsigned char *ptr = gus->gf1.lfos + lfo_addr;
329
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);
335         }
336 }
337
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)
341 {
342         struct ULTRA_STRU_IW_LFO_PROGRAM program;
343
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;
350         }
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);
361 }
362
363 void snd_gf1_lfo_shutdown(snd_gus_card_t * gus, int voice, int lfo_type)
364 {
365         unsigned long flags;
366         unsigned int lfo_addr;
367
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);
375         }
376         if (gus->gf1.sw_lfo) {
377                 unsigned char *ptr = gus->gf1.lfos + lfo_addr;
378                 snd_gf1_voice_t *pvoice;
379
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);
395                 }
396         }
397 }
398
399 void snd_gf1_lfo_command(snd_gus_card_t * gus, int voice, unsigned char *data)
400 {
401         int lfo_type;
402         int lfo_command;
403         int temp1, temp2;
404
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;
428         }
429 }