patch-2.1.67 linux/drivers/sound/lowlevel/awe_wave.c

Next file: linux/drivers/sound/mad16.c
Previous file: linux/drivers/sound/lowlevel/awe_voice.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/awe_wave.c linux/drivers/sound/lowlevel/awe_wave.c
@@ -2,7 +2,7 @@
  * sound/awe_wave.c
  *
  * The low level driver for the AWE32/Sound Blaster 32 wave table synth.
- *   version 0.4.2; Sep. 1, 1997
+ *   version 0.4.2c; Oct. 7, 1997
  *
  * Copyright (C) 1996,1997 Takashi Iwai
  *
@@ -24,12 +24,18 @@
 #ifdef __FreeBSD__
 #  include <i386/isa/sound/awe_config.h>
 #else
+#ifdef MODULE
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#  include "../soundmodule.h"
+#endif
 #  include "awe_config.h"
 #endif
 
 /*----------------------------------------------------------------*/
 
-#ifdef CONFIG_AWE32_SYNTH
+#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE)
 
 #ifdef __FreeBSD__
 #  include <i386/isa/sound/awe_hw.h>
@@ -96,20 +102,21 @@
 
 /* bank record */
 typedef struct _awe_voice_list {
-	int next;	/* index list */
-	unsigned char bank, instr;
-	char type, disabled;
-	awe_voice_info v;
+	int next;	/* linked list with same sf_id */
+	unsigned char bank, instr;	/* preset number information */
+	char type, disabled;	/* type=normal/mapped, disabled=boolean */
+	awe_voice_info v;	/* voice information */
 	int next_instr;	/* preset table list */
 	int next_bank;	/* preset table list */
 } awe_voice_list;
 
+/* voice list type */
 #define V_ST_NORMAL	0
 #define V_ST_MAPPED	1
 
 typedef struct _awe_sample_list {
-	int next;	/* sf list */
-	awe_sample_info v;
+	int next;	/* linked list with same sf_id */
+	awe_sample_info v;	/* sample information */
 } awe_sample_list;
 
 /* sample and information table */
@@ -153,6 +160,7 @@
 
 /* channel parameters */
 typedef struct _awe_chan_info {
+	int channel;		/* channel number */
 	int bank;		/* current tone bank */
 	int instr;		/* current program */
 	int bender;		/* midi pitchbend (-8192 - 8192) */
@@ -163,9 +171,9 @@
 	int chan_press;		/* channel pressure */
 	int vrec;		/* instrument list */
 	int def_vrec;		/* default instrument list */
+	int sustained;		/* sustain status in MIDI */
 	FX_Rec fx;		/* effects */
 	FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
-	int sustained;		/* sustain status in MIDI */
 } awe_chan_info;
 
 /* voice parameters */
@@ -203,6 +211,7 @@
 #define IS_NO_SOUND(v)	(voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))
 #define IS_NO_EFFECT(v)	(voices[v].state != AWE_ST_ON)
 #define IS_PLAYING(v)	(voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))
+#define IS_EMPTY(v)	(voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))
 
 
 /* MIDI channel effects information (for hw control) */
@@ -233,15 +242,20 @@
 
 static int patch_opened = 0;		/* sample already loaded? */
 
-static int reverb_mode = 3;		/* reverb mode */
-static int chorus_mode = 5;		/* chorus mode */
+static int reverb_mode = 4;		/* reverb mode */
+static int chorus_mode = 2;		/* chorus mode */
 static short init_atten = AWE_DEFAULT_ATTENUATION; /* 12dB below */
 
 static int awe_present = FALSE;		/* awe device present? */
 static int awe_busy = FALSE;		/* awe device opened? */
 
+static int my_dev = -1;			
+static int my_mixerdev = -1 ;
+
 #define DEFAULT_DRUM_FLAGS	((1 << 9) | (1 << 25))
 #define IS_DRUM_CHANNEL(c)	(drum_flags & (1 << (c)))
+#define DRUM_CHANNEL_ON(c)	(drum_flags |= (1 << (c)))
+#define DRUM_CHANNEL_OFF(c)	(drum_flags &= ~(1 << (c)))
 static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */
 
 static int playing_mode = AWE_PLAY_INDIRECT;
@@ -266,6 +280,7 @@
 	{AWE_DEFAULT_PRESET, TRUE}, /* def_preset */
 	{AWE_DEFAULT_BANK, TRUE}, /* def_bank */
 	{AWE_DEFAULT_DRUM, TRUE}, /* def_drum */
+	{FALSE, TRUE}, /* toggle_drum_bank */
 };
 
 static int misc_modes[AWE_MD_END];
@@ -341,12 +356,15 @@
 static void awe_fx_fmmod(int voice, int forced);
 static void awe_fx_tremfrq(int voice, int forced);
 static void awe_fx_fm2frq2(int voice, int forced);
+static void awe_fx_filterQ(int voice, int forced);
 static void awe_calc_pitch(int voice);
 #ifdef AWE_HAS_GUS_COMPATIBILITY
 static void awe_calc_pitch_from_freq(int voice, int freq);
 #endif
 static void awe_calc_volume(int voice);
-static void awe_voice_init(int voice, int keep_ch_info);
+static void awe_voice_init(int voice, int init_all);
+static void awe_channel_init(int ch, int init_all);
+static void awe_fx_init(int ch);
 
 /* sequencer interface */
 static int awe_open(int dev, int mode);
@@ -379,6 +397,7 @@
 static void awe_voice_change(int voice, fx_affect_func func);
 static void awe_sostenuto_on(int voice, int forced);
 static void awe_sustain_off(int voice, int forced);
+static void awe_terminate_and_init(int voice, int forced);
 
 /* voice search */
 static int awe_search_instr(int bank, int preset);
@@ -446,7 +465,7 @@
 static struct synth_operations awe_operations =
 {
 #ifdef AWE_OSS38
-	"Emu8000",
+	"EMU8K",
 #endif
 	&awe_info,
 	0,
@@ -532,17 +551,17 @@
 	INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list);
 	INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list);
 
-	if (num_synths >= MAX_SYNTH_DEV)
-		printk("AWE32 Error: too many synthesizers\n");
+	if (my_dev=sound_alloc_synthdev())
+		printk(KERN_WARNING "AWE32 Error: too many synthesizers\n");
 	else {
 		voice_alloc = &awe_operations.alloc;
 		voice_alloc->max_voice = awe_max_voices;
-		synth_devs[num_synths++] = &awe_operations;
+		synth_devs[my_dev] = &awe_operations;
 	}
 
 #ifdef CONFIG_AWE32_MIXER
-	if (num_mixers < MAX_MIXER_DEV) {
-		mixer_devs[num_mixers++] = &awe_mixer_operations;
+	if (my_mixerdev=sound_alloc_mixerdev()) {
+		mixer_devs[my_mixerdev] = &awe_mixer_operations;
 	}
 #endif
 
@@ -600,6 +619,8 @@
 		my_free(voices);
 		my_free(channels);
 		free_tables();
+		sound_unload_mixerdev(my_mixerdev);
+		sound_unload_synthdev(my_dev);
 		awe_present = FALSE;
 	}
 }
@@ -1054,16 +1075,70 @@
  *================================================================*/
 
 /* set an effect value */
+#define FX_FLAG_OFF	0
+#define FX_FLAG_SET	1
+#define FX_FLAG_ADD	2
+
 #define FX_SET(rec,type,value) \
-	((rec)->flags[type] = 1, (rec)->val[type] = (value))
+	((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value))
 #define FX_ADD(rec,type,value) \
-	((rec)->flags[type] = 2, (rec)->val[type] = (value))
+	((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value))
 #define FX_UNSET(rec,type) \
-	((rec)->flags[type] = 0, (rec)->val[type] = 0)
+	((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0)
 
 /* check the effect value is set */
 #define FX_ON(rec,type)	((rec)->flags[type])
 
+#define PARM_BYTE	0
+#define PARM_WORD	1
+
+static struct PARM_DEFS {
+	int type;	/* byte or word */
+	int low, high;	/* value range */
+	fx_affect_func realtime;	/* realtime paramater change */
+} parm_defs[] = {
+	{PARM_WORD, 0, 0x8000, NULL},	/* env1 delay */
+	{PARM_BYTE, 1, 0x7f, NULL},	/* env1 attack */
+	{PARM_BYTE, 0, 0x7e, NULL},	/* env1 hold */
+	{PARM_BYTE, 1, 0x7f, NULL},	/* env1 decay */
+	{PARM_BYTE, 1, 0x7f, NULL},	/* env1 release */
+	{PARM_BYTE, 0, 0x7f, NULL},	/* env1 sustain */
+	{PARM_BYTE, 0, 0xff, NULL},	/* env1 pitch */
+	{PARM_BYTE, 0, 0xff, NULL},	/* env1 cutoff */
+
+	{PARM_WORD, 0, 0x8000, NULL},	/* env2 delay */
+	{PARM_BYTE, 1, 0x7f, NULL},	/* env2 attack */
+	{PARM_BYTE, 0, 0x7e, NULL},	/* env2 hold */
+	{PARM_BYTE, 1, 0x7f, NULL},	/* env2 decay */
+	{PARM_BYTE, 1, 0x7f, NULL},	/* env2 release */
+	{PARM_BYTE, 0, 0x7f, NULL},	/* env2 sustain */
+
+	{PARM_WORD, 0, 0x8000, NULL},	/* lfo1 delay */
+	{PARM_BYTE, 0, 0xff, awe_fx_tremfrq},	/* lfo1 freq */
+	{PARM_BYTE, 0, 0x7f, awe_fx_tremfrq},	/* lfo1 volume (positive only)*/
+	{PARM_BYTE, 0, 0x7f, awe_fx_fmmod},	/* lfo1 pitch (positive only)*/
+	{PARM_BYTE, 0, 0xff, awe_fx_fmmod},	/* lfo1 cutoff (positive only)*/
+
+	{PARM_WORD, 0, 0x8000, NULL},	/* lfo2 delay */
+	{PARM_BYTE, 0, 0xff, awe_fx_fm2frq2},	/* lfo2 freq */
+	{PARM_BYTE, 0, 0x7f, awe_fx_fm2frq2},	/* lfo2 pitch (positive only)*/
+
+	{PARM_WORD, 0, 0xffff, awe_set_voice_pitch},	/* initial pitch */
+	{PARM_BYTE, 0, 0xff, NULL},	/* chorus */
+	{PARM_BYTE, 0, 0xff, NULL},	/* reverb */
+	{PARM_BYTE, 0, 0xff, awe_set_volume},	/* initial cutoff */
+	{PARM_BYTE, 0, 15, awe_fx_filterQ},	/* initial resonance */
+
+	{PARM_WORD, 0, 0xffff, NULL},	/* sample start */
+	{PARM_WORD, 0, 0xffff, NULL},	/* loop start */
+	{PARM_WORD, 0, 0xffff, NULL},	/* loop end */
+	{PARM_WORD, 0, 0xffff, NULL},	/* coarse sample start */
+	{PARM_WORD, 0, 0xffff, NULL},	/* coarse loop start */
+	{PARM_WORD, 0, 0xffff, NULL},	/* coarse loop end */
+	{PARM_BYTE, 0, 0xff, awe_set_volume},	/* initial attenuation */
+};
+
+
 static unsigned char
 FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value)
 {
@@ -1073,10 +1148,15 @@
 		effect = lay->val[type];
 	if (!on && (on = FX_ON(rec, type)) != 0)
 		effect = rec->val[type];
-	if (on == 1)
+	if (on == FX_FLAG_ADD)
+		effect += (int)value;
+	if (on) {
+		if (effect < parm_defs[type].low)
+			effect = parm_defs[type].low;
+		else if (effect > parm_defs[type].high)
+			effect = parm_defs[type].high;
 		return (unsigned char)effect;
-	else if (on == 2)
-		return (unsigned char)(effect + (int)value);
+	}
 	return value;
 }
 
@@ -1090,10 +1170,15 @@
 		effect = lay->val[type];
 	if (!on && (on = FX_ON(rec, type)) != 0)
 		effect = rec->val[type];
-	if (on == 1)
+	if (on == FX_FLAG_ADD)
+		effect += (int)value;
+	if (on) {
+		if (effect < parm_defs[type].low)
+			effect = parm_defs[type].low;
+		else if (effect > parm_defs[type].high)
+			effect = parm_defs[type].high;
 		return (unsigned short)effect;
-	else if (on == 2)
-		return (unsigned short)(effect + (int)value);
+	}
 	return value;
 }
 
@@ -1229,6 +1314,12 @@
 	awe_poke_dw(AWE_CPF(voice), 0x40000000);
 
 	voices[voice].state = AWE_ST_ON;
+
+	/* clear voice position for the next note on this channel */
+	if (SINGLE_LAYER_MODE()) {
+		FX_UNSET(fx, AWE_FX_SAMPLE_START);
+		FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START);
+	}
 }
 
 
@@ -1254,7 +1345,7 @@
 	tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE,
 			       (unsigned char)vp->parm.volrelease);
 	awe_poke(AWE_DCYSUSV(voice), tmp);
-	awe_voice_init(voice, TRUE);
+	voices[voice].state = AWE_ST_RELEASED;
 }
 
 /* force to terminate the voice (no releasing echo) */
@@ -1263,7 +1354,7 @@
 {
 	awe_poke(AWE_DCYSUSV(voice), 0x807F);
 	awe_tweak_voice(voice);
-	awe_voice_init(voice, FALSE);
+	voices[voice].state = AWE_ST_OFF;
 }
 
 /* turn off other voices with the same exclusive class (for drums) */
@@ -1284,6 +1375,7 @@
 		    voices[i].sample->exclusiveClass == exclass) {
 			DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
 			awe_terminate(i);
+			awe_voice_init(i, TRUE);
 		}
 	}
 }
@@ -1321,7 +1413,7 @@
 	if (voices[voice].layer < MAX_LAYERS)
 		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
 
-	if (IS_NO_EFFECT(voice) && !forced) return;
+	if (!IS_PLAYING(voice) && !forced) return;
 	if ((vp = voices[voice].sample) == NULL || vp->index < 0)
 		return;
 
@@ -1336,6 +1428,8 @@
 static void
 awe_set_voice_vol(int voice, int forced)
 {
+	if (IS_EMPTY(voice))
+		return;
 	awe_calc_volume(voice);
 	awe_set_volume(voice, forced);
 }
@@ -1439,6 +1533,26 @@
 }
 
 
+/* Q & current address (Q 4bit value, MSB) */
+static void
+awe_fx_filterQ(int voice, int forced)
+{
+	unsigned int addr;
+	awe_voice_info *vp;
+	FX_Rec *fx = &voices[voice].cinfo->fx;
+	FX_Rec *fx_lay = NULL;
+	if (voices[voice].layer < MAX_LAYERS)
+		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+	if (IS_NO_EFFECT(voice) && !forced) return;
+	if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+		return;
+
+	addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
+	addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28);
+	awe_poke_dw(AWE_CCCA(voice), addr);
+}
+
 /*================================================================
  * calculate pitch offset
  *----------------------------------------------------------------
@@ -1472,6 +1586,8 @@
 		offset = (vp->note - ap->root) * 4096 / 12;
 		DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
 	}
+	offset = (offset * ap->scaleTuning) / 100;
+	DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
 	offset += ap->tune * 4096 / 1200;
 	DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
 	if (cp->bender != 0) {
@@ -1479,8 +1595,6 @@
 		/* (819200: 1 semitone) ==> (4096: 12 semitones) */
 		offset += cp->bender * cp->bender_range / 2400;
 	}
-	offset = (offset * ap->scaleTuning) / 100;
-	DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
 
 	/* add initial pitch correction */
 	if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH))
@@ -1603,8 +1717,20 @@
 /* drop sustain */
 static void awe_sustain_off(int voice, int forced)
 {
-	if (voices[voice].state == AWE_ST_SUSTAINED)
+	if (voices[voice].state == AWE_ST_SUSTAINED) {
 		awe_note_off(voice);
+		awe_fx_init(voices[voice].ch);
+		awe_voice_init(voice, FALSE);
+	}
+}
+
+
+/* terminate and initialize voice */
+static void awe_terminate_and_init(int voice, int forced)
+{
+	awe_terminate(voice);
+	awe_fx_init(voices[voice].ch);
+	awe_voice_init(voice, TRUE);
 }
 
 
@@ -1618,49 +1744,54 @@
 
 /* initialize the voice */
 static void
-awe_voice_init(int voice, int keep_ch_info)
+awe_voice_init(int voice, int init_all)
 {
 	voice_info *vp = &voices[voice];
-	vp->note = -1;
-	vp->velocity = 0;
-	vp->sostenuto = 0;
+
+	/* reset voice search key */
 	if (playing_mode == AWE_PLAY_DIRECT)
 		vp->key = AWE_VOICE_KEY(voice);
 	else
 		vp->key = 0;
+
+	/* clear voice mapping */
+	voice_alloc->map[voice] = 0;
+
+	/* touch the timing flag */
 	vp->time = current_alloc_time;
 
-	/* keep channel info for terminating release echo if necessary */
-	if (keep_ch_info)
-		vp->state = AWE_ST_RELEASED;
-	else {
+	/* initialize other parameters if necessary */
+	if (init_all) {
+		vp->note = -1;
+		vp->velocity = 0;
+		vp->sostenuto = 0;
+
 		vp->sample = NULL;
 		vp->cinfo = &channels[voice];
 		vp->ch = voice;
 		vp->state = AWE_ST_OFF;
-	}
-
-	/* emu8000 parameters */
-	vp->apitch = 0;
-	vp->avol = 255;
-	vp->apan = -1;
 
-	/* clear voice mapping */
-	voice_alloc->map[voice] = 0;
+		/* emu8000 parameters */
+		vp->apitch = 0;
+		vp->avol = 255;
+		vp->apan = -1;
+	}
+}
 
-	/* clear effects */
+/* clear effects */
+static void awe_fx_init(int ch)
+{
 	if (SINGLE_LAYER_MODE() && !misc_modes[AWE_MD_KEEP_EFFECT]) {
-		BZERO(&vp->cinfo->fx, sizeof(vp->cinfo->fx));
-		BZERO(&vp->cinfo->fx_layer, sizeof(vp->cinfo->fx_layer));
+		BZERO(&channels[ch].fx, sizeof(channels[ch].fx));
+		BZERO(&channels[ch].fx_layer, sizeof(&channels[ch].fx_layer));
 	}
-
-	/*awe_tweak_voice(voice);*/
 }
 
 /* initialize channel info */
 static void awe_channel_init(int ch, int init_all)
 {
 	awe_chan_info *cp = &channels[ch];
+	cp->channel = ch;
 	if (init_all) {
 		cp->panning = 0; /* zero center */
 		cp->bender_range = 200; /* sense * 100 */
@@ -1724,10 +1855,6 @@
 		return RET_ERROR(EBUSY);
 
 	awe_busy = TRUE;
-	awe_reset(dev);
-
-	/* clear sample position flag */
-	patch_opened = 0;
 
 	/* set default mode */
 	awe_init_misc_modes(FALSE);
@@ -1735,6 +1862,11 @@
 	drum_flags = DEFAULT_DRUM_FLAGS;
 	playing_mode = AWE_PLAY_INDIRECT;
 
+	/* reset voices & channels */
+	awe_reset(dev);
+
+	patch_opened = 0;
+
 	return 0;
 }
 
@@ -1818,8 +1950,11 @@
 	if (do_sustain && (voices[voice].cinfo->sustained == 127 ||
 			    voices[voice].sostenuto == 127))
 		voices[voice].state = AWE_ST_SUSTAINED;
-	else
+	else {
 		awe_note_off(voice);
+		awe_fx_init(voices[voice].ch);
+		awe_voice_init(voice, FALSE);
+	}
 }
 
 /* release all notes */
@@ -1941,10 +2076,11 @@
 	/* if the same note still playing, stop it */
 	for (i = 0; i < awe_max_voices; i++)
 		if (voices[i].key == key) {
-			if (voices[i].state == AWE_ST_ON)
+			if (voices[i].state == AWE_ST_ON) {
 				awe_note_off(i);
-			else if (voices[i].state == AWE_ST_STANDBY)
 				awe_voice_init(i, FALSE);
+			} else if (voices[i].state == AWE_ST_STANDBY)
+				awe_voice_init(i, TRUE);
 		}
 
 	/* allocate voices */
@@ -2008,19 +2144,18 @@
 		return RET_ERROR(EINVAL);
 
 	cinfo = &channels[voice];
-	def_bank = cinfo->bank;
 
-	if (MULTI_LAYER_MODE()) {
-		if (IS_DRUM_CHANNEL(voice))
-			def_bank = AWE_DRUM_BANK;
-	}
+	if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
+		def_bank = AWE_DRUM_BANK; /* always search drumset */
+	else
+		def_bank = cinfo->bank;
 
 	cinfo->vrec = -1;
 	cinfo->def_vrec = -1;
 	cinfo->vrec = awe_search_instr(def_bank, instr_no);
-	if (def_bank == AWE_DRUM_BANK)
+	if (def_bank == AWE_DRUM_BANK)	/* search default drumset */
 		cinfo->def_vrec = awe_search_instr(def_bank, misc_modes[AWE_MD_DEF_DRUM]);
-	else
+	else	/* search default preset */
 		cinfo->def_vrec = awe_search_instr(misc_modes[AWE_MD_DEF_BANK], instr_no);
 
 	if (cinfo->vrec < 0 && cinfo->def_vrec < 0) {
@@ -2040,8 +2175,10 @@
 	int i;
 	current_alloc_time = 0;
 	/* don't turn off voice 31 and 32.  they are used also for FM voices */
-	for (i = 0; i < awe_max_voices; i++)
+	for (i = 0; i < awe_max_voices; i++) {
 		awe_terminate(i);
+		awe_voice_init(i, TRUE);
+	}
 	for (i = 0; i < AWE_MAX_CHANNELS; i++)
 		awe_channel_init(i, TRUE);
 	for (i = 0; i < 16; i++) {
@@ -2136,15 +2273,19 @@
 				break;
 
 			case _GUS_VOICEOFF:
-			awe_terminate(i);
+				awe_terminate(i);
+				awe_fx_init(voices[i].ch);
+				awe_voice_init(i, TRUE);
 				break;
 
 			case _GUS_VOICEFADE:
 				awe_note_off(i);
+				awe_fx_init(voices[i].ch);
+				awe_voice_init(i, FALSE);
 				break;
-	
+
 			case _GUS_VOICEFREQ:
-			awe_calc_pitch_from_freq(i, plong);
+				awe_calc_pitch_from_freq(i, plong);
 				break;
 			}
 		}
@@ -2154,26 +2295,6 @@
 #endif
 
 
-/* converter function table for realtime paramter change */
-
-static fx_affect_func fx_realtime[] = {
-	/* env1: delay, attack, hold, decay, release, sustain, pitch, cutoff*/
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	/* env2: delay, attack, hold, decay, release, sustain */
-	NULL, NULL, NULL, NULL, NULL, NULL,
-	/* lfo1: delay, freq, volume, pitch, cutoff */
-	NULL, awe_fx_tremfrq, awe_fx_tremfrq, awe_fx_fmmod, awe_fx_fmmod,
-	/* lfo2: delay, freq, pitch */
-	NULL, awe_fx_fm2frq2, awe_fx_fm2frq2,
-	/* global: initpitch, chorus, reverb, cutoff, filterQ */
-	awe_set_voice_pitch, NULL, NULL, awe_set_volume, NULL,
-	/* sample: start, loopstart, loopend */
-	NULL, NULL, NULL, NULL, NULL, NULL,
-	/* global: attenuation */
-	awe_set_volume,
-};
-
-
 /* AWE32 specific controls */
 static void
 awe_hw_awe_control(int dev, int cmd, unsigned char *event)
@@ -2224,27 +2345,27 @@
 
 	case _AWE_SEND_EFFECT:
 		fx = &cinfo->fx;
-		i = 0; /* set */
+		i = FX_FLAG_SET;
 		if (p1 >= 0x100) {
 			int layer = (p1 >> 8);
 			if (layer >= 0 && layer < MAX_LAYERS)
 				fx = &cinfo->fx_layer[layer];
 			p1 &= 0xff;
 		}
-		if (p1 & 0x40) i = 2; /* clear */
-		if (p1 & 0x80) i = 1; /* add */
+		if (p1 & 0x40) i = FX_FLAG_OFF;
+		if (p1 & 0x80) i = FX_FLAG_ADD;
 		p1 &= 0x3f;
 		if (p1 < AWE_FX_END) {
-			DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, cinfo->fx.val[p1]));
-			if (i == 0)
+			DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, p2));
+			if (i == FX_FLAG_SET)
 				FX_SET(fx, p1, p2);
-			else if (i == 1)
+			else if (i == FX_FLAG_ADD)
 				FX_ADD(fx, p1, p2);
 			else
 				FX_UNSET(fx, p1);
-			if (i != 2 && fx_realtime[p1]) {
+			if (i != FX_FLAG_OFF && parm_defs[p1].realtime) {
 				DEBUG(0,printk("AWE32: fx_realtime (%d)\n", voice));
-				awe_voice_change(voice, fx_realtime[p1]);
+				awe_voice_change(voice, parm_defs[p1].realtime);
 			}
 		}
 		break;
@@ -2258,7 +2379,7 @@
 		break;
 
 	case _AWE_TERMINATE_CHANNEL:
-		awe_voice_change(voice, (fx_affect_func)awe_terminate);
+		awe_voice_change(voice, awe_terminate_and_init);
 		break;
 
 	case _AWE_RELEASE_ALL:
@@ -2276,7 +2397,7 @@
 			init_atten = misc_modes[AWE_MD_ZERO_ATTEN] + (short)p1;
 		if (init_atten < 0) init_atten = 0;
 		for (i = 0; i < awe_max_voices; i++)
-			awe_set_voice_vol(i, FALSE);
+			awe_set_voice_vol(i, TRUE);
 		break;
 
 	case _AWE_CHN_PRESSURE:
@@ -2360,7 +2481,14 @@
 	switch (ctrl_num) {
 	case CTL_BANK_SELECT: /* MIDI control #0 */
 		DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
+		if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
+		    !misc_modes[AWE_MD_TOGGLE_DRUM_BANK])
+			break;
 		cinfo->bank = value;
+		if (cinfo->bank == AWE_DRUM_BANK)
+			DRUM_CHANNEL_ON(cinfo->channel);
+		else
+			DRUM_CHANNEL_OFF(cinfo->channel);
 		awe_set_instr(dev, voice, cinfo->instr);
 		break;
 
@@ -3117,7 +3245,6 @@
 
 	/* initialize FM */
 	awe_init_fm();
-	/*awe_tweak();*/
 
 	return 0;
 }
@@ -3561,8 +3688,11 @@
 		}
 	}
 	/* clear voice */
-	if (best >= 0)
-		awe_terminate(best);
+	if (best >= 0) {
+		if (voices[best].state != AWE_ST_OFF)
+			awe_terminate(best);
+		awe_voice_init(best, TRUE);
+	}
 
 	return best;
 }
@@ -3647,6 +3777,7 @@
 awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
 {
 	playing_mode = AWE_PLAY_MULTI2;
+	awe_info.nr_voices = AWE_MAX_CHANNELS;
 	return awe_clear_voice();
 }
 
@@ -3719,7 +3850,7 @@
 			if (level >= 128) level = 127;
 			init_atten = vol_table[level];
 			for (i = 0; i < awe_max_voices; i++)
-				awe_set_voice_vol(i, FALSE);
+				awe_set_voice_vol(i, TRUE);
 			break;
 		}
 	}
@@ -4010,7 +4141,10 @@
 
 	/* change maximum channels to 30 */
 	awe_max_voices = AWE_NORMAL_VOICES;
-	awe_info.nr_voices = awe_max_voices;
+	if (playing_mode == AWE_PLAY_DIRECT)
+		awe_info.nr_voices = awe_max_voices;
+	else
+		awe_info.nr_voices = AWE_MAX_CHANNELS;
 	voice_alloc->max_voice = awe_max_voices;
 }
 
@@ -4426,3 +4560,18 @@
 
 
 #endif /* CONFIG_AWE32_SYNTH */
+
+#ifdef MODULE
+int init_module(void)
+{
+	attach_awe();
+	SOUND_LOCK;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unload_awe();
+	SOUND_LOCK_END;
+}
+#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov