1/*
2 *  Routines for Gravis UltraSound soundcards - Simple instrument handlers
3 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 *   This program is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation; either version 2 of the License, or
9 *   (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *   GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with this program; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/time.h>
24#include <sound/core.h>
25#include <sound/gus.h>
26#include "gus_tables.h"
27
28/*
29 *
30 */
31
32static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice);
33static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice);
34static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice);
35
36static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position);
37static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode);
38static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq);
39static void sample_volume(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume);
40static void sample_loop(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop);
41static void sample_pos(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position);
42static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data);
43
44static struct snd_gus_sample_ops sample_ops = {
45	sample_start,
46	sample_stop,
47	sample_freq,
48	sample_volume,
49	sample_loop,
50	sample_pos,
51	sample_private1
52};
53
54
55static void do_volume_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice);
56static void do_pan_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice);
57
58/*
59 *
60 */
61
62static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice)
63{
64	spin_lock(&gus->event_lock);
65	snd_gf1_stop_voice(gus, voice->number);
66	spin_lock(&gus->reg_lock);
67	snd_gf1_select_voice(gus, voice->number);
68	snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0);
69	spin_unlock(&gus->reg_lock);
70	voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
71	spin_unlock(&gus->event_lock);
72}
73
74static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice)
75{
76	spin_lock(&gus->event_lock);
77	if (voice->flags & SNDRV_GF1_VFLG_RUNNING)
78		do_volume_envelope(gus, voice);
79	else
80		snd_gf1_stop_voice(gus, voice->number);
81	spin_unlock(&gus->event_lock);
82}
83
84static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice)
85{
86	spin_lock(&gus->event_lock);
87	if ((voice->flags & (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) ==
88	                    (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1))
89		do_pan_envelope(gus, voice);
90	spin_unlock(&gus->event_lock);
91}
92
93/*
94 *
95 */
96
97static void do_volume_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice)
98{
99	unsigned short next, rate, old_volume;
100	int program_next_ramp;
101	unsigned long flags;
102
103	if (!gus->gf1.volume_ramp) {
104		spin_lock_irqsave(&gus->reg_lock, flags);
105		snd_gf1_select_voice(gus, voice->number);
106		snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
107		snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume);
108		/* printk("gf1_volume = 0x%x\n", voice->gf1_volume); */
109		spin_unlock_irqrestore(&gus->reg_lock, flags);
110		return;
111	}
112	program_next_ramp = 0;
113	rate = next = 0;
114	while (1) {
115		program_next_ramp = 0;
116		rate = next = 0;
117		switch (voice->venv_state) {
118		case VENV_BEFORE:
119			voice->venv_state = VENV_ATTACK;
120			voice->venv_value_next = 0;
121			spin_lock_irqsave(&gus->reg_lock, flags);
122			snd_gf1_select_voice(gus, voice->number);
123			snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
124			snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
125			spin_unlock_irqrestore(&gus->reg_lock, flags);
126			break;
127		case VENV_ATTACK:
128			voice->venv_state = VENV_SUSTAIN;
129			program_next_ramp++;
130			next = 255;
131			rate = gus->gf1.volume_ramp;
132			break;
133		case VENV_SUSTAIN:
134			voice->venv_state = VENV_RELEASE;
135			spin_lock_irqsave(&gus->reg_lock, flags);
136			snd_gf1_select_voice(gus, voice->number);
137			snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
138 			snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, ((int)voice->gf1_volume * (int)voice->venv_value_next) / 255);
139			spin_unlock_irqrestore(&gus->reg_lock, flags);
140			return;
141		case VENV_RELEASE:
142			voice->venv_state = VENV_DONE;
143			program_next_ramp++;
144			next = 0;
145			rate = gus->gf1.volume_ramp;
146			break;
147		case VENV_DONE:
148			snd_gf1_stop_voice(gus, voice->number);
149			voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
150			return;
151		case VENV_VOLUME:
152			program_next_ramp++;
153			next = voice->venv_value_next;
154			rate = gus->gf1.volume_ramp;
155			voice->venv_state = voice->venv_state_prev;
156			break;
157		}
158		voice->venv_value_next = next;
159		if (!program_next_ramp)
160			continue;
161		spin_lock_irqsave(&gus->reg_lock, flags);
162		snd_gf1_select_voice(gus, voice->number);
163		snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
164		old_volume = snd_gf1_read16(gus, SNDRV_GF1_VW_VOLUME) >> 8;
165		if (!rate) {
166			spin_unlock_irqrestore(&gus->reg_lock, flags);
167			continue;
168		}
169		next = (((int)voice->gf1_volume * (int)next) / 255) >> 8;
170		if (old_volume < SNDRV_GF1_MIN_OFFSET)
171			old_volume = SNDRV_GF1_MIN_OFFSET;
172		if (next < SNDRV_GF1_MIN_OFFSET)
173			next = SNDRV_GF1_MIN_OFFSET;
174		if (next > SNDRV_GF1_MAX_OFFSET)
175			next = SNDRV_GF1_MAX_OFFSET;
176		if (old_volume == next) {
177			spin_unlock_irqrestore(&gus->reg_lock, flags);
178			continue;
179		}
180		voice->volume_control &= ~0xc3;
181		voice->volume_control |= 0x20;
182		if (old_volume > next) {
183			snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, next);
184			snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, old_volume);
185			voice->volume_control |= 0x40;
186		} else {
187			snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, old_volume);
188			snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, next);
189		}
190		snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, rate);
191		snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
192		if (!gus->gf1.enh_mode) {
193			snd_gf1_delay(gus);
194			snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
195		}
196		spin_unlock_irqrestore(&gus->reg_lock, flags);
197		return;
198	}
199}
200
201static void do_pan_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice)
202{
203	unsigned long flags;
204	unsigned char old_pan;
205
206	if (gus->gf1.enh_mode) {
207		voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
208		return;
209	}
210	if (!gus->gf1.smooth_pan) {
211		spin_lock_irqsave(&gus->reg_lock, flags);
212		snd_gf1_select_voice(gus, voice->number);
213		snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
214		spin_unlock_irqrestore(&gus->reg_lock, flags);
215		return;
216	}
217	if (!(voice->flags & SNDRV_GF1_VFLG_PAN))		/* before */
218		voice->flags |= SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN;
219	spin_lock_irqsave(&gus->reg_lock, flags);
220	snd_gf1_select_voice(gus, voice->number);
221	old_pan = snd_gf1_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f;
222	if (old_pan > voice->gf1_pan )
223		old_pan--;
224	if (old_pan < voice->gf1_pan)
225		old_pan++;
226	snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, old_pan);
227	spin_unlock_irqrestore(&gus->reg_lock, flags);
228	if (old_pan == voice->gf1_pan)			/* the goal was reached */
229		voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
230}
231
232static void set_enhanced_pan(struct snd_gus_card *gus, struct snd_gus_voice *voice, unsigned short pan)
233{
234	unsigned long flags;
235	unsigned short vlo, vro;
236
237	vlo = SNDRV_GF1_ATTEN((SNDRV_GF1_ATTEN_TABLE_SIZE-1) - pan);
238	vro = SNDRV_GF1_ATTEN(pan);
239	if (pan != SNDRV_GF1_ATTEN_TABLE_SIZE - 1 && pan != 0) {
240		vlo >>= 1;
241		vro >>= 1;
242	}
243	vlo <<= 4;
244	vro <<= 4;
245	spin_lock_irqsave(&gus->reg_lock, flags);
246	snd_gf1_select_voice(gus, voice->number);
247        snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, vlo);
248	snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, vro);
249	spin_unlock_irqrestore(&gus->reg_lock, flags);
250	voice->vlo = vlo;
251	voice->vro = vro;
252}
253
254/*
255 *
256 */
257
258static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position)
259{
260	unsigned long flags;
261	unsigned int begin, addr, addr_end, addr_start;
262	int w_16;
263	struct simple_instrument *simple;
264	struct snd_seq_kinstr *instr;
265
266	instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
267	if (instr == NULL)
268		return;
269	voice->instr = instr->instr;	/* copy ID to speedup aliases */
270	simple = KINSTR_DATA(instr);
271	begin = simple->address.memory << 4;
272	w_16 = simple->format & SIMPLE_WAVE_16BIT ? 0x04 : 0;
273	addr_start = simple->loop_start;
274	if (simple->format & SIMPLE_WAVE_LOOP) {
275		addr_end = simple->loop_end;
276	} else {
277		addr_end = (simple->size << 4) - (w_16 ? 40 : 24);
278	}
279	if (simple->format & SIMPLE_WAVE_BACKWARD) {
280		addr = simple->loop_end;
281		if (position < simple->loop_end)
282			addr -= position;
283	} else {
284		addr = position;
285	}
286	voice->control = 0x00;
287	voice->mode = 0x20;		/* enable offset registers */
288	if (simple->format & SIMPLE_WAVE_16BIT)
289		voice->control |= 0x04;
290	if (simple->format & SIMPLE_WAVE_BACKWARD)
291		voice->control |= 0x40;
292	if (simple->format & SIMPLE_WAVE_LOOP) {
293		voice->control |= 0x08;
294	} else {
295		voice->control |= 0x20;
296	}
297	if (simple->format & SIMPLE_WAVE_BIDIR)
298		voice->control |= 0x10;
299	if (simple->format & SIMPLE_WAVE_ULAW)
300		voice->mode |= 0x40;
301	if (w_16) {
302		addr = ((addr << 1) & ~0x1f) | (addr & 0x0f);
303		addr_start = ((addr_start << 1) & ~0x1f) | (addr_start & 0x0f);
304		addr_end = ((addr_end << 1) & ~0x1f) | (addr_end & 0x0f);
305	}
306	addr += begin;
307	addr_start += begin;
308	addr_end += begin;
309	snd_gf1_stop_voice(gus, voice->number);
310	spin_lock_irqsave(&gus->reg_lock, flags);
311	snd_gf1_select_voice(gus, voice->number);
312	snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
313	voice->venv_state = VENV_BEFORE;
314	voice->volume_control = 0x03;
315	snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
316	snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
317	snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
318	if (!gus->gf1.enh_mode) {
319		snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
320	} else {
321		snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT, voice->vlo);
322		snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, voice->vlo);
323		snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT, voice->vro);
324		snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, voice->vro);
325		snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, voice->effect_accumulator);
326		snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, voice->gf1_effect_volume);
327		snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, voice->gf1_effect_volume);
328	}
329	spin_unlock_irqrestore(&gus->reg_lock, flags);
330	do_volume_envelope(gus, voice);
331	spin_lock_irqsave(&gus->reg_lock, flags);
332	snd_gf1_select_voice(gus, voice->number);
333	if (gus->gf1.enh_mode)
334		snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, voice->mode);
335	snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control);
336	if (!gus->gf1.enh_mode) {
337		snd_gf1_delay(gus);
338		snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control );
339	}
340	spin_unlock_irqrestore(&gus->reg_lock, flags);
341	voice->flags |= SNDRV_GF1_VFLG_RUNNING;
342	snd_seq_instr_free_use(gus->gf1.ilist, instr);
343}
344
345static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode)
346{
347	unsigned char control;
348	unsigned long flags;
349
350	if (!(voice->flags & SNDRV_GF1_VFLG_RUNNING))
351		return;
352	switch (mode) {
353	default:
354		if (gus->gf1.volume_ramp > 0) {
355			if (voice->venv_state < VENV_RELEASE) {
356				voice->venv_state = VENV_RELEASE;
357				do_volume_envelope(gus, voice);
358			}
359		}
360		if (mode != SAMPLE_STOP_VENVELOPE) {
361			snd_gf1_stop_voice(gus, voice->number);
362			spin_lock_irqsave(&gus->reg_lock, flags);
363			snd_gf1_select_voice(gus, voice->number);
364			snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
365			spin_unlock_irqrestore(&gus->reg_lock, flags);
366			voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
367		}
368		break;
369	case SAMPLE_STOP_LOOP:		/* disable loop only */
370		spin_lock_irqsave(&gus->reg_lock, flags);
371		snd_gf1_select_voice(gus, voice->number);
372		control = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
373		control &= ~(0x83 | 0x04);
374		control |= 0x20;
375		snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, control);
376		spin_unlock_irqrestore(&gus->reg_lock, flags);
377		break;
378	}
379}
380
381static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq)
382{
383	unsigned long flags;
384
385	spin_lock_irqsave(&gus->reg_lock, flags);
386	voice->fc_register = snd_gf1_translate_freq(gus, freq);
387	snd_gf1_select_voice(gus, voice->number);
388	snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
389	spin_unlock_irqrestore(&gus->reg_lock, flags);
390}
391
392static void sample_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume)
393{
394	if (volume->volume >= 0) {
395		volume->volume &= 0x3fff;
396		voice->gf1_volume = snd_gf1_lvol_to_gvol_raw(volume->volume << 2) << 4;
397		voice->venv_state_prev = VENV_SUSTAIN;
398		voice->venv_state = VENV_VOLUME;
399		do_volume_envelope(gus, voice);
400        }
401	if (volume->lr >= 0) {
402		volume->lr &= 0x3fff;
403		if (!gus->gf1.enh_mode) {
404			voice->gf1_pan = (volume->lr >> 10) & 15;
405			if (!gus->gf1.full_range_pan) {
406				if (voice->gf1_pan == 0)
407					voice->gf1_pan++;
408				if (voice->gf1_pan == 15)
409					voice->gf1_pan--;
410			}
411			voice->flags &= ~SNDRV_GF1_VFLG_PAN;	/* before */
412			do_pan_envelope(gus, voice);
413		} else {
414			set_enhanced_pan(gus, voice, volume->lr >> 7);
415		}
416	}
417}
418
419static void sample_loop(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop)
420{
421	unsigned long flags;
422	int w_16 = voice->control & 0x04;
423	unsigned int begin, addr_start, addr_end;
424	struct simple_instrument *simple;
425	struct snd_seq_kinstr *instr;
426
427	instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
428	if (instr == NULL)
429		return;
430	voice->instr = instr->instr;	/* copy ID to speedup aliases */
431	simple = KINSTR_DATA(instr);
432	begin = simple->address.memory;
433	addr_start = loop->start;
434	addr_end = loop->end;
435	addr_start = (((addr_start << 1) & ~0x1f) | (addr_start & 0x0f)) + begin;
436	addr_end = (((addr_end << 1) & ~0x1f) | (addr_end & 0x0f)) + begin;
437	spin_lock_irqsave(&gus->reg_lock, flags);
438	snd_gf1_select_voice(gus, voice->number);
439	snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
440	snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
441	spin_unlock_irqrestore(&gus->reg_lock, flags);
442	snd_seq_instr_free_use(gus->gf1.ilist, instr);
443}
444
445static void sample_pos(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position)
446{
447	unsigned long flags;
448	int w_16 = voice->control & 0x04;
449	unsigned int begin, addr;
450	struct simple_instrument *simple;
451	struct snd_seq_kinstr *instr;
452
453	instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
454	if (instr == NULL)
455		return;
456	voice->instr = instr->instr;	/* copy ID to speedup aliases */
457	simple = KINSTR_DATA(instr);
458	begin = simple->address.memory;
459	addr = (((position << 1) & ~0x1f) | (position & 0x0f)) + begin;
460	spin_lock_irqsave(&gus->reg_lock, flags);
461	snd_gf1_select_voice(gus, voice->number);
462	snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
463	spin_unlock_irqrestore(&gus->reg_lock, flags);
464	snd_seq_instr_free_use(gus->gf1.ilist, instr);
465}
466
467
468static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data)
469{
470}
471
472
473void snd_gf1_simple_init(struct snd_gus_voice *voice)
474{
475	voice->handler_wave = interrupt_wave;
476	voice->handler_volume = interrupt_volume;
477	voice->handler_effect = interrupt_effect;
478	voice->volume_change = NULL;
479	voice->sample_ops = &sample_ops;
480}
481