Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * sound/awe_wave.c | |
3 | * | |
4 | * The low level driver for the AWE32/SB32/AWE64 wave table synth. | |
5 | * version 0.4.4; Jan. 4, 2000 | |
6 | * | |
7 | * Copyright (C) 1996-2000 Takashi Iwai | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | */ | |
23 | ||
24 | /* | |
25 | * Changelog: | |
26 | * Aug 18, 2003, Adam Belay <ambx1@neo.rr.com> | |
27 | * - detection code rewrite | |
28 | */ | |
29 | ||
30 | #include <linux/awe_voice.h> | |
31 | #include <linux/config.h> | |
32 | #include <linux/init.h> | |
33 | #include <linux/module.h> | |
34 | #include <linux/string.h> | |
35 | #include <linux/pnp.h> | |
36 | ||
37 | #include "sound_config.h" | |
38 | ||
39 | #include "awe_wave.h" | |
40 | #include "awe_hw.h" | |
41 | ||
42 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
43 | #include "tuning.h" | |
44 | #include <linux/ultrasound.h> | |
45 | #endif | |
46 | ||
47 | /* | |
48 | * debug message | |
49 | */ | |
50 | ||
51 | #ifdef AWE_DEBUG_ON | |
52 | #define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }} | |
53 | #define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }} | |
54 | #define FATALERR(XXX) XXX | |
55 | #else | |
56 | #define DEBUG(LVL,XXX) /**/ | |
57 | #define ERRMSG(XXX) XXX | |
58 | #define FATALERR(XXX) XXX | |
59 | #endif | |
60 | ||
61 | /* | |
62 | * bank and voice record | |
63 | */ | |
64 | ||
65 | typedef struct _sf_list sf_list; | |
66 | typedef struct _awe_voice_list awe_voice_list; | |
67 | typedef struct _awe_sample_list awe_sample_list; | |
68 | ||
69 | /* soundfont record */ | |
70 | struct _sf_list { | |
71 | unsigned short sf_id; /* id number */ | |
72 | unsigned short type; /* lock & shared flags */ | |
73 | int num_info; /* current info table index */ | |
74 | int num_sample; /* current sample table index */ | |
75 | int mem_ptr; /* current word byte pointer */ | |
76 | awe_voice_list *infos, *last_infos; /* instruments */ | |
77 | awe_sample_list *samples, *last_samples; /* samples */ | |
78 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
79 | sf_list *shared; /* shared list */ | |
80 | unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */ | |
81 | #endif | |
82 | sf_list *next, *prev; | |
83 | }; | |
84 | ||
85 | /* instrument list */ | |
86 | struct _awe_voice_list { | |
87 | awe_voice_info v; /* instrument information */ | |
88 | sf_list *holder; /* parent sf_list of this record */ | |
89 | unsigned char bank, instr; /* preset number information */ | |
90 | char type, disabled; /* type=normal/mapped, disabled=boolean */ | |
91 | awe_voice_list *next; /* linked list with same sf_id */ | |
92 | awe_voice_list *next_instr; /* instrument list */ | |
93 | awe_voice_list *next_bank; /* hash table list */ | |
94 | }; | |
95 | ||
96 | /* voice list type */ | |
97 | #define V_ST_NORMAL 0 | |
98 | #define V_ST_MAPPED 1 | |
99 | ||
100 | /* sample list */ | |
101 | struct _awe_sample_list { | |
102 | awe_sample_info v; /* sample information */ | |
103 | sf_list *holder; /* parent sf_list of this record */ | |
104 | awe_sample_list *next; /* linked list with same sf_id */ | |
105 | }; | |
106 | ||
107 | /* sample and information table */ | |
108 | static int current_sf_id; /* current number of fonts */ | |
109 | static int locked_sf_id; /* locked position */ | |
110 | static sf_list *sfhead, *sftail; /* linked-lists */ | |
111 | ||
112 | #define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0) | |
113 | #define awe_free_info() (sftail ? sftail->num_info : 0) | |
114 | #define awe_free_sample() (sftail ? sftail->num_sample : 0) | |
115 | ||
116 | #define AWE_MAX_PRESETS 256 | |
117 | #define AWE_DEFAULT_PRESET 0 | |
118 | #define AWE_DEFAULT_BANK 0 | |
119 | #define AWE_DEFAULT_DRUM 0 | |
120 | #define AWE_DRUM_BANK 128 | |
121 | ||
122 | #define MAX_LAYERS AWE_MAX_VOICES | |
123 | ||
124 | /* preset table index */ | |
125 | static awe_voice_list *preset_table[AWE_MAX_PRESETS]; | |
126 | ||
127 | /* | |
128 | * voice table | |
129 | */ | |
130 | ||
131 | /* effects table */ | |
132 | typedef struct FX_Rec { /* channel effects */ | |
133 | unsigned char flags[AWE_FX_END]; | |
134 | short val[AWE_FX_END]; | |
135 | } FX_Rec; | |
136 | ||
137 | ||
138 | /* channel parameters */ | |
139 | typedef struct _awe_chan_info { | |
140 | int channel; /* channel number */ | |
141 | int bank; /* current tone bank */ | |
142 | int instr; /* current program */ | |
143 | int bender; /* midi pitchbend (-8192 - 8192) */ | |
144 | int bender_range; /* midi bender range (x100) */ | |
145 | int panning; /* panning (0-127) */ | |
146 | int main_vol; /* channel volume (0-127) */ | |
147 | int expression_vol; /* midi expression (0-127) */ | |
148 | int chan_press; /* channel pressure */ | |
149 | int sustained; /* sustain status in MIDI */ | |
150 | FX_Rec fx; /* effects */ | |
151 | FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */ | |
152 | } awe_chan_info; | |
153 | ||
154 | /* voice parameters */ | |
155 | typedef struct _voice_info { | |
156 | int state; | |
157 | #define AWE_ST_OFF (1<<0) /* no sound */ | |
158 | #define AWE_ST_ON (1<<1) /* playing */ | |
159 | #define AWE_ST_STANDBY (1<<2) /* stand by for playing */ | |
160 | #define AWE_ST_SUSTAINED (1<<3) /* sustained */ | |
161 | #define AWE_ST_MARK (1<<4) /* marked for allocation */ | |
162 | #define AWE_ST_DRAM (1<<5) /* DRAM read/write */ | |
163 | #define AWE_ST_FM (1<<6) /* reserved for FM */ | |
164 | #define AWE_ST_RELEASED (1<<7) /* released */ | |
165 | ||
166 | int ch; /* midi channel */ | |
167 | int key; /* internal key for search */ | |
168 | int layer; /* layer number (for channel mode only) */ | |
169 | int time; /* allocated time */ | |
170 | awe_chan_info *cinfo; /* channel info */ | |
171 | ||
172 | int note; /* midi key (0-127) */ | |
173 | int velocity; /* midi velocity (0-127) */ | |
174 | int sostenuto; /* sostenuto on/off */ | |
175 | awe_voice_info *sample; /* assigned voice */ | |
176 | ||
177 | /* EMU8000 parameters */ | |
178 | int apitch; /* pitch parameter */ | |
179 | int avol; /* volume parameter */ | |
180 | int apan; /* panning parameter */ | |
181 | int acutoff; /* cutoff parameter */ | |
182 | short aaux; /* aux word */ | |
183 | } voice_info; | |
184 | ||
185 | /* voice information */ | |
186 | static voice_info voices[AWE_MAX_VOICES]; | |
187 | ||
188 | #define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED)) | |
189 | #define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON) | |
190 | #define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED)) | |
191 | #define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM)) | |
192 | ||
193 | ||
194 | /* MIDI channel effects information (for hw control) */ | |
195 | static awe_chan_info channels[AWE_MAX_CHANNELS]; | |
196 | ||
197 | ||
198 | /* | |
199 | * global variables | |
200 | */ | |
201 | ||
202 | #ifndef AWE_DEFAULT_BASE_ADDR | |
203 | #define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */ | |
204 | #endif | |
205 | ||
206 | #ifndef AWE_DEFAULT_MEM_SIZE | |
207 | #define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */ | |
208 | #endif | |
209 | ||
210 | static int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */ | |
211 | static int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */ | |
212 | #ifdef CONFIG_PNP | |
213 | static int isapnp = -1; | |
214 | #else | |
215 | static int isapnp; | |
216 | #endif | |
217 | ||
218 | MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>"); | |
219 | MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver"); | |
220 | MODULE_LICENSE("GPL"); | |
221 | ||
222 | module_param(io, int, 0); | |
223 | MODULE_PARM_DESC(io, "base i/o port of Emu8000"); | |
224 | module_param(memsize, int, 0); | |
225 | MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes"); | |
226 | module_param(isapnp, bool, 0); | |
227 | MODULE_PARM_DESC(isapnp, "use ISAPnP detection"); | |
228 | ||
229 | /* DRAM start offset */ | |
230 | static int awe_mem_start = AWE_DRAM_OFFSET; | |
231 | ||
232 | /* maximum channels for playing */ | |
233 | static int awe_max_voices = AWE_MAX_VOICES; | |
234 | ||
235 | static int patch_opened; /* sample already loaded? */ | |
236 | ||
237 | static char atten_relative = FALSE; | |
238 | static short atten_offset; | |
239 | ||
240 | static int awe_present = FALSE; /* awe device present? */ | |
241 | static int awe_busy = FALSE; /* awe device opened? */ | |
242 | ||
243 | static int my_dev = -1; | |
244 | ||
245 | #define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25)) | |
246 | #define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c))) | |
247 | #define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c))) | |
248 | #define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c))) | |
249 | static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */ | |
250 | ||
251 | static int playing_mode = AWE_PLAY_INDIRECT; | |
252 | #define SINGLE_LAYER_MODE() (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT) | |
253 | #define MULTI_LAYER_MODE() (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2) | |
254 | ||
255 | static int current_alloc_time; /* voice allocation index for channel mode */ | |
256 | ||
257 | static struct synth_info awe_info = { | |
258 | "AWE32 Synth", /* name */ | |
259 | 0, /* device */ | |
260 | SYNTH_TYPE_SAMPLE, /* synth_type */ | |
261 | SAMPLE_TYPE_AWE32, /* synth_subtype */ | |
262 | 0, /* perc_mode (obsolete) */ | |
263 | AWE_MAX_VOICES, /* nr_voices */ | |
264 | 0, /* nr_drums (obsolete) */ | |
265 | 400 /* instr_bank_size */ | |
266 | }; | |
267 | ||
268 | ||
269 | static struct voice_alloc_info *voice_alloc; /* set at initialization */ | |
270 | ||
271 | ||
272 | /* | |
273 | * function prototypes | |
274 | */ | |
275 | ||
276 | static int awe_request_region(void); | |
277 | static void awe_release_region(void); | |
278 | ||
279 | static void awe_reset_samples(void); | |
280 | /* emu8000 chip i/o access */ | |
281 | static void setup_ports(int p1, int p2, int p3); | |
282 | static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data); | |
283 | static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data); | |
284 | static unsigned short awe_peek(unsigned short cmd, unsigned short port); | |
285 | static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port); | |
286 | static void awe_wait(unsigned short delay); | |
287 | ||
288 | /* initialize emu8000 chip */ | |
289 | static void awe_initialize(void); | |
290 | ||
291 | /* set voice parameters */ | |
292 | static void awe_init_ctrl_parms(int init_all); | |
293 | static void awe_init_voice_info(awe_voice_info *vp); | |
294 | static void awe_init_voice_parm(awe_voice_parm *pp); | |
295 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
296 | static int freq_to_note(int freq); | |
297 | static int calc_rate_offset(int Hz); | |
298 | /*static int calc_parm_delay(int msec);*/ | |
299 | static int calc_parm_hold(int msec); | |
300 | static int calc_parm_attack(int msec); | |
301 | static int calc_parm_decay(int msec); | |
302 | static int calc_parm_search(int msec, short *table); | |
303 | #endif /* gus compat */ | |
304 | ||
305 | /* turn on/off note */ | |
306 | static void awe_note_on(int voice); | |
307 | static void awe_note_off(int voice); | |
308 | static void awe_terminate(int voice); | |
309 | static void awe_exclusive_off(int voice); | |
310 | static void awe_note_off_all(int do_sustain); | |
311 | ||
312 | /* calculate voice parameters */ | |
313 | typedef void (*fx_affect_func)(int voice, int forced); | |
314 | static void awe_set_pitch(int voice, int forced); | |
315 | static void awe_set_voice_pitch(int voice, int forced); | |
316 | static void awe_set_volume(int voice, int forced); | |
317 | static void awe_set_voice_vol(int voice, int forced); | |
318 | static void awe_set_pan(int voice, int forced); | |
319 | static void awe_fx_fmmod(int voice, int forced); | |
320 | static void awe_fx_tremfrq(int voice, int forced); | |
321 | static void awe_fx_fm2frq2(int voice, int forced); | |
322 | static void awe_fx_filterQ(int voice, int forced); | |
323 | static void awe_calc_pitch(int voice); | |
324 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
325 | static void awe_calc_pitch_from_freq(int voice, int freq); | |
326 | #endif | |
327 | static void awe_calc_volume(int voice); | |
328 | static void awe_update_volume(void); | |
329 | static void awe_change_master_volume(short val); | |
330 | static void awe_voice_init(int voice, int init_all); | |
331 | static void awe_channel_init(int ch, int init_all); | |
332 | static void awe_fx_init(int ch); | |
333 | static void awe_send_effect(int voice, int layer, int type, int val); | |
334 | static void awe_modwheel_change(int voice, int value); | |
335 | ||
336 | /* sequencer interface */ | |
337 | static int awe_open(int dev, int mode); | |
338 | static void awe_close(int dev); | |
339 | static int awe_ioctl(int dev, unsigned int cmd, void __user * arg); | |
340 | static int awe_kill_note(int dev, int voice, int note, int velocity); | |
341 | static int awe_start_note(int dev, int v, int note_num, int volume); | |
342 | static int awe_set_instr(int dev, int voice, int instr_no); | |
343 | static int awe_set_instr_2(int dev, int voice, int instr_no); | |
344 | static void awe_reset(int dev); | |
345 | static void awe_hw_control(int dev, unsigned char *event); | |
346 | static int awe_load_patch(int dev, int format, const char __user *addr, | |
347 | int offs, int count, int pmgr_flag); | |
348 | static void awe_aftertouch(int dev, int voice, int pressure); | |
349 | static void awe_controller(int dev, int voice, int ctrl_num, int value); | |
350 | static void awe_panning(int dev, int voice, int value); | |
351 | static void awe_volume_method(int dev, int mode); | |
352 | static void awe_bender(int dev, int voice, int value); | |
353 | static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc); | |
354 | static void awe_setup_voice(int dev, int voice, int chn); | |
355 | ||
356 | #define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press) | |
357 | ||
358 | /* hardware controls */ | |
359 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
360 | static void awe_hw_gus_control(int dev, int cmd, unsigned char *event); | |
361 | #endif | |
362 | static void awe_hw_awe_control(int dev, int cmd, unsigned char *event); | |
363 | static void awe_voice_change(int voice, fx_affect_func func); | |
364 | static void awe_sostenuto_on(int voice, int forced); | |
365 | static void awe_sustain_off(int voice, int forced); | |
366 | static void awe_terminate_and_init(int voice, int forced); | |
367 | ||
368 | /* voice search */ | |
369 | static int awe_search_key(int bank, int preset, int note); | |
370 | static awe_voice_list *awe_search_instr(int bank, int preset, int note); | |
371 | static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist); | |
372 | static void awe_alloc_multi_voices(int ch, int note, int velocity, int key); | |
373 | static void awe_alloc_one_voice(int voice, int note, int velocity); | |
374 | static int awe_clear_voice(void); | |
375 | ||
376 | /* load / remove patches */ | |
377 | static int awe_open_patch(awe_patch_info *patch, const char __user *addr, int count); | |
378 | static int awe_close_patch(awe_patch_info *patch, const char __user *addr, int count); | |
379 | static int awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count); | |
380 | static int awe_load_info(awe_patch_info *patch, const char __user *addr, int count); | |
381 | static int awe_remove_info(awe_patch_info *patch, const char __user *addr, int count); | |
382 | static int awe_load_data(awe_patch_info *patch, const char __user *addr, int count); | |
383 | static int awe_replace_data(awe_patch_info *patch, const char __user *addr, int count); | |
384 | static int awe_load_map(awe_patch_info *patch, const char __user *addr, int count); | |
385 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
386 | static int awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag); | |
387 | #endif | |
388 | /*static int awe_probe_info(awe_patch_info *patch, const char __user *addr, int count);*/ | |
389 | static int awe_probe_data(awe_patch_info *patch, const char __user *addr, int count); | |
390 | static sf_list *check_patch_opened(int type, char *name); | |
391 | static int awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *sp, int channels); | |
392 | static int awe_create_sf(int type, char *name); | |
393 | static void awe_free_sf(sf_list *sf); | |
394 | static void add_sf_info(sf_list *sf, awe_voice_list *rec); | |
395 | static void add_sf_sample(sf_list *sf, awe_sample_list *smp); | |
396 | static void purge_old_list(awe_voice_list *rec, awe_voice_list *next); | |
397 | static void add_info_list(awe_voice_list *rec); | |
398 | static void awe_remove_samples(int sf_id); | |
399 | static void rebuild_preset_list(void); | |
400 | static short awe_set_sample(awe_voice_list *rec); | |
401 | static awe_sample_list *search_sample_index(sf_list *sf, int sample); | |
402 | ||
403 | static int is_identical_holder(sf_list *sf1, sf_list *sf2); | |
404 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
405 | static int is_identical_name(unsigned char *name, sf_list *p); | |
406 | static int is_shared_sf(unsigned char *name); | |
407 | static int info_duplicated(sf_list *sf, awe_voice_list *rec); | |
408 | #endif /* allow sharing */ | |
409 | ||
410 | /* lowlevel functions */ | |
411 | static void awe_init_audio(void); | |
412 | static void awe_init_dma(void); | |
413 | static void awe_init_array(void); | |
414 | static void awe_send_array(unsigned short *data); | |
415 | static void awe_tweak_voice(int voice); | |
416 | static void awe_tweak(void); | |
417 | static void awe_init_fm(void); | |
418 | static int awe_open_dram_for_write(int offset, int channels); | |
419 | static void awe_open_dram_for_check(void); | |
420 | static void awe_close_dram(void); | |
421 | /*static void awe_write_dram(unsigned short c);*/ | |
422 | static int awe_detect_base(int addr); | |
423 | static int awe_detect(void); | |
424 | static void awe_check_dram(void); | |
425 | static int awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count); | |
426 | static void awe_set_chorus_mode(int mode); | |
427 | static void awe_update_chorus_mode(void); | |
428 | static int awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count); | |
429 | static void awe_set_reverb_mode(int mode); | |
430 | static void awe_update_reverb_mode(void); | |
431 | static void awe_equalizer(int bass, int treble); | |
432 | static void awe_update_equalizer(void); | |
433 | ||
434 | #ifdef CONFIG_AWE32_MIXER | |
435 | static void attach_mixer(void); | |
436 | static void unload_mixer(void); | |
437 | #endif | |
438 | ||
439 | #ifdef CONFIG_AWE32_MIDIEMU | |
440 | static void attach_midiemu(void); | |
441 | static void unload_midiemu(void); | |
442 | #endif | |
443 | ||
444 | #define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b) | |
445 | ||
446 | /* | |
447 | * control parameters | |
448 | */ | |
449 | ||
450 | ||
451 | #ifdef AWE_USE_NEW_VOLUME_CALC | |
452 | #define DEF_VOLUME_CALC TRUE | |
453 | #else | |
454 | #define DEF_VOLUME_CALC FALSE | |
455 | #endif /* new volume */ | |
456 | ||
457 | #define DEF_ZERO_ATTEN 32 /* 12dB below */ | |
458 | #define DEF_MOD_SENSE 18 | |
459 | #define DEF_CHORUS_MODE 2 | |
460 | #define DEF_REVERB_MODE 4 | |
461 | #define DEF_BASS_LEVEL 5 | |
462 | #define DEF_TREBLE_LEVEL 9 | |
463 | ||
464 | static struct CtrlParmsDef { | |
465 | int value; | |
466 | int init_each_time; | |
467 | void (*update)(void); | |
468 | } ctrl_parms[AWE_MD_END] = { | |
469 | {0,0, NULL}, {0,0, NULL}, /* <-- not used */ | |
470 | {AWE_VERSION_NUMBER, FALSE, NULL}, | |
471 | {TRUE, FALSE, NULL}, /* exclusive */ | |
472 | {TRUE, FALSE, NULL}, /* realpan */ | |
473 | {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */ | |
474 | {FALSE, TRUE, NULL}, /* keep effect */ | |
475 | {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */ | |
476 | {FALSE, FALSE, NULL}, /* chn_prior */ | |
477 | {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */ | |
478 | {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */ | |
479 | {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */ | |
480 | {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */ | |
481 | {FALSE, FALSE, NULL}, /* toggle_drum_bank */ | |
482 | {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */ | |
483 | {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */ | |
484 | {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */ | |
485 | {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */ | |
486 | {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */ | |
487 | {0, FALSE, NULL}, /* debug mode */ | |
488 | {FALSE, FALSE, NULL}, /* pan exchange */ | |
489 | }; | |
490 | ||
491 | static int ctrls[AWE_MD_END]; | |
492 | ||
493 | ||
494 | /* | |
495 | * synth operation table | |
496 | */ | |
497 | ||
498 | static struct synth_operations awe_operations = | |
499 | { | |
500 | .owner = THIS_MODULE, | |
501 | .id = "EMU8K", | |
502 | .info = &awe_info, | |
503 | .midi_dev = 0, | |
504 | .synth_type = SYNTH_TYPE_SAMPLE, | |
505 | .synth_subtype = SAMPLE_TYPE_AWE32, | |
506 | .open = awe_open, | |
507 | .close = awe_close, | |
508 | .ioctl = awe_ioctl, | |
509 | .kill_note = awe_kill_note, | |
510 | .start_note = awe_start_note, | |
511 | .set_instr = awe_set_instr_2, | |
512 | .reset = awe_reset, | |
513 | .hw_control = awe_hw_control, | |
514 | .load_patch = awe_load_patch, | |
515 | .aftertouch = awe_aftertouch, | |
516 | .controller = awe_controller, | |
517 | .panning = awe_panning, | |
518 | .volume_method = awe_volume_method, | |
519 | .bender = awe_bender, | |
520 | .alloc_voice = awe_alloc, | |
521 | .setup_voice = awe_setup_voice | |
522 | }; | |
523 | ||
524 | static void free_tables(void) | |
525 | { | |
526 | if (sftail) { | |
527 | sf_list *p, *prev; | |
528 | for (p = sftail; p; p = prev) { | |
529 | prev = p->prev; | |
530 | awe_free_sf(p); | |
531 | } | |
532 | } | |
533 | sfhead = sftail = NULL; | |
534 | } | |
535 | ||
536 | /* | |
537 | * clear sample tables | |
538 | */ | |
539 | ||
540 | static void | |
541 | awe_reset_samples(void) | |
542 | { | |
543 | /* free all bank tables */ | |
544 | memset(preset_table, 0, sizeof(preset_table)); | |
545 | free_tables(); | |
546 | ||
547 | current_sf_id = 0; | |
548 | locked_sf_id = 0; | |
549 | patch_opened = 0; | |
550 | } | |
551 | ||
552 | ||
553 | /* | |
554 | * EMU register access | |
555 | */ | |
556 | ||
557 | /* select a given AWE32 pointer */ | |
558 | static int awe_ports[5]; | |
559 | static int port_setuped = FALSE; | |
560 | static int awe_cur_cmd = -1; | |
561 | #define awe_set_cmd(cmd) \ | |
562 | if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; } | |
563 | ||
564 | /* write 16bit data */ | |
565 | static void | |
566 | awe_poke(unsigned short cmd, unsigned short port, unsigned short data) | |
567 | { | |
568 | awe_set_cmd(cmd); | |
569 | outw(data, awe_ports[port]); | |
570 | } | |
571 | ||
572 | /* write 32bit data */ | |
573 | static void | |
574 | awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data) | |
575 | { | |
576 | unsigned short addr = awe_ports[port]; | |
577 | awe_set_cmd(cmd); | |
578 | outw(data, addr); /* write lower 16 bits */ | |
579 | outw(data >> 16, addr + 2); /* write higher 16 bits */ | |
580 | } | |
581 | ||
582 | /* read 16bit data */ | |
583 | static unsigned short | |
584 | awe_peek(unsigned short cmd, unsigned short port) | |
585 | { | |
586 | unsigned short k; | |
587 | awe_set_cmd(cmd); | |
588 | k = inw(awe_ports[port]); | |
589 | return k; | |
590 | } | |
591 | ||
592 | /* read 32bit data */ | |
593 | static unsigned int | |
594 | awe_peek_dw(unsigned short cmd, unsigned short port) | |
595 | { | |
596 | unsigned int k1, k2; | |
597 | unsigned short addr = awe_ports[port]; | |
598 | awe_set_cmd(cmd); | |
599 | k1 = inw(addr); | |
600 | k2 = inw(addr + 2); | |
601 | k1 |= k2 << 16; | |
602 | return k1; | |
603 | } | |
604 | ||
605 | /* wait delay number of AWE32 44100Hz clocks */ | |
606 | #ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */ | |
607 | static void | |
608 | awe_wait(unsigned short delay) | |
609 | { | |
610 | unsigned short clock, target; | |
611 | unsigned short port = awe_ports[AWE_WC_Port]; | |
612 | int counter; | |
613 | ||
614 | /* sample counter */ | |
615 | awe_set_cmd(AWE_WC_Cmd); | |
616 | clock = (unsigned short)inw(port); | |
617 | target = clock + delay; | |
618 | counter = 0; | |
619 | if (target < clock) { | |
620 | for (; (unsigned short)inw(port) > target; counter++) | |
621 | if (counter > 65536) | |
622 | break; | |
623 | } | |
624 | for (; (unsigned short)inw(port) < target; counter++) | |
625 | if (counter > 65536) | |
626 | break; | |
627 | } | |
628 | #else | |
629 | ||
630 | static void awe_wait(unsigned short delay) | |
631 | { | |
632 | current->state = TASK_INTERRUPTIBLE; | |
633 | schedule_timeout((HZ*(unsigned long)delay + 44099)/44100); | |
634 | } | |
635 | /* | |
636 | static void awe_wait(unsigned short delay) | |
637 | { | |
638 | udelay(((unsigned long)delay * 1000000L + 44099) / 44100); | |
639 | } | |
640 | */ | |
641 | #endif /* wait by loop */ | |
642 | ||
643 | /* write a word data */ | |
644 | #define awe_write_dram(c) awe_poke(AWE_SMLD, c) | |
645 | ||
646 | /* | |
647 | * AWE32 voice parameters | |
648 | */ | |
649 | ||
650 | /* initialize voice_info record */ | |
651 | static void | |
652 | awe_init_voice_info(awe_voice_info *vp) | |
653 | { | |
654 | vp->sample = 0; | |
655 | vp->rate_offset = 0; | |
656 | ||
657 | vp->start = 0; | |
658 | vp->end = 0; | |
659 | vp->loopstart = 0; | |
660 | vp->loopend = 0; | |
661 | vp->mode = 0; | |
662 | vp->root = 60; | |
663 | vp->tune = 0; | |
664 | vp->low = 0; | |
665 | vp->high = 127; | |
666 | vp->vellow = 0; | |
667 | vp->velhigh = 127; | |
668 | ||
669 | vp->fixkey = -1; | |
670 | vp->fixvel = -1; | |
671 | vp->fixpan = -1; | |
672 | vp->pan = -1; | |
673 | ||
674 | vp->exclusiveClass = 0; | |
675 | vp->amplitude = 127; | |
676 | vp->attenuation = 0; | |
677 | vp->scaleTuning = 100; | |
678 | ||
679 | awe_init_voice_parm(&vp->parm); | |
680 | } | |
681 | ||
682 | /* initialize voice_parm record: | |
683 | * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0. | |
684 | * Vibrato and Tremolo effects are zero. | |
685 | * Cutoff is maximum. | |
686 | * Chorus and Reverb effects are zero. | |
687 | */ | |
688 | static void | |
689 | awe_init_voice_parm(awe_voice_parm *pp) | |
690 | { | |
691 | pp->moddelay = 0x8000; | |
692 | pp->modatkhld = 0x7f7f; | |
693 | pp->moddcysus = 0x7f7f; | |
694 | pp->modrelease = 0x807f; | |
695 | pp->modkeyhold = 0; | |
696 | pp->modkeydecay = 0; | |
697 | ||
698 | pp->voldelay = 0x8000; | |
699 | pp->volatkhld = 0x7f7f; | |
700 | pp->voldcysus = 0x7f7f; | |
701 | pp->volrelease = 0x807f; | |
702 | pp->volkeyhold = 0; | |
703 | pp->volkeydecay = 0; | |
704 | ||
705 | pp->lfo1delay = 0x8000; | |
706 | pp->lfo2delay = 0x8000; | |
707 | pp->pefe = 0; | |
708 | ||
709 | pp->fmmod = 0; | |
710 | pp->tremfrq = 0; | |
711 | pp->fm2frq2 = 0; | |
712 | ||
713 | pp->cutoff = 0xff; | |
714 | pp->filterQ = 0; | |
715 | ||
716 | pp->chorus = 0; | |
717 | pp->reverb = 0; | |
718 | } | |
719 | ||
720 | ||
721 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
722 | ||
723 | /* convert frequency mHz to abstract cents (= midi key * 100) */ | |
724 | static int | |
725 | freq_to_note(int mHz) | |
726 | { | |
727 | /* abscents = log(mHz/8176) / log(2) * 1200 */ | |
728 | unsigned int max_val = (unsigned int)0xffffffff / 10000; | |
729 | int i, times; | |
730 | unsigned int base; | |
731 | unsigned int freq; | |
732 | int note, tune; | |
733 | ||
734 | if (mHz == 0) | |
735 | return 0; | |
736 | if (mHz < 0) | |
737 | return 12799; /* maximum */ | |
738 | ||
739 | freq = mHz; | |
740 | note = 0; | |
741 | for (base = 8176 * 2; freq >= base; base *= 2) { | |
742 | note += 12; | |
743 | if (note >= 128) /* over maximum */ | |
744 | return 12799; | |
745 | } | |
746 | base /= 2; | |
747 | ||
748 | /* to avoid overflow... */ | |
749 | times = 10000; | |
750 | while (freq > max_val) { | |
751 | max_val *= 10; | |
752 | times /= 10; | |
753 | base /= 10; | |
754 | } | |
755 | ||
756 | freq = freq * times / base; | |
757 | for (i = 0; i < 12; i++) { | |
758 | if (freq < semitone_tuning[i+1]) | |
759 | break; | |
760 | note++; | |
761 | } | |
762 | ||
763 | tune = 0; | |
764 | freq = freq * 10000 / semitone_tuning[i]; | |
765 | for (i = 0; i < 100; i++) { | |
766 | if (freq < cent_tuning[i+1]) | |
767 | break; | |
768 | tune++; | |
769 | } | |
770 | ||
771 | return note * 100 + tune; | |
772 | } | |
773 | ||
774 | ||
775 | /* convert Hz to AWE32 rate offset: | |
776 | * sample pitch offset for the specified sample rate | |
777 | * rate=44100 is no offset, each 4096 is 1 octave (twice). | |
778 | * eg, when rate is 22050, this offset becomes -4096. | |
779 | */ | |
780 | static int | |
781 | calc_rate_offset(int Hz) | |
782 | { | |
783 | /* offset = log(Hz / 44100) / log(2) * 4096 */ | |
784 | int freq, base, i; | |
785 | ||
786 | /* maybe smaller than max (44100Hz) */ | |
787 | if (Hz <= 0 || Hz >= 44100) return 0; | |
788 | ||
789 | base = 0; | |
790 | for (freq = Hz * 2; freq < 44100; freq *= 2) | |
791 | base++; | |
792 | base *= 1200; | |
793 | ||
794 | freq = 44100 * 10000 / (freq/2); | |
795 | for (i = 0; i < 12; i++) { | |
796 | if (freq < semitone_tuning[i+1]) | |
797 | break; | |
798 | base += 100; | |
799 | } | |
800 | freq = freq * 10000 / semitone_tuning[i]; | |
801 | for (i = 0; i < 100; i++) { | |
802 | if (freq < cent_tuning[i+1]) | |
803 | break; | |
804 | base++; | |
805 | } | |
806 | return -base * 4096 / 1200; | |
807 | } | |
808 | ||
809 | ||
810 | /* | |
811 | * convert envelope time parameter to AWE32 raw parameter | |
812 | */ | |
813 | ||
814 | /* attack & decay/release time table (msec) */ | |
815 | static short attack_time_tbl[128] = { | |
816 | 32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816, | |
817 | 707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, | |
818 | 361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, | |
819 | 180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, | |
820 | 90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, | |
821 | 45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, | |
822 | 22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, | |
823 | 11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0, | |
824 | }; | |
825 | ||
826 | static short decay_time_tbl[128] = { | |
827 | 32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082, | |
828 | 2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507, | |
829 | 1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722, | |
830 | 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361, | |
831 | 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180, | |
832 | 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90, | |
833 | 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45, | |
834 | 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22, | |
835 | }; | |
836 | ||
837 | #define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725); | |
838 | ||
839 | /* delay time = 0x8000 - msec/92 */ | |
840 | static int | |
841 | calc_parm_hold(int msec) | |
842 | { | |
843 | int val = (0x7f * 92 - msec) / 92; | |
844 | if (val < 1) val = 1; | |
845 | if (val > 127) val = 127; | |
846 | return val; | |
847 | } | |
848 | ||
849 | /* attack time: search from time table */ | |
850 | static int | |
851 | calc_parm_attack(int msec) | |
852 | { | |
853 | return calc_parm_search(msec, attack_time_tbl); | |
854 | } | |
855 | ||
856 | /* decay/release time: search from time table */ | |
857 | static int | |
858 | calc_parm_decay(int msec) | |
859 | { | |
860 | return calc_parm_search(msec, decay_time_tbl); | |
861 | } | |
862 | ||
863 | /* search an index for specified time from given time table */ | |
864 | static int | |
865 | calc_parm_search(int msec, short *table) | |
866 | { | |
867 | int left = 1, right = 127, mid; | |
868 | while (left < right) { | |
869 | mid = (left + right) / 2; | |
870 | if (msec < (int)table[mid]) | |
871 | left = mid + 1; | |
872 | else | |
873 | right = mid; | |
874 | } | |
875 | return left; | |
876 | } | |
877 | #endif /* AWE_HAS_GUS_COMPATIBILITY */ | |
878 | ||
879 | ||
880 | /* | |
881 | * effects table | |
882 | */ | |
883 | ||
884 | /* set an effect value */ | |
885 | #define FX_FLAG_OFF 0 | |
886 | #define FX_FLAG_SET 1 | |
887 | #define FX_FLAG_ADD 2 | |
888 | ||
889 | #define FX_SET(rec,type,value) \ | |
890 | ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value)) | |
891 | #define FX_ADD(rec,type,value) \ | |
892 | ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value)) | |
893 | #define FX_UNSET(rec,type) \ | |
894 | ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0) | |
895 | ||
896 | /* check the effect value is set */ | |
897 | #define FX_ON(rec,type) ((rec)->flags[type]) | |
898 | ||
899 | #define PARM_BYTE 0 | |
900 | #define PARM_WORD 1 | |
901 | #define PARM_SIGN 2 | |
902 | ||
903 | static struct PARM_DEFS { | |
904 | int type; /* byte or word */ | |
905 | int low, high; /* value range */ | |
906 | fx_affect_func realtime; /* realtime paramater change */ | |
907 | } parm_defs[] = { | |
908 | {PARM_WORD, 0, 0x8000, NULL}, /* env1 delay */ | |
909 | {PARM_BYTE, 1, 0x7f, NULL}, /* env1 attack */ | |
910 | {PARM_BYTE, 0, 0x7e, NULL}, /* env1 hold */ | |
911 | {PARM_BYTE, 1, 0x7f, NULL}, /* env1 decay */ | |
912 | {PARM_BYTE, 1, 0x7f, NULL}, /* env1 release */ | |
913 | {PARM_BYTE, 0, 0x7f, NULL}, /* env1 sustain */ | |
914 | {PARM_BYTE, 0, 0xff, NULL}, /* env1 pitch */ | |
915 | {PARM_BYTE, 0, 0xff, NULL}, /* env1 cutoff */ | |
916 | ||
917 | {PARM_WORD, 0, 0x8000, NULL}, /* env2 delay */ | |
918 | {PARM_BYTE, 1, 0x7f, NULL}, /* env2 attack */ | |
919 | {PARM_BYTE, 0, 0x7e, NULL}, /* env2 hold */ | |
920 | {PARM_BYTE, 1, 0x7f, NULL}, /* env2 decay */ | |
921 | {PARM_BYTE, 1, 0x7f, NULL}, /* env2 release */ | |
922 | {PARM_BYTE, 0, 0x7f, NULL}, /* env2 sustain */ | |
923 | ||
924 | {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */ | |
925 | {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */ | |
926 | {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */ | |
927 | {PARM_SIGN, -128, 127, awe_fx_fmmod}, /* lfo1 pitch */ | |
928 | {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff */ | |
929 | ||
930 | {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */ | |
931 | {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */ | |
932 | {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */ | |
933 | ||
934 | {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */ | |
935 | {PARM_BYTE, 0, 0xff, NULL}, /* chorus */ | |
936 | {PARM_BYTE, 0, 0xff, NULL}, /* reverb */ | |
937 | {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial cutoff */ | |
938 | {PARM_BYTE, 0, 15, awe_fx_filterQ}, /* initial resonance */ | |
939 | ||
940 | {PARM_WORD, 0, 0xffff, NULL}, /* sample start */ | |
941 | {PARM_WORD, 0, 0xffff, NULL}, /* loop start */ | |
942 | {PARM_WORD, 0, 0xffff, NULL}, /* loop end */ | |
943 | {PARM_WORD, 0, 0xffff, NULL}, /* coarse sample start */ | |
944 | {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop start */ | |
945 | {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop end */ | |
946 | {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial attenuation */ | |
947 | }; | |
948 | ||
949 | ||
950 | static unsigned char | |
951 | FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value) | |
952 | { | |
953 | int effect = 0; | |
954 | int on = 0; | |
955 | if (lay && (on = FX_ON(lay, type)) != 0) | |
956 | effect = lay->val[type]; | |
957 | if (!on && (on = FX_ON(rec, type)) != 0) | |
958 | effect = rec->val[type]; | |
959 | if (on == FX_FLAG_ADD) { | |
960 | if (parm_defs[type].type == PARM_SIGN) { | |
961 | if (value > 0x7f) | |
962 | effect += (int)value - 0x100; | |
963 | else | |
964 | effect += (int)value; | |
965 | } else { | |
966 | effect += (int)value; | |
967 | } | |
968 | } | |
969 | if (on) { | |
970 | if (effect < parm_defs[type].low) | |
971 | effect = parm_defs[type].low; | |
972 | else if (effect > parm_defs[type].high) | |
973 | effect = parm_defs[type].high; | |
974 | return (unsigned char)effect; | |
975 | } | |
976 | return value; | |
977 | } | |
978 | ||
979 | /* get word effect value */ | |
980 | static unsigned short | |
981 | FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value) | |
982 | { | |
983 | int effect = 0; | |
984 | int on = 0; | |
985 | if (lay && (on = FX_ON(lay, type)) != 0) | |
986 | effect = lay->val[type]; | |
987 | if (!on && (on = FX_ON(rec, type)) != 0) | |
988 | effect = rec->val[type]; | |
989 | if (on == FX_FLAG_ADD) | |
990 | effect += (int)value; | |
991 | if (on) { | |
992 | if (effect < parm_defs[type].low) | |
993 | effect = parm_defs[type].low; | |
994 | else if (effect > parm_defs[type].high) | |
995 | effect = parm_defs[type].high; | |
996 | return (unsigned short)effect; | |
997 | } | |
998 | return value; | |
999 | } | |
1000 | ||
1001 | /* get word (upper=type1/lower=type2) effect value */ | |
1002 | static unsigned short | |
1003 | FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value) | |
1004 | { | |
1005 | unsigned short tmp; | |
1006 | tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8)); | |
1007 | tmp <<= 8; | |
1008 | tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff)); | |
1009 | return tmp; | |
1010 | } | |
1011 | ||
1012 | /* address offset */ | |
1013 | static int | |
1014 | FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode) | |
1015 | { | |
1016 | int addr = 0; | |
1017 | if (lay && FX_ON(lay, hi)) | |
1018 | addr = (short)lay->val[hi]; | |
1019 | else if (FX_ON(rec, hi)) | |
1020 | addr = (short)rec->val[hi]; | |
1021 | addr = addr << 15; | |
1022 | if (lay && FX_ON(lay, lo)) | |
1023 | addr += (short)lay->val[lo]; | |
1024 | else if (FX_ON(rec, lo)) | |
1025 | addr += (short)rec->val[lo]; | |
1026 | if (!(mode & AWE_SAMPLE_8BITS)) | |
1027 | addr /= 2; | |
1028 | return addr; | |
1029 | } | |
1030 | ||
1031 | ||
1032 | /* | |
1033 | * turn on/off sample | |
1034 | */ | |
1035 | ||
1036 | /* table for volume target calculation */ | |
1037 | static unsigned short voltarget[16] = { | |
1038 | 0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58, | |
1039 | 0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90 | |
1040 | }; | |
1041 | ||
1042 | static void | |
1043 | awe_note_on(int voice) | |
1044 | { | |
1045 | unsigned int temp; | |
1046 | int addr; | |
1047 | int vtarget, ftarget, ptarget, pitch; | |
1048 | awe_voice_info *vp; | |
1049 | awe_voice_parm_block *parm; | |
1050 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1051 | FX_Rec *fx_lay = NULL; | |
1052 | if (voices[voice].layer < MAX_LAYERS) | |
1053 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1054 | ||
1055 | /* A voice sample must assigned before calling */ | |
1056 | if ((vp = voices[voice].sample) == NULL || vp->index == 0) | |
1057 | return; | |
1058 | ||
1059 | parm = (awe_voice_parm_block*)&vp->parm; | |
1060 | ||
1061 | /* channel to be silent and idle */ | |
1062 | awe_poke(AWE_DCYSUSV(voice), 0x0080); | |
1063 | awe_poke(AWE_VTFT(voice), 0x0000FFFF); | |
1064 | awe_poke(AWE_CVCF(voice), 0x0000FFFF); | |
1065 | awe_poke(AWE_PTRX(voice), 0); | |
1066 | awe_poke(AWE_CPF(voice), 0); | |
1067 | ||
1068 | /* set pitch offset */ | |
1069 | awe_set_pitch(voice, TRUE); | |
1070 | ||
1071 | /* modulation & volume envelope */ | |
1072 | if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) { | |
1073 | awe_poke(AWE_ENVVAL(voice), 0xBFFF); | |
1074 | pitch = (parm->env1pit<<4) + voices[voice].apitch; | |
1075 | if (pitch > 0xffff) pitch = 0xffff; | |
1076 | /* calculate filter target */ | |
1077 | ftarget = parm->cutoff + parm->env1fc; | |
1078 | limitvalue(ftarget, 0, 255); | |
1079 | ftarget <<= 8; | |
1080 | } else { | |
1081 | awe_poke(AWE_ENVVAL(voice), | |
1082 | FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay)); | |
1083 | ftarget = parm->cutoff; | |
1084 | ftarget <<= 8; | |
1085 | pitch = voices[voice].apitch; | |
1086 | } | |
1087 | ||
1088 | /* calcualte pitch target */ | |
1089 | if (pitch != 0xffff) { | |
1090 | ptarget = 1 << (pitch >> 12); | |
1091 | if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710; | |
1092 | if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710; | |
1093 | if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710; | |
1094 | ptarget += (ptarget>>1); | |
1095 | if (ptarget > 0xffff) ptarget = 0xffff; | |
1096 | ||
1097 | } else ptarget = 0xffff; | |
1098 | if (parm->modatk >= 0x80) | |
1099 | awe_poke(AWE_ATKHLD(voice), | |
1100 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f); | |
1101 | else | |
1102 | awe_poke(AWE_ATKHLD(voice), | |
1103 | FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK, | |
1104 | vp->parm.modatkhld)); | |
1105 | awe_poke(AWE_DCYSUS(voice), | |
1106 | FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY, | |
1107 | vp->parm.moddcysus)); | |
1108 | ||
1109 | if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) { | |
1110 | awe_poke(AWE_ENVVOL(voice), 0xBFFF); | |
1111 | vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4); | |
1112 | } else { | |
1113 | awe_poke(AWE_ENVVOL(voice), | |
1114 | FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay)); | |
1115 | vtarget = 0; | |
1116 | } | |
1117 | if (parm->volatk >= 0x80) | |
1118 | awe_poke(AWE_ATKHLDV(voice), | |
1119 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f); | |
1120 | else | |
1121 | awe_poke(AWE_ATKHLDV(voice), | |
1122 | FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK, | |
1123 | vp->parm.volatkhld)); | |
1124 | /* decay/sustain parameter for volume envelope must be set at last */ | |
1125 | ||
1126 | /* cutoff and volume */ | |
1127 | awe_set_volume(voice, TRUE); | |
1128 | ||
1129 | /* modulation envelope heights */ | |
1130 | awe_poke(AWE_PEFE(voice), | |
1131 | FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF, | |
1132 | vp->parm.pefe)); | |
1133 | ||
1134 | /* lfo1/2 delay */ | |
1135 | awe_poke(AWE_LFO1VAL(voice), | |
1136 | FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay)); | |
1137 | awe_poke(AWE_LFO2VAL(voice), | |
1138 | FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay)); | |
1139 | ||
1140 | /* lfo1 pitch & cutoff shift */ | |
1141 | awe_fx_fmmod(voice, TRUE); | |
1142 | /* lfo1 volume & freq */ | |
1143 | awe_fx_tremfrq(voice, TRUE); | |
1144 | /* lfo2 pitch & freq */ | |
1145 | awe_fx_fm2frq2(voice, TRUE); | |
1146 | /* pan & loop start */ | |
1147 | awe_set_pan(voice, TRUE); | |
1148 | ||
1149 | /* chorus & loop end (chorus 8bit, MSB) */ | |
1150 | addr = vp->loopend - 1; | |
1151 | addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END, | |
1152 | AWE_FX_COARSE_LOOP_END, vp->mode); | |
1153 | temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus); | |
1154 | temp = (temp <<24) | (unsigned int)addr; | |
1155 | awe_poke_dw(AWE_CSL(voice), temp); | |
1156 | DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr)); | |
1157 | ||
1158 | /* Q & current address (Q 4bit value, MSB) */ | |
1159 | addr = vp->start - 1; | |
1160 | addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START, | |
1161 | AWE_FX_COARSE_SAMPLE_START, vp->mode); | |
1162 | temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ); | |
1163 | temp = (temp<<28) | (unsigned int)addr; | |
1164 | awe_poke_dw(AWE_CCCA(voice), temp); | |
1165 | DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr)); | |
1166 | ||
1167 | /* clear unknown registers */ | |
1168 | awe_poke_dw(AWE_00A0(voice), 0); | |
1169 | awe_poke_dw(AWE_0080(voice), 0); | |
1170 | ||
1171 | /* reset volume */ | |
1172 | awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget); | |
1173 | awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget); | |
1174 | ||
1175 | /* set reverb */ | |
1176 | temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb); | |
1177 | temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux; | |
1178 | awe_poke_dw(AWE_PTRX(voice), temp); | |
1179 | awe_poke_dw(AWE_CPF(voice), ptarget << 16); | |
1180 | /* turn on envelope */ | |
1181 | awe_poke(AWE_DCYSUSV(voice), | |
1182 | FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY, | |
1183 | vp->parm.voldcysus)); | |
1184 | ||
1185 | voices[voice].state = AWE_ST_ON; | |
1186 | ||
1187 | /* clear voice position for the next note on this channel */ | |
1188 | if (SINGLE_LAYER_MODE()) { | |
1189 | FX_UNSET(fx, AWE_FX_SAMPLE_START); | |
1190 | FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START); | |
1191 | } | |
1192 | } | |
1193 | ||
1194 | ||
1195 | /* turn off the voice */ | |
1196 | static void | |
1197 | awe_note_off(int voice) | |
1198 | { | |
1199 | awe_voice_info *vp; | |
1200 | unsigned short tmp; | |
1201 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1202 | FX_Rec *fx_lay = NULL; | |
1203 | if (voices[voice].layer < MAX_LAYERS) | |
1204 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1205 | ||
1206 | if ((vp = voices[voice].sample) == NULL) { | |
1207 | voices[voice].state = AWE_ST_OFF; | |
1208 | return; | |
1209 | } | |
1210 | ||
1211 | tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE, | |
1212 | (unsigned char)vp->parm.modrelease); | |
1213 | awe_poke(AWE_DCYSUS(voice), tmp); | |
1214 | tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE, | |
1215 | (unsigned char)vp->parm.volrelease); | |
1216 | awe_poke(AWE_DCYSUSV(voice), tmp); | |
1217 | voices[voice].state = AWE_ST_RELEASED; | |
1218 | } | |
1219 | ||
1220 | /* force to terminate the voice (no releasing echo) */ | |
1221 | static void | |
1222 | awe_terminate(int voice) | |
1223 | { | |
1224 | awe_poke(AWE_DCYSUSV(voice), 0x807F); | |
1225 | awe_tweak_voice(voice); | |
1226 | voices[voice].state = AWE_ST_OFF; | |
1227 | } | |
1228 | ||
1229 | /* turn off other voices with the same exclusive class (for drums) */ | |
1230 | static void | |
1231 | awe_exclusive_off(int voice) | |
1232 | { | |
1233 | int i, exclass; | |
1234 | ||
1235 | if (voices[voice].sample == NULL) | |
1236 | return; | |
1237 | if ((exclass = voices[voice].sample->exclusiveClass) == 0) | |
1238 | return; /* not exclusive */ | |
1239 | ||
1240 | /* turn off voices with the same class */ | |
1241 | for (i = 0; i < awe_max_voices; i++) { | |
1242 | if (i != voice && IS_PLAYING(i) && | |
1243 | voices[i].sample && voices[i].ch == voices[voice].ch && | |
1244 | voices[i].sample->exclusiveClass == exclass) { | |
1245 | DEBUG(4,printk("AWE32: [exoff(%d)]\n", i)); | |
1246 | awe_terminate(i); | |
1247 | awe_voice_init(i, TRUE); | |
1248 | } | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | ||
1253 | /* | |
1254 | * change the parameters of an audible voice | |
1255 | */ | |
1256 | ||
1257 | /* change pitch */ | |
1258 | static void | |
1259 | awe_set_pitch(int voice, int forced) | |
1260 | { | |
1261 | if (IS_NO_EFFECT(voice) && !forced) return; | |
1262 | awe_poke(AWE_IP(voice), voices[voice].apitch); | |
1263 | DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch)); | |
1264 | } | |
1265 | ||
1266 | /* calculate & change pitch */ | |
1267 | static void | |
1268 | awe_set_voice_pitch(int voice, int forced) | |
1269 | { | |
1270 | awe_calc_pitch(voice); | |
1271 | awe_set_pitch(voice, forced); | |
1272 | } | |
1273 | ||
1274 | /* change volume & cutoff */ | |
1275 | static void | |
1276 | awe_set_volume(int voice, int forced) | |
1277 | { | |
1278 | awe_voice_info *vp; | |
1279 | unsigned short tmp2; | |
1280 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1281 | FX_Rec *fx_lay = NULL; | |
1282 | if (voices[voice].layer < MAX_LAYERS) | |
1283 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1284 | ||
1285 | if (!IS_PLAYING(voice) && !forced) return; | |
1286 | if ((vp = voices[voice].sample) == NULL || vp->index == 0) | |
1287 | return; | |
1288 | ||
1289 | tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF, | |
1290 | (unsigned char)voices[voice].acutoff); | |
1291 | tmp2 = (tmp2 << 8); | |
1292 | tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN, | |
1293 | (unsigned char)voices[voice].avol); | |
1294 | awe_poke(AWE_IFATN(voice), tmp2); | |
1295 | } | |
1296 | ||
1297 | /* calculate & change volume */ | |
1298 | static void | |
1299 | awe_set_voice_vol(int voice, int forced) | |
1300 | { | |
1301 | if (IS_EMPTY(voice)) | |
1302 | return; | |
1303 | awe_calc_volume(voice); | |
1304 | awe_set_volume(voice, forced); | |
1305 | } | |
1306 | ||
1307 | ||
1308 | /* change pan; this could make a click noise.. */ | |
1309 | static void | |
1310 | awe_set_pan(int voice, int forced) | |
1311 | { | |
1312 | unsigned int temp; | |
1313 | int addr; | |
1314 | awe_voice_info *vp; | |
1315 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1316 | FX_Rec *fx_lay = NULL; | |
1317 | if (voices[voice].layer < MAX_LAYERS) | |
1318 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1319 | ||
1320 | if (IS_NO_EFFECT(voice) && !forced) return; | |
1321 | if ((vp = voices[voice].sample) == NULL || vp->index == 0) | |
1322 | return; | |
1323 | ||
1324 | /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */ | |
1325 | if (vp->fixpan > 0) /* 0-127 */ | |
1326 | temp = 255 - (int)vp->fixpan * 2; | |
1327 | else { | |
1328 | int pos = 0; | |
1329 | if (vp->pan >= 0) /* 0-127 */ | |
1330 | pos = (int)vp->pan * 2 - 128; | |
1331 | pos += voices[voice].cinfo->panning; /* -128 - 127 */ | |
1332 | temp = 127 - pos; | |
1333 | } | |
1334 | limitvalue(temp, 0, 255); | |
1335 | if (ctrls[AWE_MD_PAN_EXCHANGE]) { | |
1336 | temp = 255 - temp; | |
1337 | } | |
1338 | if (forced || temp != voices[voice].apan) { | |
1339 | voices[voice].apan = temp; | |
1340 | if (temp == 0) | |
1341 | voices[voice].aaux = 0xff; | |
1342 | else | |
1343 | voices[voice].aaux = (-temp) & 0xff; | |
1344 | addr = vp->loopstart - 1; | |
1345 | addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START, | |
1346 | AWE_FX_COARSE_LOOP_START, vp->mode); | |
1347 | temp = (temp<<24) | (unsigned int)addr; | |
1348 | awe_poke_dw(AWE_PSST(voice), temp); | |
1349 | DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr)); | |
1350 | } | |
1351 | } | |
1352 | ||
1353 | /* effects change during playing */ | |
1354 | static void | |
1355 | awe_fx_fmmod(int voice, int forced) | |
1356 | { | |
1357 | awe_voice_info *vp; | |
1358 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1359 | FX_Rec *fx_lay = NULL; | |
1360 | if (voices[voice].layer < MAX_LAYERS) | |
1361 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1362 | ||
1363 | if (IS_NO_EFFECT(voice) && !forced) return; | |
1364 | if ((vp = voices[voice].sample) == NULL || vp->index == 0) | |
1365 | return; | |
1366 | awe_poke(AWE_FMMOD(voice), | |
1367 | FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF, | |
1368 | vp->parm.fmmod)); | |
1369 | } | |
1370 | ||
1371 | /* set tremolo (lfo1) volume & frequency */ | |
1372 | static void | |
1373 | awe_fx_tremfrq(int voice, int forced) | |
1374 | { | |
1375 | awe_voice_info *vp; | |
1376 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1377 | FX_Rec *fx_lay = NULL; | |
1378 | if (voices[voice].layer < MAX_LAYERS) | |
1379 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1380 | ||
1381 | if (IS_NO_EFFECT(voice) && !forced) return; | |
1382 | if ((vp = voices[voice].sample) == NULL || vp->index == 0) | |
1383 | return; | |
1384 | awe_poke(AWE_TREMFRQ(voice), | |
1385 | FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ, | |
1386 | vp->parm.tremfrq)); | |
1387 | } | |
1388 | ||
1389 | /* set lfo2 pitch & frequency */ | |
1390 | static void | |
1391 | awe_fx_fm2frq2(int voice, int forced) | |
1392 | { | |
1393 | awe_voice_info *vp; | |
1394 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1395 | FX_Rec *fx_lay = NULL; | |
1396 | if (voices[voice].layer < MAX_LAYERS) | |
1397 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1398 | ||
1399 | if (IS_NO_EFFECT(voice) && !forced) return; | |
1400 | if ((vp = voices[voice].sample) == NULL || vp->index == 0) | |
1401 | return; | |
1402 | awe_poke(AWE_FM2FRQ2(voice), | |
1403 | FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ, | |
1404 | vp->parm.fm2frq2)); | |
1405 | } | |
1406 | ||
1407 | ||
1408 | /* Q & current address (Q 4bit value, MSB) */ | |
1409 | static void | |
1410 | awe_fx_filterQ(int voice, int forced) | |
1411 | { | |
1412 | unsigned int addr; | |
1413 | awe_voice_info *vp; | |
1414 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1415 | FX_Rec *fx_lay = NULL; | |
1416 | if (voices[voice].layer < MAX_LAYERS) | |
1417 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1418 | ||
1419 | if (IS_NO_EFFECT(voice) && !forced) return; | |
1420 | if ((vp = voices[voice].sample) == NULL || vp->index == 0) | |
1421 | return; | |
1422 | ||
1423 | addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff; | |
1424 | addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28); | |
1425 | awe_poke_dw(AWE_CCCA(voice), addr); | |
1426 | } | |
1427 | ||
1428 | /* | |
1429 | * calculate pitch offset | |
1430 | * | |
1431 | * 0xE000 is no pitch offset at 44100Hz sample. | |
1432 | * Every 4096 is one octave. | |
1433 | */ | |
1434 | ||
1435 | static void | |
1436 | awe_calc_pitch(int voice) | |
1437 | { | |
1438 | voice_info *vp = &voices[voice]; | |
1439 | awe_voice_info *ap; | |
1440 | awe_chan_info *cp = voices[voice].cinfo; | |
1441 | int offset; | |
1442 | ||
1443 | /* search voice information */ | |
1444 | if ((ap = vp->sample) == NULL) | |
1445 | return; | |
1446 | if (ap->index == 0) { | |
1447 | DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); | |
1448 | if (awe_set_sample((awe_voice_list*)ap) == 0) | |
1449 | return; | |
1450 | } | |
1451 | ||
1452 | /* calculate offset */ | |
1453 | if (ap->fixkey >= 0) { | |
1454 | DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune)); | |
1455 | offset = (ap->fixkey - ap->root) * 4096 / 12; | |
1456 | } else { | |
1457 | DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune)); | |
1458 | offset = (vp->note - ap->root) * 4096 / 12; | |
1459 | DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset)); | |
1460 | } | |
1461 | offset = (offset * ap->scaleTuning) / 100; | |
1462 | DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset)); | |
1463 | offset += ap->tune * 4096 / 1200; | |
1464 | DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset)); | |
1465 | if (cp->bender != 0) { | |
1466 | DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender)); | |
1467 | /* (819200: 1 semitone) ==> (4096: 12 semitones) */ | |
1468 | offset += cp->bender * cp->bender_range / 2400; | |
1469 | } | |
1470 | ||
1471 | /* add initial pitch correction */ | |
1472 | if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH)) | |
1473 | offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH]; | |
1474 | else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH)) | |
1475 | offset += cp->fx.val[AWE_FX_INIT_PITCH]; | |
1476 | ||
1477 | /* 0xe000: root pitch */ | |
1478 | vp->apitch = 0xe000 + ap->rate_offset + offset; | |
1479 | DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset)); | |
1480 | if (vp->apitch > 0xffff) | |
1481 | vp->apitch = 0xffff; | |
1482 | if (vp->apitch < 0) | |
1483 | vp->apitch = 0; | |
1484 | } | |
1485 | ||
1486 | ||
1487 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
1488 | /* calculate MIDI key and semitone from the specified frequency */ | |
1489 | static void | |
1490 | awe_calc_pitch_from_freq(int voice, int freq) | |
1491 | { | |
1492 | voice_info *vp = &voices[voice]; | |
1493 | awe_voice_info *ap; | |
1494 | FX_Rec *fx = &voices[voice].cinfo->fx; | |
1495 | FX_Rec *fx_lay = NULL; | |
1496 | int offset; | |
1497 | int note; | |
1498 | ||
1499 | if (voices[voice].layer < MAX_LAYERS) | |
1500 | fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; | |
1501 | ||
1502 | /* search voice information */ | |
1503 | if ((ap = vp->sample) == NULL) | |
1504 | return; | |
1505 | if (ap->index == 0) { | |
1506 | DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); | |
1507 | if (awe_set_sample((awe_voice_list*)ap) == 0) | |
1508 | return; | |
1509 | } | |
1510 | note = freq_to_note(freq); | |
1511 | offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200; | |
1512 | offset = (offset * ap->scaleTuning) / 100; | |
1513 | if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH)) | |
1514 | offset += fx_lay->val[AWE_FX_INIT_PITCH]; | |
1515 | else if (FX_ON(fx, AWE_FX_INIT_PITCH)) | |
1516 | offset += fx->val[AWE_FX_INIT_PITCH]; | |
1517 | vp->apitch = 0xe000 + ap->rate_offset + offset; | |
1518 | if (vp->apitch > 0xffff) | |
1519 | vp->apitch = 0xffff; | |
1520 | if (vp->apitch < 0) | |
1521 | vp->apitch = 0; | |
1522 | } | |
1523 | #endif /* AWE_HAS_GUS_COMPATIBILITY */ | |
1524 | ||
1525 | ||
1526 | /* | |
1527 | * calculate volume attenuation | |
1528 | * | |
1529 | * Voice volume is controlled by volume attenuation parameter. | |
1530 | * So volume becomes maximum when avol is 0 (no attenuation), and | |
1531 | * minimum when 255 (-96dB or silence). | |
1532 | */ | |
1533 | ||
1534 | static int vol_table[128] = { | |
1535 | 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49, | |
1536 | 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32, | |
1537 | 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22, | |
1538 | 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16, | |
1539 | 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10, | |
1540 | 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6, | |
1541 | 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3, | |
1542 | 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0, | |
1543 | }; | |
1544 | ||
1545 | /* tables for volume->attenuation calculation */ | |
1546 | static unsigned char voltab1[128] = { | |
1547 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | |
1548 | 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, | |
1549 | 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, | |
1550 | 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, | |
1551 | 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, | |
1552 | 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, | |
1553 | 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, | |
1554 | 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, | |
1555 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, | |
1556 | 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, | |
1557 | 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, | |
1558 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, | |
1559 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
1560 | }; | |
1561 | ||
1562 | static unsigned char voltab2[128] = { | |
1563 | 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a, | |
1564 | 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21, | |
1565 | 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, | |
1566 | 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15, | |
1567 | 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, | |
1568 | 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, | |
1569 | 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, | |
1570 | 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, | |
1571 | 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, | |
1572 | 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, | |
1573 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, | |
1574 | 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, | |
1575 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 | |
1576 | }; | |
1577 | ||
1578 | static unsigned char expressiontab[128] = { | |
1579 | 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42, | |
1580 | 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30, | |
1581 | 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, | |
1582 | 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e, | |
1583 | 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, | |
1584 | 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13, | |
1585 | 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f, | |
1586 | 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, | |
1587 | 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, | |
1588 | 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, | |
1589 | 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, | |
1590 | 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, | |
1591 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
1592 | }; | |
1593 | ||
1594 | static void | |
1595 | awe_calc_volume(int voice) | |
1596 | { | |
1597 | voice_info *vp = &voices[voice]; | |
1598 | awe_voice_info *ap; | |
1599 | awe_chan_info *cp = voices[voice].cinfo; | |
1600 | int vol; | |
1601 | ||
1602 | /* search voice information */ | |
1603 | if ((ap = vp->sample) == NULL) | |
1604 | return; | |
1605 | ||
1606 | ap = vp->sample; | |
1607 | if (ap->index == 0) { | |
1608 | DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); | |
1609 | if (awe_set_sample((awe_voice_list*)ap) == 0) | |
1610 | return; | |
1611 | } | |
1612 | ||
1613 | if (ctrls[AWE_MD_NEW_VOLUME_CALC]) { | |
1614 | int main_vol = cp->main_vol * ap->amplitude / 127; | |
1615 | limitvalue(vp->velocity, 0, 127); | |
1616 | limitvalue(main_vol, 0, 127); | |
1617 | limitvalue(cp->expression_vol, 0, 127); | |
1618 | ||
1619 | vol = voltab1[main_vol] + voltab2[vp->velocity]; | |
1620 | vol = (vol * 8) / 3; | |
1621 | vol += ap->attenuation; | |
1622 | if (cp->expression_vol < 127) | |
1623 | vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128; | |
1624 | vol += atten_offset; | |
1625 | if (atten_relative) | |
1626 | vol += ctrls[AWE_MD_ZERO_ATTEN]; | |
1627 | limitvalue(vol, 0, 255); | |
1628 | vp->avol = vol; | |
1629 | ||
1630 | } else { | |
1631 | /* 0 - 127 */ | |
1632 | vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127); | |
1633 | vol = vol * ap->amplitude / 127; | |
1634 | ||
1635 | if (vol < 0) vol = 0; | |
1636 | if (vol > 127) vol = 127; | |
1637 | ||
1638 | /* calc to attenuation */ | |
1639 | vol = vol_table[vol]; | |
1640 | vol += (int)ap->attenuation; | |
1641 | vol += atten_offset; | |
1642 | if (atten_relative) | |
1643 | vol += ctrls[AWE_MD_ZERO_ATTEN]; | |
1644 | if (vol > 255) vol = 255; | |
1645 | ||
1646 | vp->avol = vol; | |
1647 | } | |
1648 | if (cp->bank != AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) { | |
1649 | int atten; | |
1650 | if (vp->velocity < 70) atten = 70; | |
1651 | else atten = vp->velocity; | |
1652 | vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7; | |
1653 | } else { | |
1654 | vp->acutoff = ap->parm.cutoff; | |
1655 | } | |
1656 | DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol)); | |
1657 | } | |
1658 | ||
1659 | /* change master volume */ | |
1660 | static void | |
1661 | awe_change_master_volume(short val) | |
1662 | { | |
1663 | limitvalue(val, 0, 127); | |
1664 | atten_offset = vol_table[val]; | |
1665 | atten_relative = TRUE; | |
1666 | awe_update_volume(); | |
1667 | } | |
1668 | ||
1669 | /* update volumes of all available channels */ | |
1670 | static void awe_update_volume(void) | |
1671 | { | |
1672 | int i; | |
1673 | for (i = 0; i < awe_max_voices; i++) | |
1674 | awe_set_voice_vol(i, TRUE); | |
1675 | } | |
1676 | ||
1677 | /* set sostenuto on */ | |
1678 | static void awe_sostenuto_on(int voice, int forced) | |
1679 | { | |
1680 | if (IS_NO_EFFECT(voice) && !forced) return; | |
1681 | voices[voice].sostenuto = 127; | |
1682 | } | |
1683 | ||
1684 | ||
1685 | /* drop sustain */ | |
1686 | static void awe_sustain_off(int voice, int forced) | |
1687 | { | |
1688 | if (voices[voice].state == AWE_ST_SUSTAINED) { | |
1689 | awe_note_off(voice); | |
1690 | awe_fx_init(voices[voice].ch); | |
1691 | awe_voice_init(voice, FALSE); | |
1692 | } | |
1693 | } | |
1694 | ||
1695 | ||
1696 | /* terminate and initialize voice */ | |
1697 | static void awe_terminate_and_init(int voice, int forced) | |
1698 | { | |
1699 | awe_terminate(voice); | |
1700 | awe_fx_init(voices[voice].ch); | |
1701 | awe_voice_init(voice, TRUE); | |
1702 | } | |
1703 | ||
1704 | ||
1705 | /* | |
1706 | * synth operation routines | |
1707 | */ | |
1708 | ||
1709 | #define AWE_VOICE_KEY(v) (0x8000 | (v)) | |
1710 | #define AWE_CHAN_KEY(c,n) (((c) << 8) | ((n) + 1)) | |
1711 | #define KEY_CHAN_MATCH(key,c) (((key) >> 8) == (c)) | |
1712 | ||
1713 | /* initialize the voice */ | |
1714 | static void | |
1715 | awe_voice_init(int voice, int init_all) | |
1716 | { | |
1717 | voice_info *vp = &voices[voice]; | |
1718 | ||
1719 | /* reset voice search key */ | |
1720 | if (playing_mode == AWE_PLAY_DIRECT) | |
1721 | vp->key = AWE_VOICE_KEY(voice); | |
1722 | else | |
1723 | vp->key = 0; | |
1724 | ||
1725 | /* clear voice mapping */ | |
1726 | voice_alloc->map[voice] = 0; | |
1727 | ||
1728 | /* touch the timing flag */ | |
1729 | vp->time = current_alloc_time; | |
1730 | ||
1731 | /* initialize other parameters if necessary */ | |
1732 | if (init_all) { | |
1733 | vp->note = -1; | |
1734 | vp->velocity = 0; | |
1735 | vp->sostenuto = 0; | |
1736 | ||
1737 | vp->sample = NULL; | |
1738 | vp->cinfo = &channels[voice]; | |
1739 | vp->ch = voice; | |
1740 | vp->state = AWE_ST_OFF; | |
1741 | ||
1742 | /* emu8000 parameters */ | |
1743 | vp->apitch = 0; | |
1744 | vp->avol = 255; | |
1745 | vp->apan = -1; | |
1746 | } | |
1747 | } | |
1748 | ||
1749 | /* clear effects */ | |
1750 | static void awe_fx_init(int ch) | |
1751 | { | |
1752 | if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) { | |
1753 | memset(&channels[ch].fx, 0, sizeof(channels[ch].fx)); | |
1754 | memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer)); | |
1755 | } | |
1756 | } | |
1757 | ||
1758 | /* initialize channel info */ | |
1759 | static void awe_channel_init(int ch, int init_all) | |
1760 | { | |
1761 | awe_chan_info *cp = &channels[ch]; | |
1762 | cp->channel = ch; | |
1763 | if (init_all) { | |
1764 | cp->panning = 0; /* zero center */ | |
1765 | cp->bender_range = 200; /* sense * 100 */ | |
1766 | cp->main_vol = 127; | |
1767 | if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) { | |
1768 | cp->instr = ctrls[AWE_MD_DEF_DRUM]; | |
1769 | cp->bank = AWE_DRUM_BANK; | |
1770 | } else { | |
1771 | cp->instr = ctrls[AWE_MD_DEF_PRESET]; | |
1772 | cp->bank = ctrls[AWE_MD_DEF_BANK]; | |
1773 | } | |
1774 | } | |
1775 | ||
1776 | cp->bender = 0; /* zero tune skew */ | |
1777 | cp->expression_vol = 127; | |
1778 | cp->chan_press = 0; | |
1779 | cp->sustained = 0; | |
1780 | ||
1781 | if (! ctrls[AWE_MD_KEEP_EFFECT]) { | |
1782 | memset(&cp->fx, 0, sizeof(cp->fx)); | |
1783 | memset(&cp->fx_layer, 0, sizeof(cp->fx_layer)); | |
1784 | } | |
1785 | } | |
1786 | ||
1787 | ||
1788 | /* change the voice parameters; voice = channel */ | |
1789 | static void awe_voice_change(int voice, fx_affect_func func) | |
1790 | { | |
1791 | int i; | |
1792 | switch (playing_mode) { | |
1793 | case AWE_PLAY_DIRECT: | |
1794 | func(voice, FALSE); | |
1795 | break; | |
1796 | case AWE_PLAY_INDIRECT: | |
1797 | for (i = 0; i < awe_max_voices; i++) | |
1798 | if (voices[i].key == AWE_VOICE_KEY(voice)) | |
1799 | func(i, FALSE); | |
1800 | break; | |
1801 | default: | |
1802 | for (i = 0; i < awe_max_voices; i++) | |
1803 | if (KEY_CHAN_MATCH(voices[i].key, voice)) | |
1804 | func(i, FALSE); | |
1805 | break; | |
1806 | } | |
1807 | } | |
1808 | ||
1809 | ||
1810 | /* | |
1811 | * device open / close | |
1812 | */ | |
1813 | ||
1814 | /* open device: | |
1815 | * reset status of all voices, and clear sample position flag | |
1816 | */ | |
1817 | static int | |
1818 | awe_open(int dev, int mode) | |
1819 | { | |
1820 | if (awe_busy) | |
1821 | return -EBUSY; | |
1822 | ||
1823 | awe_busy = TRUE; | |
1824 | ||
1825 | /* set default mode */ | |
1826 | awe_init_ctrl_parms(FALSE); | |
1827 | atten_relative = TRUE; | |
1828 | atten_offset = 0; | |
1829 | drum_flags = DEFAULT_DRUM_FLAGS; | |
1830 | playing_mode = AWE_PLAY_INDIRECT; | |
1831 | ||
1832 | /* reset voices & channels */ | |
1833 | awe_reset(dev); | |
1834 | ||
1835 | patch_opened = 0; | |
1836 | ||
1837 | return 0; | |
1838 | } | |
1839 | ||
1840 | ||
1841 | /* close device: | |
1842 | * reset all voices again (terminate sounds) | |
1843 | */ | |
1844 | static void | |
1845 | awe_close(int dev) | |
1846 | { | |
1847 | awe_reset(dev); | |
1848 | awe_busy = FALSE; | |
1849 | } | |
1850 | ||
1851 | ||
1852 | /* set miscellaneous mode parameters | |
1853 | */ | |
1854 | static void | |
1855 | awe_init_ctrl_parms(int init_all) | |
1856 | { | |
1857 | int i; | |
1858 | for (i = 0; i < AWE_MD_END; i++) { | |
1859 | if (init_all || ctrl_parms[i].init_each_time) | |
1860 | ctrls[i] = ctrl_parms[i].value; | |
1861 | } | |
1862 | } | |
1863 | ||
1864 | ||
1865 | /* sequencer I/O control: | |
1866 | */ | |
1867 | static int | |
1868 | awe_ioctl(int dev, unsigned int cmd, void __user *arg) | |
1869 | { | |
1870 | switch (cmd) { | |
1871 | case SNDCTL_SYNTH_INFO: | |
1872 | if (playing_mode == AWE_PLAY_DIRECT) | |
1873 | awe_info.nr_voices = awe_max_voices; | |
1874 | else | |
1875 | awe_info.nr_voices = AWE_MAX_CHANNELS; | |
1876 | if (copy_to_user(arg, &awe_info, sizeof(awe_info))) | |
1877 | return -EFAULT; | |
1878 | return 0; | |
1879 | break; | |
1880 | ||
1881 | case SNDCTL_SEQ_RESETSAMPLES: | |
1882 | awe_reset(dev); | |
1883 | awe_reset_samples(); | |
1884 | return 0; | |
1885 | break; | |
1886 | ||
1887 | case SNDCTL_SEQ_PERCMODE: | |
1888 | /* what's this? */ | |
1889 | return 0; | |
1890 | break; | |
1891 | ||
1892 | case SNDCTL_SYNTH_MEMAVL: | |
1893 | return memsize - awe_free_mem_ptr() * 2; | |
1894 | break; | |
1895 | ||
1896 | default: | |
1897 | printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd); | |
1898 | return -EINVAL; | |
1899 | break; | |
1900 | } | |
1901 | } | |
1902 | ||
1903 | ||
1904 | static int voice_in_range(int voice) | |
1905 | { | |
1906 | if (playing_mode == AWE_PLAY_DIRECT) { | |
1907 | if (voice < 0 || voice >= awe_max_voices) | |
1908 | return FALSE; | |
1909 | } else { | |
1910 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
1911 | return FALSE; | |
1912 | } | |
1913 | return TRUE; | |
1914 | } | |
1915 | ||
1916 | static void release_voice(int voice, int do_sustain) | |
1917 | { | |
1918 | if (IS_NO_SOUND(voice)) | |
1919 | return; | |
1920 | if (do_sustain && (voices[voice].cinfo->sustained == 127 || | |
1921 | voices[voice].sostenuto == 127)) | |
1922 | voices[voice].state = AWE_ST_SUSTAINED; | |
1923 | else { | |
1924 | awe_note_off(voice); | |
1925 | awe_fx_init(voices[voice].ch); | |
1926 | awe_voice_init(voice, FALSE); | |
1927 | } | |
1928 | } | |
1929 | ||
1930 | /* release all notes */ | |
1931 | static void awe_note_off_all(int do_sustain) | |
1932 | { | |
1933 | int i; | |
1934 | for (i = 0; i < awe_max_voices; i++) | |
1935 | release_voice(i, do_sustain); | |
1936 | } | |
1937 | ||
1938 | /* kill a voice: | |
1939 | * not terminate, just release the voice. | |
1940 | */ | |
1941 | static int | |
1942 | awe_kill_note(int dev, int voice, int note, int velocity) | |
1943 | { | |
1944 | int i, v2, key; | |
1945 | ||
1946 | DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity)); | |
1947 | if (! voice_in_range(voice)) | |
1948 | return -EINVAL; | |
1949 | ||
1950 | switch (playing_mode) { | |
1951 | case AWE_PLAY_DIRECT: | |
1952 | case AWE_PLAY_INDIRECT: | |
1953 | key = AWE_VOICE_KEY(voice); | |
1954 | break; | |
1955 | ||
1956 | case AWE_PLAY_MULTI2: | |
1957 | v2 = voice_alloc->map[voice] >> 8; | |
1958 | voice_alloc->map[voice] = 0; | |
1959 | voice = v2; | |
1960 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
1961 | return -EINVAL; | |
1962 | /* continue to below */ | |
1963 | default: | |
1964 | key = AWE_CHAN_KEY(voice, note); | |
1965 | break; | |
1966 | } | |
1967 | ||
1968 | for (i = 0; i < awe_max_voices; i++) { | |
1969 | if (voices[i].key == key) | |
1970 | release_voice(i, TRUE); | |
1971 | } | |
1972 | return 0; | |
1973 | } | |
1974 | ||
1975 | ||
1976 | static void start_or_volume_change(int voice, int velocity) | |
1977 | { | |
1978 | voices[voice].velocity = velocity; | |
1979 | awe_calc_volume(voice); | |
1980 | if (voices[voice].state == AWE_ST_STANDBY) | |
1981 | awe_note_on(voice); | |
1982 | else if (voices[voice].state == AWE_ST_ON) | |
1983 | awe_set_volume(voice, FALSE); | |
1984 | } | |
1985 | ||
1986 | static void set_and_start_voice(int voice, int state) | |
1987 | { | |
1988 | /* calculate pitch & volume parameters */ | |
1989 | voices[voice].state = state; | |
1990 | awe_calc_pitch(voice); | |
1991 | awe_calc_volume(voice); | |
1992 | if (state == AWE_ST_ON) | |
1993 | awe_note_on(voice); | |
1994 | } | |
1995 | ||
1996 | /* start a voice: | |
1997 | * if note is 255, identical with aftertouch function. | |
1998 | * Otherwise, start a voice with specified not and volume. | |
1999 | */ | |
2000 | static int | |
2001 | awe_start_note(int dev, int voice, int note, int velocity) | |
2002 | { | |
2003 | int i, key, state, volonly; | |
2004 | ||
2005 | DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity)); | |
2006 | if (! voice_in_range(voice)) | |
2007 | return -EINVAL; | |
2008 | ||
2009 | if (velocity == 0) | |
2010 | state = AWE_ST_STANDBY; /* stand by for playing */ | |
2011 | else | |
2012 | state = AWE_ST_ON; /* really play */ | |
2013 | volonly = FALSE; | |
2014 | ||
2015 | switch (playing_mode) { | |
2016 | case AWE_PLAY_DIRECT: | |
2017 | case AWE_PLAY_INDIRECT: | |
2018 | key = AWE_VOICE_KEY(voice); | |
2019 | if (note == 255) | |
2020 | volonly = TRUE; | |
2021 | break; | |
2022 | ||
2023 | case AWE_PLAY_MULTI2: | |
2024 | voice = voice_alloc->map[voice] >> 8; | |
2025 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
2026 | return -EINVAL; | |
2027 | /* continue to below */ | |
2028 | default: | |
2029 | if (note >= 128) { /* key volume mode */ | |
2030 | note -= 128; | |
2031 | volonly = TRUE; | |
2032 | } | |
2033 | key = AWE_CHAN_KEY(voice, note); | |
2034 | break; | |
2035 | } | |
2036 | ||
2037 | /* dynamic volume change */ | |
2038 | if (volonly) { | |
2039 | for (i = 0; i < awe_max_voices; i++) { | |
2040 | if (voices[i].key == key) | |
2041 | start_or_volume_change(i, velocity); | |
2042 | } | |
2043 | return 0; | |
2044 | } | |
2045 | ||
2046 | /* if the same note still playing, stop it */ | |
2047 | if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) { | |
2048 | for (i = 0; i < awe_max_voices; i++) | |
2049 | if (voices[i].key == key) { | |
2050 | if (voices[i].state == AWE_ST_ON) { | |
2051 | awe_note_off(i); | |
2052 | awe_voice_init(i, FALSE); | |
2053 | } else if (voices[i].state == AWE_ST_STANDBY) | |
2054 | awe_voice_init(i, TRUE); | |
2055 | } | |
2056 | } | |
2057 | ||
2058 | /* allocate voices */ | |
2059 | if (playing_mode == AWE_PLAY_DIRECT) | |
2060 | awe_alloc_one_voice(voice, note, velocity); | |
2061 | else | |
2062 | awe_alloc_multi_voices(voice, note, velocity, key); | |
2063 | ||
2064 | /* turn off other voices exlusively (for drums) */ | |
2065 | for (i = 0; i < awe_max_voices; i++) | |
2066 | if (voices[i].key == key) | |
2067 | awe_exclusive_off(i); | |
2068 | ||
2069 | /* set up pitch and volume parameters */ | |
2070 | for (i = 0; i < awe_max_voices; i++) { | |
2071 | if (voices[i].key == key && voices[i].state == AWE_ST_OFF) | |
2072 | set_and_start_voice(i, state); | |
2073 | } | |
2074 | ||
2075 | return 0; | |
2076 | } | |
2077 | ||
2078 | ||
2079 | /* calculate hash key */ | |
2080 | static int | |
2081 | awe_search_key(int bank, int preset, int note) | |
2082 | { | |
2083 | unsigned int key; | |
2084 | ||
2085 | #if 1 /* new hash table */ | |
2086 | if (bank == AWE_DRUM_BANK) | |
2087 | key = preset + note + 128; | |
2088 | else | |
2089 | key = bank + preset; | |
2090 | #else | |
2091 | key = preset; | |
2092 | #endif | |
2093 | key %= AWE_MAX_PRESETS; | |
2094 | ||
2095 | return (int)key; | |
2096 | } | |
2097 | ||
2098 | ||
2099 | /* search instrument from hash table */ | |
2100 | static awe_voice_list * | |
2101 | awe_search_instr(int bank, int preset, int note) | |
2102 | { | |
2103 | awe_voice_list *p; | |
2104 | int key, key2; | |
2105 | ||
2106 | key = awe_search_key(bank, preset, note); | |
2107 | for (p = preset_table[key]; p; p = p->next_bank) { | |
2108 | if (p->instr == preset && p->bank == bank) | |
2109 | return p; | |
2110 | } | |
2111 | key2 = awe_search_key(bank, preset, 0); /* search default */ | |
2112 | if (key == key2) | |
2113 | return NULL; | |
2114 | for (p = preset_table[key2]; p; p = p->next_bank) { | |
2115 | if (p->instr == preset && p->bank == bank) | |
2116 | return p; | |
2117 | } | |
2118 | return NULL; | |
2119 | } | |
2120 | ||
2121 | ||
2122 | /* assign the instrument to a voice */ | |
2123 | static int | |
2124 | awe_set_instr_2(int dev, int voice, int instr_no) | |
2125 | { | |
2126 | if (playing_mode == AWE_PLAY_MULTI2) { | |
2127 | voice = voice_alloc->map[voice] >> 8; | |
2128 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
2129 | return -EINVAL; | |
2130 | } | |
2131 | return awe_set_instr(dev, voice, instr_no); | |
2132 | } | |
2133 | ||
2134 | /* assign the instrument to a channel; voice is the channel number */ | |
2135 | static int | |
2136 | awe_set_instr(int dev, int voice, int instr_no) | |
2137 | { | |
2138 | awe_chan_info *cinfo; | |
2139 | ||
2140 | if (! voice_in_range(voice)) | |
2141 | return -EINVAL; | |
2142 | ||
2143 | if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS) | |
2144 | return -EINVAL; | |
2145 | ||
2146 | cinfo = &channels[voice]; | |
2147 | cinfo->instr = instr_no; | |
2148 | DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no)); | |
2149 | ||
2150 | return 0; | |
2151 | } | |
2152 | ||
2153 | ||
2154 | /* reset all voices; terminate sounds and initialize parameters */ | |
2155 | static void | |
2156 | awe_reset(int dev) | |
2157 | { | |
2158 | int i; | |
2159 | current_alloc_time = 0; | |
2160 | /* don't turn off voice 31 and 32. they are used also for FM voices */ | |
2161 | for (i = 0; i < awe_max_voices; i++) { | |
2162 | awe_terminate(i); | |
2163 | awe_voice_init(i, TRUE); | |
2164 | } | |
2165 | for (i = 0; i < AWE_MAX_CHANNELS; i++) | |
2166 | awe_channel_init(i, TRUE); | |
2167 | for (i = 0; i < 16; i++) { | |
2168 | awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127; | |
2169 | awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127; | |
2170 | } | |
2171 | awe_init_fm(); | |
2172 | awe_tweak(); | |
2173 | } | |
2174 | ||
2175 | ||
2176 | /* hardware specific control: | |
2177 | * GUS specific and AWE32 specific controls are available. | |
2178 | */ | |
2179 | static void | |
2180 | awe_hw_control(int dev, unsigned char *event) | |
2181 | { | |
2182 | int cmd = event[2]; | |
2183 | if (cmd & _AWE_MODE_FLAG) | |
2184 | awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event); | |
2185 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
2186 | else | |
2187 | awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event); | |
2188 | #endif | |
2189 | } | |
2190 | ||
2191 | ||
2192 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
2193 | ||
2194 | /* GUS compatible controls */ | |
2195 | static void | |
2196 | awe_hw_gus_control(int dev, int cmd, unsigned char *event) | |
2197 | { | |
2198 | int voice, i, key; | |
2199 | unsigned short p1; | |
2200 | short p2; | |
2201 | int plong; | |
2202 | ||
2203 | if (MULTI_LAYER_MODE()) | |
2204 | return; | |
2205 | if (cmd == _GUS_NUMVOICES) | |
2206 | return; | |
2207 | ||
2208 | voice = event[3]; | |
2209 | if (! voice_in_range(voice)) | |
2210 | return; | |
2211 | ||
2212 | p1 = *(unsigned short *) &event[4]; | |
2213 | p2 = *(short *) &event[6]; | |
2214 | plong = *(int*) &event[4]; | |
2215 | ||
2216 | switch (cmd) { | |
2217 | case _GUS_VOICESAMPLE: | |
2218 | awe_set_instr(dev, voice, p1); | |
2219 | return; | |
2220 | ||
2221 | case _GUS_VOICEBALA: | |
2222 | /* 0 to 15 --> -128 to 127 */ | |
2223 | awe_panning(dev, voice, ((int)p1 << 4) - 128); | |
2224 | return; | |
2225 | ||
2226 | case _GUS_VOICEVOL: | |
2227 | case _GUS_VOICEVOL2: | |
2228 | /* not supported yet */ | |
2229 | return; | |
2230 | ||
2231 | case _GUS_RAMPRANGE: | |
2232 | case _GUS_RAMPRATE: | |
2233 | case _GUS_RAMPMODE: | |
2234 | case _GUS_RAMPON: | |
2235 | case _GUS_RAMPOFF: | |
2236 | /* volume ramping not supported */ | |
2237 | return; | |
2238 | ||
2239 | case _GUS_VOLUME_SCALE: | |
2240 | return; | |
2241 | ||
2242 | case _GUS_VOICE_POS: | |
2243 | FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START, | |
2244 | (short)(plong & 0x7fff)); | |
2245 | FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START, | |
2246 | (plong >> 15) & 0xffff); | |
2247 | return; | |
2248 | } | |
2249 | ||
2250 | key = AWE_VOICE_KEY(voice); | |
2251 | for (i = 0; i < awe_max_voices; i++) { | |
2252 | if (voices[i].key == key) { | |
2253 | switch (cmd) { | |
2254 | case _GUS_VOICEON: | |
2255 | awe_note_on(i); | |
2256 | break; | |
2257 | ||
2258 | case _GUS_VOICEOFF: | |
2259 | awe_terminate(i); | |
2260 | awe_fx_init(voices[i].ch); | |
2261 | awe_voice_init(i, TRUE); | |
2262 | break; | |
2263 | ||
2264 | case _GUS_VOICEFADE: | |
2265 | awe_note_off(i); | |
2266 | awe_fx_init(voices[i].ch); | |
2267 | awe_voice_init(i, FALSE); | |
2268 | break; | |
2269 | ||
2270 | case _GUS_VOICEFREQ: | |
2271 | awe_calc_pitch_from_freq(i, plong); | |
2272 | break; | |
2273 | } | |
2274 | } | |
2275 | } | |
2276 | } | |
2277 | ||
2278 | #endif /* gus_compat */ | |
2279 | ||
2280 | ||
2281 | /* AWE32 specific controls */ | |
2282 | static void | |
2283 | awe_hw_awe_control(int dev, int cmd, unsigned char *event) | |
2284 | { | |
2285 | int voice; | |
2286 | unsigned short p1; | |
2287 | short p2; | |
2288 | int i; | |
2289 | ||
2290 | voice = event[3]; | |
2291 | if (! voice_in_range(voice)) | |
2292 | return; | |
2293 | ||
2294 | if (playing_mode == AWE_PLAY_MULTI2) { | |
2295 | voice = voice_alloc->map[voice] >> 8; | |
2296 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
2297 | return; | |
2298 | } | |
2299 | ||
2300 | p1 = *(unsigned short *) &event[4]; | |
2301 | p2 = *(short *) &event[6]; | |
2302 | ||
2303 | switch (cmd) { | |
2304 | case _AWE_DEBUG_MODE: | |
2305 | ctrls[AWE_MD_DEBUG_MODE] = p1; | |
2306 | printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]); | |
2307 | break; | |
2308 | case _AWE_REVERB_MODE: | |
2309 | ctrls[AWE_MD_REVERB_MODE] = p1; | |
2310 | awe_update_reverb_mode(); | |
2311 | break; | |
2312 | ||
2313 | case _AWE_CHORUS_MODE: | |
2314 | ctrls[AWE_MD_CHORUS_MODE] = p1; | |
2315 | awe_update_chorus_mode(); | |
2316 | break; | |
2317 | ||
2318 | case _AWE_REMOVE_LAST_SAMPLES: | |
2319 | DEBUG(0,printk("AWE32: remove last samples\n")); | |
2320 | awe_reset(0); | |
2321 | if (locked_sf_id > 0) | |
2322 | awe_remove_samples(locked_sf_id); | |
2323 | break; | |
2324 | ||
2325 | case _AWE_INITIALIZE_CHIP: | |
2326 | awe_initialize(); | |
2327 | break; | |
2328 | ||
2329 | case _AWE_SEND_EFFECT: | |
2330 | i = -1; | |
2331 | if (p1 >= 0x100) { | |
2332 | i = (p1 >> 8); | |
2333 | if (i < 0 || i >= MAX_LAYERS) | |
2334 | break; | |
2335 | } | |
2336 | awe_send_effect(voice, i, p1, p2); | |
2337 | break; | |
2338 | ||
2339 | case _AWE_RESET_CHANNEL: | |
2340 | awe_channel_init(voice, !p1); | |
2341 | break; | |
2342 | ||
2343 | case _AWE_TERMINATE_ALL: | |
2344 | awe_reset(0); | |
2345 | break; | |
2346 | ||
2347 | case _AWE_TERMINATE_CHANNEL: | |
2348 | awe_voice_change(voice, awe_terminate_and_init); | |
2349 | break; | |
2350 | ||
2351 | case _AWE_RELEASE_ALL: | |
2352 | awe_note_off_all(FALSE); | |
2353 | break; | |
2354 | case _AWE_NOTEOFF_ALL: | |
2355 | awe_note_off_all(TRUE); | |
2356 | break; | |
2357 | ||
2358 | case _AWE_INITIAL_VOLUME: | |
2359 | DEBUG(0,printk("AWE32: init attenuation %d\n", p1)); | |
2360 | atten_relative = (char)p2; | |
2361 | atten_offset = (short)p1; | |
2362 | awe_update_volume(); | |
2363 | break; | |
2364 | ||
2365 | case _AWE_CHN_PRESSURE: | |
2366 | channels[voice].chan_press = p1; | |
2367 | awe_modwheel_change(voice, p1); | |
2368 | break; | |
2369 | ||
2370 | case _AWE_CHANNEL_MODE: | |
2371 | DEBUG(0,printk("AWE32: channel mode = %d\n", p1)); | |
2372 | playing_mode = p1; | |
2373 | awe_reset(0); | |
2374 | break; | |
2375 | ||
2376 | case _AWE_DRUM_CHANNELS: | |
2377 | DEBUG(0,printk("AWE32: drum flags = %x\n", p1)); | |
2378 | drum_flags = *(unsigned int*)&event[4]; | |
2379 | break; | |
2380 | ||
2381 | case _AWE_MISC_MODE: | |
2382 | DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2)); | |
2383 | if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) { | |
2384 | ctrls[p1] = p2; | |
2385 | if (ctrl_parms[p1].update) | |
2386 | ctrl_parms[p1].update(); | |
2387 | } | |
2388 | break; | |
2389 | ||
2390 | case _AWE_EQUALIZER: | |
2391 | ctrls[AWE_MD_BASS_LEVEL] = p1; | |
2392 | ctrls[AWE_MD_TREBLE_LEVEL] = p2; | |
2393 | awe_update_equalizer(); | |
2394 | break; | |
2395 | ||
2396 | default: | |
2397 | DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice)); | |
2398 | break; | |
2399 | } | |
2400 | } | |
2401 | ||
2402 | ||
2403 | /* change effects */ | |
2404 | static void | |
2405 | awe_send_effect(int voice, int layer, int type, int val) | |
2406 | { | |
2407 | awe_chan_info *cinfo; | |
2408 | FX_Rec *fx; | |
2409 | int mode; | |
2410 | ||
2411 | cinfo = &channels[voice]; | |
2412 | if (layer >= 0 && layer < MAX_LAYERS) | |
2413 | fx = &cinfo->fx_layer[layer]; | |
2414 | else | |
2415 | fx = &cinfo->fx; | |
2416 | ||
2417 | if (type & 0x40) | |
2418 | mode = FX_FLAG_OFF; | |
2419 | else if (type & 0x80) | |
2420 | mode = FX_FLAG_ADD; | |
2421 | else | |
2422 | mode = FX_FLAG_SET; | |
2423 | type &= 0x3f; | |
2424 | ||
2425 | if (type >= 0 && type < AWE_FX_END) { | |
2426 | DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val)); | |
2427 | if (mode == FX_FLAG_SET) | |
2428 | FX_SET(fx, type, val); | |
2429 | else if (mode == FX_FLAG_ADD) | |
2430 | FX_ADD(fx, type, val); | |
2431 | else | |
2432 | FX_UNSET(fx, type); | |
2433 | if (mode != FX_FLAG_OFF && parm_defs[type].realtime) { | |
2434 | DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice)); | |
2435 | awe_voice_change(voice, parm_defs[type].realtime); | |
2436 | } | |
2437 | } | |
2438 | } | |
2439 | ||
2440 | ||
2441 | /* change modulation wheel; voice is already mapped on multi2 mode */ | |
2442 | static void | |
2443 | awe_modwheel_change(int voice, int value) | |
2444 | { | |
2445 | int i; | |
2446 | awe_chan_info *cinfo; | |
2447 | ||
2448 | cinfo = &channels[voice]; | |
2449 | i = value * ctrls[AWE_MD_MOD_SENSE] / 1200; | |
2450 | FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i); | |
2451 | awe_voice_change(voice, awe_fx_fmmod); | |
2452 | FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i); | |
2453 | awe_voice_change(voice, awe_fx_fm2frq2); | |
2454 | } | |
2455 | ||
2456 | ||
2457 | /* voice pressure change */ | |
2458 | static void | |
2459 | awe_aftertouch(int dev, int voice, int pressure) | |
2460 | { | |
2461 | int note; | |
2462 | ||
2463 | DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure)); | |
2464 | if (! voice_in_range(voice)) | |
2465 | return; | |
2466 | ||
2467 | switch (playing_mode) { | |
2468 | case AWE_PLAY_DIRECT: | |
2469 | case AWE_PLAY_INDIRECT: | |
2470 | awe_start_note(dev, voice, 255, pressure); | |
2471 | break; | |
2472 | case AWE_PLAY_MULTI2: | |
2473 | note = (voice_alloc->map[voice] & 0xff) - 1; | |
2474 | awe_key_pressure(dev, voice, note + 0x80, pressure); | |
2475 | break; | |
2476 | } | |
2477 | } | |
2478 | ||
2479 | ||
2480 | /* voice control change */ | |
2481 | static void | |
2482 | awe_controller(int dev, int voice, int ctrl_num, int value) | |
2483 | { | |
2484 | awe_chan_info *cinfo; | |
2485 | ||
2486 | if (! voice_in_range(voice)) | |
2487 | return; | |
2488 | ||
2489 | if (playing_mode == AWE_PLAY_MULTI2) { | |
2490 | voice = voice_alloc->map[voice] >> 8; | |
2491 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
2492 | return; | |
2493 | } | |
2494 | ||
2495 | cinfo = &channels[voice]; | |
2496 | ||
2497 | switch (ctrl_num) { | |
2498 | case CTL_BANK_SELECT: /* MIDI control #0 */ | |
2499 | DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value)); | |
2500 | if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) && | |
2501 | !ctrls[AWE_MD_TOGGLE_DRUM_BANK]) | |
2502 | break; | |
2503 | if (value < 0 || value > 255) | |
2504 | break; | |
2505 | cinfo->bank = value; | |
2506 | if (cinfo->bank == AWE_DRUM_BANK) | |
2507 | DRUM_CHANNEL_ON(cinfo->channel); | |
2508 | else | |
2509 | DRUM_CHANNEL_OFF(cinfo->channel); | |
2510 | awe_set_instr(dev, voice, cinfo->instr); | |
2511 | break; | |
2512 | ||
2513 | case CTL_MODWHEEL: /* MIDI control #1 */ | |
2514 | DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value)); | |
2515 | awe_modwheel_change(voice, value); | |
2516 | break; | |
2517 | ||
2518 | case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */ | |
2519 | DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value)); | |
2520 | /* zero centered */ | |
2521 | cinfo->bender = value; | |
2522 | awe_voice_change(voice, awe_set_voice_pitch); | |
2523 | break; | |
2524 | ||
2525 | case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */ | |
2526 | DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value)); | |
2527 | /* value = sense x 100 */ | |
2528 | cinfo->bender_range = value; | |
2529 | /* no audible pitch change yet.. */ | |
2530 | break; | |
2531 | ||
2532 | case CTL_EXPRESSION: /* MIDI control #11 */ | |
2533 | if (SINGLE_LAYER_MODE()) | |
2534 | value /= 128; | |
2535 | case CTRL_EXPRESSION: /* SEQ1 V2 control */ | |
2536 | DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value)); | |
2537 | /* 0 - 127 */ | |
2538 | cinfo->expression_vol = value; | |
2539 | awe_voice_change(voice, awe_set_voice_vol); | |
2540 | break; | |
2541 | ||
2542 | case CTL_PAN: /* MIDI control #10 */ | |
2543 | DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value)); | |
2544 | /* (0-127) -> signed 8bit */ | |
2545 | cinfo->panning = value * 2 - 128; | |
2546 | if (ctrls[AWE_MD_REALTIME_PAN]) | |
2547 | awe_voice_change(voice, awe_set_pan); | |
2548 | break; | |
2549 | ||
2550 | case CTL_MAIN_VOLUME: /* MIDI control #7 */ | |
2551 | if (SINGLE_LAYER_MODE()) | |
2552 | value = (value * 100) / 16383; | |
2553 | case CTRL_MAIN_VOLUME: /* SEQ1 V2 control */ | |
2554 | DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value)); | |
2555 | /* 0 - 127 */ | |
2556 | cinfo->main_vol = value; | |
2557 | awe_voice_change(voice, awe_set_voice_vol); | |
2558 | break; | |
2559 | ||
2560 | case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */ | |
2561 | DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value)); | |
2562 | FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2); | |
2563 | break; | |
2564 | ||
2565 | case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */ | |
2566 | DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value)); | |
2567 | FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2); | |
2568 | break; | |
2569 | ||
2570 | case 120: /* all sounds off */ | |
2571 | awe_note_off_all(FALSE); | |
2572 | break; | |
2573 | case 123: /* all notes off */ | |
2574 | awe_note_off_all(TRUE); | |
2575 | break; | |
2576 | ||
2577 | case CTL_SUSTAIN: /* MIDI control #64 */ | |
2578 | cinfo->sustained = value; | |
2579 | if (value != 127) | |
2580 | awe_voice_change(voice, awe_sustain_off); | |
2581 | break; | |
2582 | ||
2583 | case CTL_SOSTENUTO: /* MIDI control #66 */ | |
2584 | if (value == 127) | |
2585 | awe_voice_change(voice, awe_sostenuto_on); | |
2586 | else | |
2587 | awe_voice_change(voice, awe_sustain_off); | |
2588 | break; | |
2589 | ||
2590 | default: | |
2591 | DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n", | |
2592 | voice, ctrl_num, value)); | |
2593 | break; | |
2594 | } | |
2595 | } | |
2596 | ||
2597 | ||
2598 | /* voice pan change (value = -128 - 127) */ | |
2599 | static void | |
2600 | awe_panning(int dev, int voice, int value) | |
2601 | { | |
2602 | awe_chan_info *cinfo; | |
2603 | ||
2604 | if (! voice_in_range(voice)) | |
2605 | return; | |
2606 | ||
2607 | if (playing_mode == AWE_PLAY_MULTI2) { | |
2608 | voice = voice_alloc->map[voice] >> 8; | |
2609 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
2610 | return; | |
2611 | } | |
2612 | ||
2613 | cinfo = &channels[voice]; | |
2614 | cinfo->panning = value; | |
2615 | DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning)); | |
2616 | if (ctrls[AWE_MD_REALTIME_PAN]) | |
2617 | awe_voice_change(voice, awe_set_pan); | |
2618 | } | |
2619 | ||
2620 | ||
2621 | /* volume mode change */ | |
2622 | static void | |
2623 | awe_volume_method(int dev, int mode) | |
2624 | { | |
2625 | /* not impremented */ | |
2626 | DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode)); | |
2627 | } | |
2628 | ||
2629 | ||
2630 | /* pitch wheel change: 0-16384 */ | |
2631 | static void | |
2632 | awe_bender(int dev, int voice, int value) | |
2633 | { | |
2634 | awe_chan_info *cinfo; | |
2635 | ||
2636 | if (! voice_in_range(voice)) | |
2637 | return; | |
2638 | ||
2639 | if (playing_mode == AWE_PLAY_MULTI2) { | |
2640 | voice = voice_alloc->map[voice] >> 8; | |
2641 | if (voice < 0 || voice >= AWE_MAX_CHANNELS) | |
2642 | return; | |
2643 | } | |
2644 | ||
2645 | /* convert to zero centered value */ | |
2646 | cinfo = &channels[voice]; | |
2647 | cinfo->bender = value - 8192; | |
2648 | DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender)); | |
2649 | awe_voice_change(voice, awe_set_voice_pitch); | |
2650 | } | |
2651 | ||
2652 | ||
2653 | /* | |
2654 | * load a sound patch: | |
2655 | * three types of patches are accepted: AWE, GUS, and SYSEX. | |
2656 | */ | |
2657 | ||
2658 | static int | |
2659 | awe_load_patch(int dev, int format, const char __user *addr, | |
2660 | int offs, int count, int pmgr_flag) | |
2661 | { | |
2662 | awe_patch_info patch; | |
2663 | int rc = 0; | |
2664 | ||
2665 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
2666 | if (format == GUS_PATCH) { | |
2667 | return awe_load_guspatch(addr, offs, count, pmgr_flag); | |
2668 | } else | |
2669 | #endif | |
2670 | if (format == SYSEX_PATCH) { | |
2671 | /* no system exclusive message supported yet */ | |
2672 | return 0; | |
2673 | } else if (format != AWE_PATCH) { | |
2674 | printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format); | |
2675 | return -EINVAL; | |
2676 | } | |
2677 | ||
2678 | if (count < AWE_PATCH_INFO_SIZE) { | |
2679 | printk(KERN_WARNING "AWE32 Error: Patch header too short\n"); | |
2680 | return -EINVAL; | |
2681 | } | |
2682 | if (copy_from_user(((char*)&patch) + offs, addr + offs, | |
2683 | AWE_PATCH_INFO_SIZE - offs)) | |
2684 | return -EFAULT; | |
2685 | ||
2686 | count -= AWE_PATCH_INFO_SIZE; | |
2687 | if (count < patch.len) { | |
2688 | printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n", | |
2689 | count, patch.len); | |
2690 | return -EINVAL; | |
2691 | } | |
2692 | ||
2693 | switch (patch.type) { | |
2694 | case AWE_LOAD_INFO: | |
2695 | rc = awe_load_info(&patch, addr, count); | |
2696 | break; | |
2697 | case AWE_LOAD_DATA: | |
2698 | rc = awe_load_data(&patch, addr, count); | |
2699 | break; | |
2700 | case AWE_OPEN_PATCH: | |
2701 | rc = awe_open_patch(&patch, addr, count); | |
2702 | break; | |
2703 | case AWE_CLOSE_PATCH: | |
2704 | rc = awe_close_patch(&patch, addr, count); | |
2705 | break; | |
2706 | case AWE_UNLOAD_PATCH: | |
2707 | rc = awe_unload_patch(&patch, addr, count); | |
2708 | break; | |
2709 | case AWE_REPLACE_DATA: | |
2710 | rc = awe_replace_data(&patch, addr, count); | |
2711 | break; | |
2712 | case AWE_MAP_PRESET: | |
2713 | rc = awe_load_map(&patch, addr, count); | |
2714 | break; | |
2715 | /* case AWE_PROBE_INFO: | |
2716 | rc = awe_probe_info(&patch, addr, count); | |
2717 | break;*/ | |
2718 | case AWE_PROBE_DATA: | |
2719 | rc = awe_probe_data(&patch, addr, count); | |
2720 | break; | |
2721 | case AWE_REMOVE_INFO: | |
2722 | rc = awe_remove_info(&patch, addr, count); | |
2723 | break; | |
2724 | case AWE_LOAD_CHORUS_FX: | |
2725 | rc = awe_load_chorus_fx(&patch, addr, count); | |
2726 | break; | |
2727 | case AWE_LOAD_REVERB_FX: | |
2728 | rc = awe_load_reverb_fx(&patch, addr, count); | |
2729 | break; | |
2730 | ||
2731 | default: | |
2732 | printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n", | |
2733 | patch.type); | |
2734 | rc = -EINVAL; | |
2735 | } | |
2736 | ||
2737 | return rc; | |
2738 | } | |
2739 | ||
2740 | ||
2741 | /* create an sf list record */ | |
2742 | static int | |
2743 | awe_create_sf(int type, char *name) | |
2744 | { | |
2745 | sf_list *rec; | |
2746 | ||
2747 | /* terminate sounds */ | |
2748 | awe_reset(0); | |
2749 | rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL); | |
2750 | if (rec == NULL) | |
2751 | return 1; /* no memory */ | |
2752 | rec->sf_id = current_sf_id + 1; | |
2753 | rec->type = type; | |
2754 | if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0) | |
2755 | locked_sf_id = current_sf_id + 1; | |
2756 | rec->num_info = awe_free_info(); | |
2757 | rec->num_sample = awe_free_sample(); | |
2758 | rec->mem_ptr = awe_free_mem_ptr(); | |
2759 | rec->infos = rec->last_infos = NULL; | |
2760 | rec->samples = rec->last_samples = NULL; | |
2761 | ||
2762 | /* add to linked-list */ | |
2763 | rec->next = NULL; | |
2764 | rec->prev = sftail; | |
2765 | if (sftail) | |
2766 | sftail->next = rec; | |
2767 | else | |
2768 | sfhead = rec; | |
2769 | sftail = rec; | |
2770 | current_sf_id++; | |
2771 | ||
2772 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
2773 | rec->shared = NULL; | |
2774 | if (name) | |
2775 | memcpy(rec->name, name, AWE_PATCH_NAME_LEN); | |
2776 | else | |
2777 | strcpy(rec->name, "*TEMPORARY*"); | |
2778 | if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) { | |
2779 | /* is the current font really a shared font? */ | |
2780 | if (is_shared_sf(rec->name)) { | |
2781 | /* check if the shared font is already installed */ | |
2782 | sf_list *p; | |
2783 | for (p = rec->prev; p; p = p->prev) { | |
2784 | if (is_identical_name(rec->name, p)) { | |
2785 | rec->shared = p; | |
2786 | break; | |
2787 | } | |
2788 | } | |
2789 | } | |
2790 | } | |
2791 | #endif /* allow sharing */ | |
2792 | ||
2793 | return 0; | |
2794 | } | |
2795 | ||
2796 | ||
2797 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
2798 | ||
2799 | /* check if the given name is a valid shared name */ | |
2800 | #define ASC_TO_KEY(c) ((c) - 'A' + 1) | |
2801 | static int is_shared_sf(unsigned char *name) | |
2802 | { | |
2803 | static unsigned char id_head[4] = { | |
2804 | ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'), | |
2805 | AWE_MAJOR_VERSION, | |
2806 | }; | |
2807 | if (memcmp(name, id_head, 4) == 0) | |
2808 | return TRUE; | |
2809 | return FALSE; | |
2810 | } | |
2811 | ||
2812 | /* check if the given name matches to the existing list */ | |
2813 | static int is_identical_name(unsigned char *name, sf_list *p) | |
2814 | { | |
2815 | char *id = p->name; | |
2816 | if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0) | |
2817 | return TRUE; | |
2818 | return FALSE; | |
2819 | } | |
2820 | ||
2821 | /* check if the given voice info exists */ | |
2822 | static int info_duplicated(sf_list *sf, awe_voice_list *rec) | |
2823 | { | |
2824 | /* search for all sharing lists */ | |
2825 | for (; sf; sf = sf->shared) { | |
2826 | awe_voice_list *p; | |
2827 | for (p = sf->infos; p; p = p->next) { | |
2828 | if (p->type == V_ST_NORMAL && | |
2829 | p->bank == rec->bank && | |
2830 | p->instr == rec->instr && | |
2831 | p->v.low == rec->v.low && | |
2832 | p->v.high == rec->v.high && | |
2833 | p->v.sample == rec->v.sample) | |
2834 | return TRUE; | |
2835 | } | |
2836 | } | |
2837 | return FALSE; | |
2838 | } | |
2839 | ||
2840 | #endif /* AWE_ALLOW_SAMPLE_SHARING */ | |
2841 | ||
2842 | ||
2843 | /* free sf_list record */ | |
2844 | /* linked-list in this function is not cared */ | |
2845 | static void | |
2846 | awe_free_sf(sf_list *sf) | |
2847 | { | |
2848 | if (sf->infos) { | |
2849 | awe_voice_list *p, *next; | |
2850 | for (p = sf->infos; p; p = next) { | |
2851 | next = p->next; | |
2852 | kfree(p); | |
2853 | } | |
2854 | } | |
2855 | if (sf->samples) { | |
2856 | awe_sample_list *p, *next; | |
2857 | for (p = sf->samples; p; p = next) { | |
2858 | next = p->next; | |
2859 | kfree(p); | |
2860 | } | |
2861 | } | |
2862 | kfree(sf); | |
2863 | } | |
2864 | ||
2865 | ||
2866 | /* open patch; create sf list and set opened flag */ | |
2867 | static int | |
2868 | awe_open_patch(awe_patch_info *patch, const char __user *addr, int count) | |
2869 | { | |
2870 | awe_open_parm parm; | |
2871 | int shared; | |
2872 | ||
2873 | if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm))) | |
2874 | return -EFAULT; | |
2875 | shared = FALSE; | |
2876 | ||
2877 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
2878 | if (sftail && (parm.type & AWE_PAT_SHARED) != 0) { | |
2879 | /* is the previous font the same font? */ | |
2880 | if (is_identical_name(parm.name, sftail)) { | |
2881 | /* then append to the previous */ | |
2882 | shared = TRUE; | |
2883 | awe_reset(0); | |
2884 | if (parm.type & AWE_PAT_LOCKED) | |
2885 | locked_sf_id = current_sf_id; | |
2886 | } | |
2887 | } | |
2888 | #endif /* allow sharing */ | |
2889 | if (! shared) { | |
2890 | if (awe_create_sf(parm.type, parm.name)) { | |
2891 | printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n"); | |
2892 | return -ENOMEM; | |
2893 | } | |
2894 | } | |
2895 | patch_opened = TRUE; | |
2896 | return current_sf_id; | |
2897 | } | |
2898 | ||
2899 | /* check if the patch is already opened */ | |
2900 | static sf_list * | |
2901 | check_patch_opened(int type, char *name) | |
2902 | { | |
2903 | if (! patch_opened) { | |
2904 | if (awe_create_sf(type, name)) { | |
2905 | printk(KERN_ERR "AWE32: failed to alloc new list\n"); | |
2906 | return NULL; | |
2907 | } | |
2908 | patch_opened = TRUE; | |
2909 | return sftail; | |
2910 | } | |
2911 | return sftail; | |
2912 | } | |
2913 | ||
2914 | /* close the patch; if no voice is loaded, remove the patch */ | |
2915 | static int | |
2916 | awe_close_patch(awe_patch_info *patch, const char __user *addr, int count) | |
2917 | { | |
2918 | if (patch_opened && sftail) { | |
2919 | /* if no voice is loaded, release the current patch */ | |
2920 | if (sftail->infos == NULL) { | |
2921 | awe_reset(0); | |
2922 | awe_remove_samples(current_sf_id - 1); | |
2923 | } | |
2924 | } | |
2925 | patch_opened = 0; | |
2926 | return 0; | |
2927 | } | |
2928 | ||
2929 | ||
2930 | /* remove the latest patch */ | |
2931 | static int | |
2932 | awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count) | |
2933 | { | |
2934 | if (current_sf_id > 0 && current_sf_id > locked_sf_id) { | |
2935 | awe_reset(0); | |
2936 | awe_remove_samples(current_sf_id - 1); | |
2937 | } | |
2938 | return 0; | |
2939 | } | |
2940 | ||
2941 | /* allocate voice info list records */ | |
2942 | static awe_voice_list * | |
2943 | alloc_new_info(void) | |
2944 | { | |
2945 | awe_voice_list *newlist; | |
2946 | ||
2947 | newlist = (awe_voice_list *)kmalloc(sizeof(*newlist), GFP_KERNEL); | |
2948 | if (newlist == NULL) { | |
2949 | printk(KERN_ERR "AWE32: can't alloc info table\n"); | |
2950 | return NULL; | |
2951 | } | |
2952 | return newlist; | |
2953 | } | |
2954 | ||
2955 | /* allocate sample info list records */ | |
2956 | static awe_sample_list * | |
2957 | alloc_new_sample(void) | |
2958 | { | |
2959 | awe_sample_list *newlist; | |
2960 | ||
2961 | newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL); | |
2962 | if (newlist == NULL) { | |
2963 | printk(KERN_ERR "AWE32: can't alloc sample table\n"); | |
2964 | return NULL; | |
2965 | } | |
2966 | return newlist; | |
2967 | } | |
2968 | ||
2969 | /* load voice map */ | |
2970 | static int | |
2971 | awe_load_map(awe_patch_info *patch, const char __user *addr, int count) | |
2972 | { | |
2973 | awe_voice_map map; | |
2974 | awe_voice_list *rec, *p; | |
2975 | sf_list *sf; | |
2976 | ||
2977 | /* get the link info */ | |
2978 | if (count < sizeof(map)) { | |
2979 | printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); | |
2980 | return -EINVAL; | |
2981 | } | |
2982 | if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map))) | |
2983 | return -EFAULT; | |
2984 | ||
2985 | /* check if the identical mapping already exists */ | |
2986 | p = awe_search_instr(map.map_bank, map.map_instr, map.map_key); | |
2987 | for (; p; p = p->next_instr) { | |
2988 | if (p->type == V_ST_MAPPED && | |
2989 | p->v.start == map.src_instr && | |
2990 | p->v.end == map.src_bank && | |
2991 | p->v.fixkey == map.src_key) | |
2992 | return 0; /* already present! */ | |
2993 | } | |
2994 | ||
2995 | if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL) | |
2996 | return -ENOMEM; | |
2997 | ||
2998 | if ((rec = alloc_new_info()) == NULL) | |
2999 | return -ENOMEM; | |
3000 | ||
3001 | rec->bank = map.map_bank; | |
3002 | rec->instr = map.map_instr; | |
3003 | rec->type = V_ST_MAPPED; | |
3004 | rec->disabled = FALSE; | |
3005 | awe_init_voice_info(&rec->v); | |
3006 | if (map.map_key >= 0) { | |
3007 | rec->v.low = map.map_key; | |
3008 | rec->v.high = map.map_key; | |
3009 | } | |
3010 | rec->v.start = map.src_instr; | |
3011 | rec->v.end = map.src_bank; | |
3012 | rec->v.fixkey = map.src_key; | |
3013 | add_sf_info(sf, rec); | |
3014 | add_info_list(rec); | |
3015 | ||
3016 | return 0; | |
3017 | } | |
3018 | ||
3019 | #if 0 | |
3020 | /* probe preset in the current list -- nothing to be loaded */ | |
3021 | static int | |
3022 | awe_probe_info(awe_patch_info *patch, const char __user *addr, int count) | |
3023 | { | |
3024 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
3025 | awe_voice_map map; | |
3026 | awe_voice_list *p; | |
3027 | ||
3028 | if (! patch_opened) | |
3029 | return -EINVAL; | |
3030 | ||
3031 | /* get the link info */ | |
3032 | if (count < sizeof(map)) { | |
3033 | printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); | |
3034 | return -EINVAL; | |
3035 | } | |
3036 | if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map))) | |
3037 | return -EFAULT; | |
3038 | ||
3039 | /* check if the identical mapping already exists */ | |
3040 | if (sftail == NULL) | |
3041 | return -EINVAL; | |
3042 | p = awe_search_instr(map.src_bank, map.src_instr, map.src_key); | |
3043 | for (; p; p = p->next_instr) { | |
3044 | if (p->type == V_ST_NORMAL && | |
3045 | is_identical_holder(p->holder, sftail) && | |
3046 | p->v.low <= map.src_key && | |
3047 | p->v.high >= map.src_key) | |
3048 | return 0; /* already present! */ | |
3049 | } | |
3050 | #endif /* allow sharing */ | |
3051 | return -EINVAL; | |
3052 | } | |
3053 | #endif | |
3054 | ||
3055 | /* probe sample in the current list -- nothing to be loaded */ | |
3056 | static int | |
3057 | awe_probe_data(awe_patch_info *patch, const char __user *addr, int count) | |
3058 | { | |
3059 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
3060 | if (! patch_opened) | |
3061 | return -EINVAL; | |
3062 | ||
3063 | /* search the specified sample by optarg */ | |
3064 | if (search_sample_index(sftail, patch->optarg) != NULL) | |
3065 | return 0; | |
3066 | #endif /* allow sharing */ | |
3067 | return -EINVAL; | |
3068 | } | |
3069 | ||
3070 | ||
3071 | /* remove the present instrument layers */ | |
3072 | static int | |
3073 | remove_info(sf_list *sf, int bank, int instr) | |
3074 | { | |
3075 | awe_voice_list *prev, *next, *p; | |
3076 | int removed = 0; | |
3077 | ||
3078 | prev = NULL; | |
3079 | for (p = sf->infos; p; p = next) { | |
3080 | next = p->next; | |
3081 | if (p->type == V_ST_NORMAL && | |
3082 | p->bank == bank && p->instr == instr) { | |
3083 | /* remove this layer */ | |
3084 | if (prev) | |
3085 | prev->next = next; | |
3086 | else | |
3087 | sf->infos = next; | |
3088 | if (p == sf->last_infos) | |
3089 | sf->last_infos = prev; | |
3090 | sf->num_info--; | |
3091 | removed++; | |
3092 | kfree(p); | |
3093 | } else | |
3094 | prev = p; | |
3095 | } | |
3096 | if (removed) | |
3097 | rebuild_preset_list(); | |
3098 | return removed; | |
3099 | } | |
3100 | ||
3101 | /* load voice information data */ | |
3102 | static int | |
3103 | awe_load_info(awe_patch_info *patch, const char __user *addr, int count) | |
3104 | { | |
3105 | int offset; | |
3106 | awe_voice_rec_hdr hdr; | |
3107 | int i; | |
3108 | int total_size; | |
3109 | sf_list *sf; | |
3110 | awe_voice_list *rec; | |
3111 | ||
3112 | if (count < AWE_VOICE_REC_SIZE) { | |
3113 | printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); | |
3114 | return -EINVAL; | |
3115 | } | |
3116 | ||
3117 | offset = AWE_PATCH_INFO_SIZE; | |
3118 | if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE)) | |
3119 | return -EFAULT; | |
3120 | offset += AWE_VOICE_REC_SIZE; | |
3121 | ||
3122 | if (hdr.nvoices <= 0 || hdr.nvoices >= 100) { | |
3123 | printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices); | |
3124 | return -EINVAL; | |
3125 | } | |
3126 | total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices; | |
3127 | if (count < total_size) { | |
3128 | printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n", | |
3129 | count, hdr.nvoices); | |
3130 | return -EINVAL; | |
3131 | } | |
3132 | ||
3133 | if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL) | |
3134 | return -ENOMEM; | |
3135 | ||
3136 | switch (hdr.write_mode) { | |
3137 | case AWE_WR_EXCLUSIVE: | |
3138 | /* exclusive mode - if the instrument already exists, | |
3139 | return error */ | |
3140 | for (rec = sf->infos; rec; rec = rec->next) { | |
3141 | if (rec->type == V_ST_NORMAL && | |
3142 | rec->bank == hdr.bank && | |
3143 | rec->instr == hdr.instr) | |
3144 | return -EINVAL; | |
3145 | } | |
3146 | break; | |
3147 | case AWE_WR_REPLACE: | |
3148 | /* replace mode - remove the instrument if it already exists */ | |
3149 | remove_info(sf, hdr.bank, hdr.instr); | |
3150 | break; | |
3151 | } | |
3152 | ||
3153 | /* append new layers */ | |
3154 | for (i = 0; i < hdr.nvoices; i++) { | |
3155 | rec = alloc_new_info(); | |
3156 | if (rec == NULL) | |
3157 | return -ENOMEM; | |
3158 | ||
3159 | rec->bank = hdr.bank; | |
3160 | rec->instr = hdr.instr; | |
3161 | rec->type = V_ST_NORMAL; | |
3162 | rec->disabled = FALSE; | |
3163 | ||
3164 | /* copy awe_voice_info parameters */ | |
3165 | if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) { | |
3166 | kfree(rec); | |
3167 | return -EFAULT; | |
3168 | } | |
3169 | offset += AWE_VOICE_INFO_SIZE; | |
3170 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
3171 | if (sf && sf->shared) { | |
3172 | if (info_duplicated(sf, rec)) { | |
3173 | kfree(rec); | |
3174 | continue; | |
3175 | } | |
3176 | } | |
3177 | #endif /* allow sharing */ | |
3178 | if (rec->v.mode & AWE_MODE_INIT_PARM) | |
3179 | awe_init_voice_parm(&rec->v.parm); | |
3180 | add_sf_info(sf, rec); | |
3181 | awe_set_sample(rec); | |
3182 | add_info_list(rec); | |
3183 | } | |
3184 | ||
3185 | return 0; | |
3186 | } | |
3187 | ||
3188 | ||
3189 | /* remove instrument layers */ | |
3190 | static int | |
3191 | awe_remove_info(awe_patch_info *patch, const char __user *addr, int count) | |
3192 | { | |
3193 | unsigned char bank, instr; | |
3194 | sf_list *sf; | |
3195 | ||
3196 | if (! patch_opened || (sf = sftail) == NULL) { | |
3197 | printk(KERN_WARNING "AWE32: remove_info: patch not opened\n"); | |
3198 | return -EINVAL; | |
3199 | } | |
3200 | ||
3201 | bank = ((unsigned short)patch->optarg >> 8) & 0xff; | |
3202 | instr = (unsigned short)patch->optarg & 0xff; | |
3203 | if (! remove_info(sf, bank, instr)) | |
3204 | return -EINVAL; | |
3205 | return 0; | |
3206 | } | |
3207 | ||
3208 | ||
3209 | /* load wave sample data */ | |
3210 | static int | |
3211 | awe_load_data(awe_patch_info *patch, const char __user *addr, int count) | |
3212 | { | |
3213 | int offset, size; | |
3214 | int rc; | |
3215 | awe_sample_info tmprec; | |
3216 | awe_sample_list *rec; | |
3217 | sf_list *sf; | |
3218 | ||
3219 | if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL) | |
3220 | return -ENOMEM; | |
3221 | ||
3222 | size = (count - AWE_SAMPLE_INFO_SIZE) / 2; | |
3223 | offset = AWE_PATCH_INFO_SIZE; | |
3224 | if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE)) | |
3225 | return -EFAULT; | |
3226 | offset += AWE_SAMPLE_INFO_SIZE; | |
3227 | if (size != tmprec.size) { | |
3228 | printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n", | |
3229 | tmprec.size, size); | |
3230 | return -EINVAL; | |
3231 | } | |
3232 | ||
3233 | if (search_sample_index(sf, tmprec.sample) != NULL) { | |
3234 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
3235 | /* if shared sample, skip this data */ | |
3236 | if (sf->type & AWE_PAT_SHARED) | |
3237 | return 0; | |
3238 | #endif /* allow sharing */ | |
3239 | DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample)); | |
3240 | return -EINVAL; | |
3241 | } | |
3242 | ||
3243 | if ((rec = alloc_new_sample()) == NULL) | |
3244 | return -ENOMEM; | |
3245 | ||
3246 | memcpy(&rec->v, &tmprec, sizeof(tmprec)); | |
3247 | ||
3248 | if (rec->v.size > 0) { | |
3249 | if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) { | |
3250 | kfree(rec); | |
3251 | return rc; | |
3252 | } | |
3253 | sf->mem_ptr += rc; | |
3254 | } | |
3255 | ||
3256 | add_sf_sample(sf, rec); | |
3257 | return 0; | |
3258 | } | |
3259 | ||
3260 | ||
3261 | /* replace wave sample data */ | |
3262 | static int | |
3263 | awe_replace_data(awe_patch_info *patch, const char __user *addr, int count) | |
3264 | { | |
3265 | int offset; | |
3266 | int size; | |
3267 | int rc; | |
3268 | int channels; | |
3269 | awe_sample_info cursmp; | |
3270 | int save_mem_ptr; | |
3271 | sf_list *sf; | |
3272 | awe_sample_list *rec; | |
3273 | ||
3274 | if (! patch_opened || (sf = sftail) == NULL) { | |
3275 | printk(KERN_WARNING "AWE32: replace: patch not opened\n"); | |
3276 | return -EINVAL; | |
3277 | } | |
3278 | ||
3279 | size = (count - AWE_SAMPLE_INFO_SIZE) / 2; | |
3280 | offset = AWE_PATCH_INFO_SIZE; | |
3281 | if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE)) | |
3282 | return -EFAULT; | |
3283 | offset += AWE_SAMPLE_INFO_SIZE; | |
3284 | if (cursmp.size == 0 || size != cursmp.size) { | |
3285 | printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n", | |
3286 | cursmp.size, size); | |
3287 | return -EINVAL; | |
3288 | } | |
3289 | channels = patch->optarg; | |
3290 | if (channels <= 0 || channels > AWE_NORMAL_VOICES) { | |
3291 | printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels); | |
3292 | return -EINVAL; | |
3293 | } | |
3294 | ||
3295 | for (rec = sf->samples; rec; rec = rec->next) { | |
3296 | if (rec->v.sample == cursmp.sample) | |
3297 | break; | |
3298 | } | |
3299 | if (rec == NULL) { | |
3300 | printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n", | |
3301 | cursmp.sample); | |
3302 | return -EINVAL; | |
3303 | } | |
3304 | ||
3305 | if (rec->v.size != cursmp.size) { | |
3306 | printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n", | |
3307 | rec->v.size, cursmp.size); | |
3308 | return -EINVAL; | |
3309 | } | |
3310 | ||
3311 | save_mem_ptr = awe_free_mem_ptr(); | |
3312 | sftail->mem_ptr = rec->v.start - awe_mem_start; | |
3313 | memcpy(&rec->v, &cursmp, sizeof(cursmp)); | |
3314 | rec->v.sf_id = current_sf_id; | |
3315 | if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0) | |
3316 | return rc; | |
3317 | sftail->mem_ptr = save_mem_ptr; | |
3318 | ||
3319 | return 0; | |
3320 | } | |
3321 | ||
3322 | ||
3323 | /*----------------------------------------------------------------*/ | |
3324 | ||
3325 | static const char __user *readbuf_addr; | |
3326 | static int readbuf_offs; | |
3327 | static int readbuf_flags; | |
3328 | ||
3329 | /* initialize read buffer */ | |
3330 | static int | |
3331 | readbuf_init(const char __user *addr, int offset, awe_sample_info *sp) | |
3332 | { | |
3333 | readbuf_addr = addr; | |
3334 | readbuf_offs = offset; | |
3335 | readbuf_flags = sp->mode_flags; | |
3336 | return 0; | |
3337 | } | |
3338 | ||
3339 | /* read directly from user buffer */ | |
3340 | static unsigned short | |
3341 | readbuf_word(int pos) | |
3342 | { | |
3343 | unsigned short c; | |
3344 | /* read from user buffer */ | |
3345 | if (readbuf_flags & AWE_SAMPLE_8BITS) { | |
3346 | unsigned char cc; | |
3347 | get_user(cc, (unsigned char __user *)(readbuf_addr + readbuf_offs + pos)); | |
3348 | c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */ | |
3349 | } else { | |
3350 | get_user(c, (unsigned short __user *)(readbuf_addr + readbuf_offs + pos * 2)); | |
3351 | } | |
3352 | if (readbuf_flags & AWE_SAMPLE_UNSIGNED) | |
3353 | c ^= 0x8000; /* unsigned -> signed */ | |
3354 | return c; | |
3355 | } | |
3356 | ||
3357 | #define readbuf_word_cache readbuf_word | |
3358 | #define readbuf_end() /**/ | |
3359 | ||
3360 | /*----------------------------------------------------------------*/ | |
3361 | ||
3362 | #define BLANK_LOOP_START 8 | |
3363 | #define BLANK_LOOP_END 40 | |
3364 | #define BLANK_LOOP_SIZE 48 | |
3365 | ||
3366 | /* loading onto memory - return the actual written size */ | |
3367 | static int | |
3368 | awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *list, int channels) | |
3369 | { | |
3370 | int i, truesize, dram_offset; | |
3371 | awe_sample_info *sp = &list->v; | |
3372 | int rc; | |
3373 | ||
3374 | /* be sure loop points start < end */ | |
3375 | if (sp->loopstart > sp->loopend) { | |
3376 | int tmp = sp->loopstart; | |
3377 | sp->loopstart = sp->loopend; | |
3378 | sp->loopend = tmp; | |
3379 | } | |
3380 | ||
3381 | /* compute true data size to be loaded */ | |
3382 | truesize = sp->size; | |
3383 | if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) | |
3384 | truesize += sp->loopend - sp->loopstart; | |
3385 | if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) | |
3386 | truesize += BLANK_LOOP_SIZE; | |
3387 | if (awe_free_mem_ptr() + truesize >= memsize/2) { | |
3388 | DEBUG(-1,printk("AWE32 Error: Sample memory full\n")); | |
3389 | return -ENOSPC; | |
3390 | } | |
3391 | ||
3392 | /* recalculate address offset */ | |
3393 | sp->end -= sp->start; | |
3394 | sp->loopstart -= sp->start; | |
3395 | sp->loopend -= sp->start; | |
3396 | ||
3397 | dram_offset = awe_free_mem_ptr() + awe_mem_start; | |
3398 | sp->start = dram_offset; | |
3399 | sp->end += dram_offset; | |
3400 | sp->loopstart += dram_offset; | |
3401 | sp->loopend += dram_offset; | |
3402 | ||
3403 | /* set the total size (store onto obsolete checksum value) */ | |
3404 | if (sp->size == 0) | |
3405 | sp->checksum = 0; | |
3406 | else | |
3407 | sp->checksum = truesize; | |
3408 | ||
3409 | if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0) | |
3410 | return rc; | |
3411 | ||
3412 | if (readbuf_init(addr, offset, sp) < 0) | |
3413 | return -ENOSPC; | |
3414 | ||
3415 | for (i = 0; i < sp->size; i++) { | |
3416 | unsigned short c; | |
3417 | c = readbuf_word(i); | |
3418 | awe_write_dram(c); | |
3419 | if (i == sp->loopend && | |
3420 | (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) { | |
3421 | int looplen = sp->loopend - sp->loopstart; | |
3422 | /* copy reverse loop */ | |
3423 | int k; | |
3424 | for (k = 1; k <= looplen; k++) { | |
3425 | c = readbuf_word_cache(i - k); | |
3426 | awe_write_dram(c); | |
3427 | } | |
3428 | if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) { | |
3429 | sp->end += looplen; | |
3430 | } else { | |
3431 | sp->start += looplen; | |
3432 | sp->end += looplen; | |
3433 | } | |
3434 | } | |
3435 | } | |
3436 | readbuf_end(); | |
3437 | ||
3438 | /* if no blank loop is attached in the sample, add it */ | |
3439 | if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) { | |
3440 | for (i = 0; i < BLANK_LOOP_SIZE; i++) | |
3441 | awe_write_dram(0); | |
3442 | if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) { | |
3443 | sp->loopstart = sp->end + BLANK_LOOP_START; | |
3444 | sp->loopend = sp->end + BLANK_LOOP_END; | |
3445 | } | |
3446 | } | |
3447 | ||
3448 | awe_close_dram(); | |
3449 | ||
3450 | /* initialize FM */ | |
3451 | awe_init_fm(); | |
3452 | ||
3453 | return truesize; | |
3454 | } | |
3455 | ||
3456 | ||
3457 | /*----------------------------------------------------------------*/ | |
3458 | ||
3459 | #ifdef AWE_HAS_GUS_COMPATIBILITY | |
3460 | ||
3461 | /* calculate GUS envelope time: | |
3462 | * is this correct? i have no idea.. | |
3463 | */ | |
3464 | static int | |
3465 | calc_gus_envelope_time(int rate, int start, int end) | |
3466 | { | |
3467 | int r, p, t; | |
3468 | r = (3 - ((rate >> 6) & 3)) * 3; | |
3469 | p = rate & 0x3f; | |
3470 | t = end - start; | |
3471 | if (t < 0) t = -t; | |
3472 | if (13 > r) | |
3473 | t = t << (13 - r); | |
3474 | else | |
3475 | t = t >> (r - 13); | |
3476 | return (t * 10) / (p * 441); | |
3477 | } | |
3478 | ||
3479 | #define calc_gus_sustain(val) (0x7f - vol_table[(val)/2]) | |
3480 | #define calc_gus_attenuation(val) vol_table[(val)/2] | |
3481 | ||
3482 | /* load GUS patch */ | |
3483 | static int | |
3484 | awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag) | |
3485 | { | |
3486 | struct patch_info patch; | |
3487 | awe_voice_info *rec; | |
3488 | awe_sample_info *smp; | |
3489 | awe_voice_list *vrec; | |
3490 | awe_sample_list *smprec; | |
3491 | int sizeof_patch; | |
3492 | int note, rc; | |
3493 | sf_list *sf; | |
3494 | ||
3495 | sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */ | |
3496 | if (size < sizeof_patch) { | |
3497 | printk(KERN_WARNING "AWE32 Error: Patch header too short\n"); | |
3498 | return -EINVAL; | |
3499 | } | |
3500 | if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs)) | |
3501 | return -EFAULT; | |
3502 | size -= sizeof_patch; | |
3503 | if (size < patch.len) { | |
3504 | printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n", | |
3505 | size, patch.len); | |
3506 | return -EINVAL; | |
3507 | } | |
3508 | if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL) | |
3509 | return -ENOMEM; | |
3510 | if ((smprec = alloc_new_sample()) == NULL) | |
3511 | return -ENOMEM; | |
3512 | if ((vrec = alloc_new_info()) == NULL) { | |
3513 | kfree(smprec); | |
3514 | return -ENOMEM; | |
3515 | } | |
3516 | ||
3517 | smp = &smprec->v; | |
3518 | smp->sample = sf->num_sample; | |
3519 | smp->start = 0; | |
3520 | smp->end = patch.len; | |
3521 | smp->loopstart = patch.loop_start; | |
3522 | smp->loopend = patch.loop_end; | |
3523 | smp->size = patch.len; | |
3524 | ||
3525 | /* set up mode flags */ | |
3526 | smp->mode_flags = 0; | |
3527 | if (!(patch.mode & WAVE_16_BITS)) | |
3528 | smp->mode_flags |= AWE_SAMPLE_8BITS; | |
3529 | if (patch.mode & WAVE_UNSIGNED) | |
3530 | smp->mode_flags |= AWE_SAMPLE_UNSIGNED; | |
3531 | smp->mode_flags |= AWE_SAMPLE_NO_BLANK; | |
3532 | if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK))) | |
3533 | smp->mode_flags |= AWE_SAMPLE_SINGLESHOT; | |
3534 | if (patch.mode & WAVE_BIDIR_LOOP) | |
3535 | smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP; | |
3536 | if (patch.mode & WAVE_LOOP_BACK) | |
3537 | smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP; | |
3538 | ||
3539 | DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags)); | |
3540 | if (patch.mode & WAVE_16_BITS) { | |
3541 | /* convert to word offsets */ | |
3542 | smp->size /= 2; | |
3543 | smp->end /= 2; | |
3544 | smp->loopstart /= 2; | |
3545 | smp->loopend /= 2; | |
3546 | } | |
3547 | smp->checksum_flag = 0; | |
3548 | smp->checksum = 0; | |
3549 | ||
3550 | if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) | |
3551 | return rc; | |
3552 | sf->mem_ptr += rc; | |
3553 | add_sf_sample(sf, smprec); | |
3554 | ||
3555 | /* set up voice info */ | |
3556 | rec = &vrec->v; | |
3557 | awe_init_voice_info(rec); | |
3558 | rec->sample = sf->num_info; /* the last sample */ | |
3559 | rec->rate_offset = calc_rate_offset(patch.base_freq); | |
3560 | note = freq_to_note(patch.base_note); | |
3561 | rec->root = note / 100; | |
3562 | rec->tune = -(note % 100); | |
3563 | rec->low = freq_to_note(patch.low_note) / 100; | |
3564 | rec->high = freq_to_note(patch.high_note) / 100; | |
3565 | DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n", | |
3566 | rec->rate_offset, note, | |
3567 | rec->low, rec->high, | |
3568 | patch.low_note, patch.high_note)); | |
3569 | /* panning position; -128 - 127 => 0-127 */ | |
3570 | rec->pan = (patch.panning + 128) / 2; | |
3571 | ||
3572 | /* detuning is ignored */ | |
3573 | /* 6points volume envelope */ | |
3574 | if (patch.mode & WAVE_ENVELOPES) { | |
3575 | int attack, hold, decay, release; | |
3576 | attack = calc_gus_envelope_time | |
3577 | (patch.env_rate[0], 0, patch.env_offset[0]); | |
3578 | hold = calc_gus_envelope_time | |
3579 | (patch.env_rate[1], patch.env_offset[0], | |
3580 | patch.env_offset[1]); | |
3581 | decay = calc_gus_envelope_time | |
3582 | (patch.env_rate[2], patch.env_offset[1], | |
3583 | patch.env_offset[2]); | |
3584 | release = calc_gus_envelope_time | |
3585 | (patch.env_rate[3], patch.env_offset[1], | |
3586 | patch.env_offset[4]); | |
3587 | release += calc_gus_envelope_time | |
3588 | (patch.env_rate[4], patch.env_offset[3], | |
3589 | patch.env_offset[4]); | |
3590 | release += calc_gus_envelope_time | |
3591 | (patch.env_rate[5], patch.env_offset[4], | |
3592 | patch.env_offset[5]); | |
3593 | rec->parm.volatkhld = (calc_parm_hold(hold) << 8) | | |
3594 | calc_parm_attack(attack); | |
3595 | rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) | | |
3596 | calc_parm_decay(decay); | |
3597 | rec->parm.volrelease = 0x8000 | calc_parm_decay(release); | |
3598 | DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release)); | |
3599 | rec->attenuation = calc_gus_attenuation(patch.env_offset[0]); | |
3600 | } | |
3601 | ||
3602 | /* tremolo effect */ | |
3603 | if (patch.mode & WAVE_TREMOLO) { | |
3604 | int rate = (patch.tremolo_rate * 1000 / 38) / 42; | |
3605 | rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate; | |
3606 | DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n", | |
3607 | patch.tremolo_rate, patch.tremolo_depth, | |
3608 | rec->parm.tremfrq)); | |
3609 | } | |
3610 | /* vibrato effect */ | |
3611 | if (patch.mode & WAVE_VIBRATO) { | |
3612 | int rate = (patch.vibrato_rate * 1000 / 38) / 42; | |
3613 | rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate; | |
3614 | DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n", | |
3615 | patch.tremolo_rate, patch.tremolo_depth, | |
3616 | rec->parm.tremfrq)); | |
3617 | } | |
3618 | ||
3619 | /* scale_freq, scale_factor, volume, and fractions not implemented */ | |
3620 | ||
3621 | /* append to the tail of the list */ | |
3622 | vrec->bank = ctrls[AWE_MD_GUS_BANK]; | |
3623 | vrec->instr = patch.instr_no; | |
3624 | vrec->disabled = FALSE; | |
3625 | vrec->type = V_ST_NORMAL; | |
3626 | ||
3627 | add_sf_info(sf, vrec); | |
3628 | add_info_list(vrec); | |
3629 | ||
3630 | /* set the voice index */ | |
3631 | awe_set_sample(vrec); | |
3632 | ||
3633 | return 0; | |
3634 | } | |
3635 | ||
3636 | #endif /* AWE_HAS_GUS_COMPATIBILITY */ | |
3637 | ||
3638 | /* | |
3639 | * sample and voice list handlers | |
3640 | */ | |
3641 | ||
3642 | /* append this to the current sf list */ | |
3643 | static void add_sf_info(sf_list *sf, awe_voice_list *rec) | |
3644 | { | |
3645 | if (sf == NULL) | |
3646 | return; | |
3647 | rec->holder = sf; | |
3648 | rec->v.sf_id = sf->sf_id; | |
3649 | if (sf->last_infos) | |
3650 | sf->last_infos->next = rec; | |
3651 | else | |
3652 | sf->infos = rec; | |
3653 | sf->last_infos = rec; | |
3654 | rec->next = NULL; | |
3655 | sf->num_info++; | |
3656 | } | |
3657 | ||
3658 | /* prepend this sample to sf list */ | |
3659 | static void add_sf_sample(sf_list *sf, awe_sample_list *rec) | |
3660 | { | |
3661 | if (sf == NULL) | |
3662 | return; | |
3663 | rec->holder = sf; | |
3664 | rec->v.sf_id = sf->sf_id; | |
3665 | if (sf->last_samples) | |
3666 | sf->last_samples->next = rec; | |
3667 | else | |
3668 | sf->samples = rec; | |
3669 | sf->last_samples = rec; | |
3670 | rec->next = NULL; | |
3671 | sf->num_sample++; | |
3672 | } | |
3673 | ||
3674 | /* purge the old records which don't belong with the same file id */ | |
3675 | static void purge_old_list(awe_voice_list *rec, awe_voice_list *next) | |
3676 | { | |
3677 | rec->next_instr = next; | |
3678 | if (rec->bank == AWE_DRUM_BANK) { | |
3679 | /* remove samples with the same note range */ | |
3680 | awe_voice_list *cur, *prev = rec; | |
3681 | int low = rec->v.low; | |
3682 | int high = rec->v.high; | |
3683 | for (cur = next; cur; cur = cur->next_instr) { | |
3684 | if (cur->v.low == low && | |
3685 | cur->v.high == high && | |
3686 | ! is_identical_holder(cur->holder, rec->holder)) | |
3687 | prev->next_instr = cur->next_instr; | |
3688 | else | |
3689 | prev = cur; | |
3690 | } | |
3691 | } else { | |
3692 | if (! is_identical_holder(next->holder, rec->holder)) | |
3693 | /* remove all samples */ | |
3694 | rec->next_instr = NULL; | |
3695 | } | |
3696 | } | |
3697 | ||
3698 | /* prepend to top of the preset table */ | |
3699 | static void add_info_list(awe_voice_list *rec) | |
3700 | { | |
3701 | awe_voice_list *prev, *cur; | |
3702 | int key; | |
3703 | ||
3704 | if (rec->disabled) | |
3705 | return; | |
3706 | ||
3707 | key = awe_search_key(rec->bank, rec->instr, rec->v.low); | |
3708 | prev = NULL; | |
3709 | for (cur = preset_table[key]; cur; cur = cur->next_bank) { | |
3710 | /* search the first record with the same bank number */ | |
3711 | if (cur->instr == rec->instr && cur->bank == rec->bank) { | |
3712 | /* replace the list with the new record */ | |
3713 | rec->next_bank = cur->next_bank; | |
3714 | if (prev) | |
3715 | prev->next_bank = rec; | |
3716 | else | |
3717 | preset_table[key] = rec; | |
3718 | purge_old_list(rec, cur); | |
3719 | return; | |
3720 | } | |
3721 | prev = cur; | |
3722 | } | |
3723 | ||
3724 | /* this is the first bank record.. just add this */ | |
3725 | rec->next_instr = NULL; | |
3726 | rec->next_bank = preset_table[key]; | |
3727 | preset_table[key] = rec; | |
3728 | } | |
3729 | ||
3730 | /* remove samples later than the specified sf_id */ | |
3731 | static void | |
3732 | awe_remove_samples(int sf_id) | |
3733 | { | |
3734 | sf_list *p, *prev; | |
3735 | ||
3736 | if (sf_id <= 0) { | |
3737 | awe_reset_samples(); | |
3738 | return; | |
3739 | } | |
3740 | /* already removed? */ | |
3741 | if (current_sf_id <= sf_id) | |
3742 | return; | |
3743 | ||
3744 | for (p = sftail; p; p = prev) { | |
3745 | if (p->sf_id <= sf_id) | |
3746 | break; | |
3747 | prev = p->prev; | |
3748 | awe_free_sf(p); | |
3749 | } | |
3750 | sftail = p; | |
3751 | if (sftail) { | |
3752 | sf_id = sftail->sf_id; | |
3753 | sftail->next = NULL; | |
3754 | } else { | |
3755 | sf_id = 0; | |
3756 | sfhead = NULL; | |
3757 | } | |
3758 | current_sf_id = sf_id; | |
3759 | if (locked_sf_id > sf_id) | |
3760 | locked_sf_id = sf_id; | |
3761 | ||
3762 | rebuild_preset_list(); | |
3763 | } | |
3764 | ||
3765 | /* rebuild preset search list */ | |
3766 | static void rebuild_preset_list(void) | |
3767 | { | |
3768 | sf_list *p; | |
3769 | awe_voice_list *rec; | |
3770 | ||
3771 | memset(preset_table, 0, sizeof(preset_table)); | |
3772 | ||
3773 | for (p = sfhead; p; p = p->next) { | |
3774 | for (rec = p->infos; rec; rec = rec->next) | |
3775 | add_info_list(rec); | |
3776 | } | |
3777 | } | |
3778 | ||
3779 | /* compare the given sf_id pair */ | |
3780 | static int is_identical_holder(sf_list *sf1, sf_list *sf2) | |
3781 | { | |
3782 | if (sf1 == NULL || sf2 == NULL) | |
3783 | return FALSE; | |
3784 | if (sf1 == sf2) | |
3785 | return TRUE; | |
3786 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
3787 | { | |
3788 | /* compare with the sharing id */ | |
3789 | sf_list *p; | |
3790 | int counter = 0; | |
3791 | if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */ | |
3792 | sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp; | |
3793 | } | |
3794 | for (p = sf1->shared; p; p = p->shared) { | |
3795 | if (counter++ > current_sf_id) | |
3796 | break; /* strange sharing loop.. quit */ | |
3797 | if (p == sf2) | |
3798 | return TRUE; | |
3799 | } | |
3800 | } | |
3801 | #endif /* allow sharing */ | |
3802 | return FALSE; | |
3803 | } | |
3804 | ||
3805 | /* search the sample index matching with the given sample id */ | |
3806 | static awe_sample_list * | |
3807 | search_sample_index(sf_list *sf, int sample) | |
3808 | { | |
3809 | awe_sample_list *p; | |
3810 | #ifdef AWE_ALLOW_SAMPLE_SHARING | |
3811 | int counter = 0; | |
3812 | while (sf) { | |
3813 | for (p = sf->samples; p; p = p->next) { | |
3814 | if (p->v.sample == sample) | |
3815 | return p; | |
3816 | } | |
3817 | sf = sf->shared; | |
3818 | if (counter++ > current_sf_id) | |
3819 | break; /* strange sharing loop.. quit */ | |
3820 | } | |
3821 | #else | |
3822 | if (sf) { | |
3823 | for (p = sf->samples; p; p = p->next) { | |
3824 | if (p->v.sample == sample) | |
3825 | return p; | |
3826 | } | |
3827 | } | |
3828 | #endif | |
3829 | return NULL; | |
3830 | } | |
3831 | ||
3832 | /* search the specified sample */ | |
3833 | /* non-zero = found */ | |
3834 | static short | |
3835 | awe_set_sample(awe_voice_list *rec) | |
3836 | { | |
3837 | awe_sample_list *smp; | |
3838 | awe_voice_info *vp = &rec->v; | |
3839 | ||
3840 | vp->index = 0; | |
3841 | if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL) | |
3842 | return 0; | |
3843 | ||
3844 | /* set the actual sample offsets */ | |
3845 | vp->start += smp->v.start; | |
3846 | vp->end += smp->v.end; | |
3847 | vp->loopstart += smp->v.loopstart; | |
3848 | vp->loopend += smp->v.loopend; | |
3849 | /* copy mode flags */ | |
3850 | vp->mode = smp->v.mode_flags; | |
3851 | /* set flag */ | |
3852 | vp->index = 1; | |
3853 | ||
3854 | return 1; | |
3855 | } | |
3856 | ||
3857 | ||
3858 | /* | |
3859 | * voice allocation | |
3860 | */ | |
3861 | ||
3862 | /* look for all voices associated with the specified note & velocity */ | |
3863 | static int | |
3864 | awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, | |
3865 | awe_voice_info **vlist) | |
3866 | { | |
3867 | int nvoices; | |
3868 | ||
3869 | nvoices = 0; | |
3870 | for (; rec; rec = rec->next_instr) { | |
3871 | if (note >= rec->v.low && | |
3872 | note <= rec->v.high && | |
3873 | velocity >= rec->v.vellow && | |
3874 | velocity <= rec->v.velhigh) { | |
3875 | if (rec->type == V_ST_MAPPED) { | |
3876 | /* mapper */ | |
3877 | vlist[0] = &rec->v; | |
3878 | return -1; | |
3879 | } | |
3880 | vlist[nvoices++] = &rec->v; | |
3881 | if (nvoices >= AWE_MAX_VOICES) | |
3882 | break; | |
3883 | } | |
3884 | } | |
3885 | return nvoices; | |
3886 | } | |
3887 | ||
3888 | /* store the voice list from the specified note and velocity. | |
3889 | if the preset is mapped, seek for the destination preset, and rewrite | |
3890 | the note number if necessary. | |
3891 | */ | |
3892 | static int | |
3893 | really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist) | |
3894 | { | |
3895 | int nvoices; | |
3896 | awe_voice_list *vrec; | |
3897 | int level = 0; | |
3898 | ||
3899 | for (;;) { | |
3900 | vrec = awe_search_instr(bank, instr, *note); | |
3901 | nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); | |
3902 | if (nvoices == 0) { | |
3903 | if (bank == AWE_DRUM_BANK) | |
3904 | /* search default drumset */ | |
3905 | vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note); | |
3906 | else | |
3907 | /* search default preset */ | |
3908 | vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note); | |
3909 | nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); | |
3910 | } | |
3911 | if (nvoices == 0) { | |
3912 | if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0) | |
3913 | /* search default drumset */ | |
3914 | vrec = awe_search_instr(bank, 0, *note); | |
3915 | else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0) | |
3916 | /* search default preset */ | |
3917 | vrec = awe_search_instr(0, instr, *note); | |
3918 | nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); | |
3919 | } | |
3920 | if (nvoices < 0) { /* mapping */ | |
3921 | int key = vlist[0]->fixkey; | |
3922 | instr = vlist[0]->start; | |
3923 | bank = vlist[0]->end; | |
3924 | if (level++ > 5) { | |
3925 | printk(KERN_ERR "AWE32: too deep mapping level\n"); | |
3926 | return 0; | |
3927 | } | |
3928 | if (key >= 0) | |
3929 | *note = key; | |
3930 | } else | |
3931 | break; | |
3932 | } | |
3933 | ||
3934 | return nvoices; | |
3935 | } | |
3936 | ||
3937 | /* allocate voices corresponding note and velocity; supports multiple insts. */ | |
3938 | static void | |
3939 | awe_alloc_multi_voices(int ch, int note, int velocity, int key) | |
3940 | { | |
3941 | int i, v, nvoices, bank; | |
3942 | awe_voice_info *vlist[AWE_MAX_VOICES]; | |
3943 | ||
3944 | if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) | |
3945 | bank = AWE_DRUM_BANK; /* always search drumset */ | |
3946 | else | |
3947 | bank = channels[ch].bank; | |
3948 | ||
3949 | /* check the possible voices; note may be changeable if mapped */ | |
3950 | nvoices = really_alloc_voices(bank, channels[ch].instr, | |
3951 | ¬e, velocity, vlist); | |
3952 | ||
3953 | /* set the voices */ | |
3954 | current_alloc_time++; | |
3955 | for (i = 0; i < nvoices; i++) { | |
3956 | v = awe_clear_voice(); | |
3957 | voices[v].key = key; | |
3958 | voices[v].ch = ch; | |
3959 | voices[v].note = note; | |
3960 | voices[v].velocity = velocity; | |
3961 | voices[v].time = current_alloc_time; | |
3962 | voices[v].cinfo = &channels[ch]; | |
3963 | voices[v].sample = vlist[i]; | |
3964 | voices[v].state = AWE_ST_MARK; | |
3965 | voices[v].layer = nvoices - i - 1; /* in reverse order */ | |
3966 | } | |
3967 | ||
3968 | /* clear the mark in allocated voices */ | |
3969 | for (i = 0; i < awe_max_voices; i++) { | |
3970 | if (voices[i].state == AWE_ST_MARK) | |
3971 | voices[i].state = AWE_ST_OFF; | |
3972 | ||
3973 | } | |
3974 | } | |
3975 | ||
3976 | ||
3977 | /* search an empty voice. | |
3978 | if no empty voice is found, at least terminate a voice | |
3979 | */ | |
3980 | static int | |
3981 | awe_clear_voice(void) | |
3982 | { | |
3983 | enum { | |
3984 | OFF=0, RELEASED, SUSTAINED, PLAYING, END | |
3985 | }; | |
3986 | struct voice_candidate_t { | |
3987 | int best; | |
3988 | int time; | |
3989 | int vtarget; | |
3990 | } candidate[END]; | |
3991 | int i, type, vtarget; | |
3992 | ||
3993 | vtarget = 0xffff; | |
3994 | for (type = OFF; type < END; type++) { | |
3995 | candidate[type].best = -1; | |
3996 | candidate[type].time = current_alloc_time + 1; | |
3997 | candidate[type].vtarget = vtarget; | |
3998 | } | |
3999 | ||
4000 | for (i = 0; i < awe_max_voices; i++) { | |
4001 | if (voices[i].state & AWE_ST_OFF) | |
4002 | type = OFF; | |
4003 | else if (voices[i].state & AWE_ST_RELEASED) | |
4004 | type = RELEASED; | |
4005 | else if (voices[i].state & AWE_ST_SUSTAINED) | |
4006 | type = SUSTAINED; | |
4007 | else if (voices[i].state & ~AWE_ST_MARK) | |
4008 | type = PLAYING; | |
4009 | else | |
4010 | continue; | |
4011 | #ifdef AWE_CHECK_VTARGET | |
4012 | /* get current volume */ | |
4013 | vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff; | |
4014 | #endif | |
4015 | if (candidate[type].best < 0 || | |
4016 | vtarget < candidate[type].vtarget || | |
4017 | (vtarget == candidate[type].vtarget && | |
4018 | voices[i].time < candidate[type].time)) { | |
4019 | candidate[type].best = i; | |
4020 | candidate[type].time = voices[i].time; | |
4021 | candidate[type].vtarget = vtarget; | |
4022 | } | |
4023 | } | |
4024 | ||
4025 | for (type = OFF; type < END; type++) { | |
4026 | if ((i = candidate[type].best) >= 0) { | |
4027 | if (voices[i].state != AWE_ST_OFF) | |
4028 | awe_terminate(i); | |
4029 | awe_voice_init(i, TRUE); | |
4030 | return i; | |
4031 | } | |
4032 | } | |
4033 | return 0; | |
4034 | } | |
4035 | ||
4036 | ||
4037 | /* search sample for the specified note & velocity and set it on the voice; | |
4038 | * note that voice is the voice index (not channel index) | |
4039 | */ | |
4040 | static void | |
4041 | awe_alloc_one_voice(int voice, int note, int velocity) | |
4042 | { | |
4043 | int ch, nvoices, bank; | |
4044 | awe_voice_info *vlist[AWE_MAX_VOICES]; | |
4045 | ||
4046 | ch = voices[voice].ch; | |
4047 | if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice)) | |
4048 | bank = AWE_DRUM_BANK; /* always search drumset */ | |
4049 | else | |
4050 | bank = voices[voice].cinfo->bank; | |
4051 | ||
4052 | nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr, | |
4053 | ¬e, velocity, vlist); | |
4054 | if (nvoices > 0) { | |
4055 | voices[voice].time = ++current_alloc_time; | |
4056 | voices[voice].sample = vlist[0]; /* use the first one */ | |
4057 | voices[voice].layer = 0; | |
4058 | voices[voice].note = note; | |
4059 | voices[voice].velocity = velocity; | |
4060 | } | |
4061 | } | |
4062 | ||
4063 | ||
4064 | /* | |
4065 | * sequencer2 functions | |
4066 | */ | |
4067 | ||
4068 | /* search an empty voice; used by sequencer2 */ | |
4069 | static int | |
4070 | awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) | |
4071 | { | |
4072 | playing_mode = AWE_PLAY_MULTI2; | |
4073 | awe_info.nr_voices = AWE_MAX_CHANNELS; | |
4074 | return awe_clear_voice(); | |
4075 | } | |
4076 | ||
4077 | ||
4078 | /* set up voice; used by sequencer2 */ | |
4079 | static void | |
4080 | awe_setup_voice(int dev, int voice, int chn) | |
4081 | { | |
4082 | struct channel_info *info; | |
4083 | if (synth_devs[dev] == NULL || | |
4084 | (info = &synth_devs[dev]->chn_info[chn]) == NULL) | |
4085 | return; | |
4086 | ||
4087 | if (voice < 0 || voice >= awe_max_voices) | |
4088 | return; | |
4089 | ||
4090 | DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn)); | |
4091 | channels[chn].expression_vol = info->controllers[CTL_EXPRESSION]; | |
4092 | channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME]; | |
4093 | channels[chn].panning = | |
4094 | info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */ | |
4095 | channels[chn].bender = info->bender_value; /* zero center */ | |
4096 | channels[chn].bank = info->controllers[CTL_BANK_SELECT]; | |
4097 | channels[chn].sustained = info->controllers[CTL_SUSTAIN]; | |
4098 | if (info->controllers[CTL_EXT_EFF_DEPTH]) { | |
4099 | FX_SET(&channels[chn].fx, AWE_FX_REVERB, | |
4100 | info->controllers[CTL_EXT_EFF_DEPTH] * 2); | |
4101 | } | |
4102 | if (info->controllers[CTL_CHORUS_DEPTH]) { | |
4103 | FX_SET(&channels[chn].fx, AWE_FX_CHORUS, | |
4104 | info->controllers[CTL_CHORUS_DEPTH] * 2); | |
4105 | } | |
4106 | awe_set_instr(dev, chn, info->pgm_num); | |
4107 | } | |
4108 | ||
4109 | ||
4110 | #ifdef CONFIG_AWE32_MIXER | |
4111 | /* | |
4112 | * AWE32 mixer device control | |
4113 | */ | |
4114 | ||
4115 | static int awe_mixer_ioctl(int dev, unsigned int cmd, void __user *arg); | |
4116 | ||
4117 | static int my_mixerdev = -1; | |
4118 | ||
4119 | static struct mixer_operations awe_mixer_operations = { | |
4120 | .owner = THIS_MODULE, | |
4121 | .id = "AWE", | |
4122 | .name = "AWE32 Equalizer", | |
4123 | .ioctl = awe_mixer_ioctl, | |
4124 | }; | |
4125 | ||
4126 | static void __init attach_mixer(void) | |
4127 | { | |
4128 | if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) { | |
4129 | mixer_devs[my_mixerdev] = &awe_mixer_operations; | |
4130 | } | |
4131 | } | |
4132 | ||
4133 | static void unload_mixer(void) | |
4134 | { | |
4135 | if (my_mixerdev >= 0) | |
4136 | sound_unload_mixerdev(my_mixerdev); | |
4137 | } | |
4138 | ||
4139 | static int | |
4140 | awe_mixer_ioctl(int dev, unsigned int cmd, void __user * arg) | |
4141 | { | |
4142 | int i, level, value; | |
4143 | ||
4144 | if (((cmd >> 8) & 0xff) != 'M') | |
4145 | return -EINVAL; | |
4146 | ||
4147 | if (get_user(level, (int __user *)arg)) | |
4148 | return -EFAULT; | |
4149 | level = ((level & 0xff) + (level >> 8)) / 2; | |
4150 | DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level)); | |
4151 | ||
4152 | if (_SIOC_DIR(cmd) & _SIOC_WRITE) { | |
4153 | switch (cmd & 0xff) { | |
4154 | case SOUND_MIXER_BASS: | |
4155 | value = level * 12 / 100; | |
4156 | if (value >= 12) | |
4157 | value = 11; | |
4158 | ctrls[AWE_MD_BASS_LEVEL] = value; | |
4159 | awe_update_equalizer(); | |
4160 | break; | |
4161 | case SOUND_MIXER_TREBLE: | |
4162 | value = level * 12 / 100; | |
4163 | if (value >= 12) | |
4164 | value = 11; | |
4165 | ctrls[AWE_MD_TREBLE_LEVEL] = value; | |
4166 | awe_update_equalizer(); | |
4167 | break; | |
4168 | case SOUND_MIXER_VOLUME: | |
4169 | level = level * 127 / 100; | |
4170 | if (level >= 128) level = 127; | |
4171 | atten_relative = FALSE; | |
4172 | atten_offset = vol_table[level]; | |
4173 | awe_update_volume(); | |
4174 | break; | |
4175 | } | |
4176 | } | |
4177 | switch (cmd & 0xff) { | |
4178 | case SOUND_MIXER_BASS: | |
4179 | level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24; | |
4180 | level = (level << 8) | level; | |
4181 | break; | |
4182 | case SOUND_MIXER_TREBLE: | |
4183 | level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24; | |
4184 | level = (level << 8) | level; | |
4185 | break; | |
4186 | case SOUND_MIXER_VOLUME: | |
4187 | value = atten_offset; | |
4188 | if (atten_relative) | |
4189 | value += ctrls[AWE_MD_ZERO_ATTEN]; | |
4190 | for (i = 127; i > 0; i--) { | |
4191 | if (value <= vol_table[i]) | |
4192 | break; | |
4193 | } | |
4194 | level = i * 100 / 127; | |
4195 | level = (level << 8) | level; | |
4196 | break; | |
4197 | case SOUND_MIXER_DEVMASK: | |
4198 | level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME; | |
4199 | break; | |
4200 | default: | |
4201 | level = 0; | |
4202 | break; | |
4203 | } | |
4204 | if (put_user(level, (int __user *)arg)) | |
4205 | return -EFAULT; | |
4206 | return level; | |
4207 | } | |
4208 | #endif /* CONFIG_AWE32_MIXER */ | |
4209 | ||
4210 | ||
4211 | /* | |
4212 | * initialization of Emu8000 | |
4213 | */ | |
4214 | ||
4215 | /* intiailize audio channels */ | |
4216 | static void | |
4217 | awe_init_audio(void) | |
4218 | { | |
4219 | int ch; | |
4220 | ||
4221 | /* turn off envelope engines */ | |
4222 | for (ch = 0; ch < AWE_MAX_VOICES; ch++) { | |
4223 | awe_poke(AWE_DCYSUSV(ch), 0x80); | |
4224 | } | |
4225 | ||
4226 | /* reset all other parameters to zero */ | |
4227 | for (ch = 0; ch < AWE_MAX_VOICES; ch++) { | |
4228 | awe_poke(AWE_ENVVOL(ch), 0); | |
4229 | awe_poke(AWE_ENVVAL(ch), 0); | |
4230 | awe_poke(AWE_DCYSUS(ch), 0); | |
4231 | awe_poke(AWE_ATKHLDV(ch), 0); | |
4232 | awe_poke(AWE_LFO1VAL(ch), 0); | |
4233 | awe_poke(AWE_ATKHLD(ch), 0); | |
4234 | awe_poke(AWE_LFO2VAL(ch), 0); | |
4235 | awe_poke(AWE_IP(ch), 0); | |
4236 | awe_poke(AWE_IFATN(ch), 0); | |
4237 | awe_poke(AWE_PEFE(ch), 0); | |
4238 | awe_poke(AWE_FMMOD(ch), 0); | |
4239 | awe_poke(AWE_TREMFRQ(ch), 0); | |
4240 | awe_poke(AWE_FM2FRQ2(ch), 0); | |
4241 | awe_poke_dw(AWE_PTRX(ch), 0); | |
4242 | awe_poke_dw(AWE_VTFT(ch), 0); | |
4243 | awe_poke_dw(AWE_PSST(ch), 0); | |
4244 | awe_poke_dw(AWE_CSL(ch), 0); | |
4245 | awe_poke_dw(AWE_CCCA(ch), 0); | |
4246 | } | |
4247 | ||
4248 | for (ch = 0; ch < AWE_MAX_VOICES; ch++) { | |
4249 | awe_poke_dw(AWE_CPF(ch), 0); | |
4250 | awe_poke_dw(AWE_CVCF(ch), 0); | |
4251 | } | |
4252 | } | |
4253 | ||
4254 | ||
4255 | /* initialize DMA address */ | |
4256 | static void | |
4257 | awe_init_dma(void) | |
4258 | { | |
4259 | awe_poke_dw(AWE_SMALR, 0); | |
4260 | awe_poke_dw(AWE_SMARR, 0); | |
4261 | awe_poke_dw(AWE_SMALW, 0); | |
4262 | awe_poke_dw(AWE_SMARW, 0); | |
4263 | } | |
4264 | ||
4265 | ||
4266 | /* initialization arrays; from ADIP */ | |
4267 | ||
4268 | static unsigned short init1[128] = { | |
4269 | 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330, | |
4270 | 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730, | |
4271 | 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30, | |
4272 | 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30, | |
4273 | ||
4274 | 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330, | |
4275 | 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730, | |
4276 | 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30, | |
4277 | 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30, | |
4278 | ||
4279 | 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330, | |
4280 | 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730, | |
4281 | 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30, | |
4282 | 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30, | |
4283 | ||
4284 | 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330, | |
4285 | 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730, | |
4286 | 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30, | |
4287 | 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30, | |
4288 | }; | |
4289 | ||
4290 | static unsigned short init2[128] = { | |
4291 | 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330, | |
4292 | 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730, | |
4293 | 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30, | |
4294 | 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30, | |
4295 | ||
4296 | 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330, | |
4297 | 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730, | |
4298 | 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30, | |
4299 | 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30, | |
4300 | ||
4301 | 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330, | |
4302 | 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730, | |
4303 | 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30, | |
4304 | 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30, | |
4305 | ||
4306 | 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330, | |
4307 | 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730, | |
4308 | 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30, | |
4309 | 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30, | |
4310 | }; | |
4311 | ||
4312 | static unsigned short init3[128] = { | |
4313 | 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, | |
4314 | 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254, | |
4315 | 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234, | |
4316 | 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224, | |
4317 | ||
4318 | 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254, | |
4319 | 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264, | |
4320 | 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294, | |
4321 | 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3, | |
4322 | ||
4323 | 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287, | |
4324 | 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7, | |
4325 | 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386, | |
4326 | 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55, | |
4327 | ||
4328 | 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308, | |
4329 | 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F, | |
4330 | 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319, | |
4331 | 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570, | |
4332 | }; | |
4333 | ||
4334 | static unsigned short init4[128] = { | |
4335 | 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, | |
4336 | 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254, | |
4337 | 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234, | |
4338 | 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224, | |
4339 | ||
4340 | 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254, | |
4341 | 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264, | |
4342 | 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294, | |
4343 | 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3, | |
4344 | ||
4345 | 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287, | |
4346 | 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7, | |
4347 | 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386, | |
4348 | 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55, | |
4349 | ||
4350 | 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308, | |
4351 | 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F, | |
4352 | 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319, | |
4353 | 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570, | |
4354 | }; | |
4355 | ||
4356 | ||
4357 | /* send initialization arrays to start up */ | |
4358 | static void | |
4359 | awe_init_array(void) | |
4360 | { | |
4361 | awe_send_array(init1); | |
4362 | awe_wait(1024); | |
4363 | awe_send_array(init2); | |
4364 | awe_send_array(init3); | |
4365 | awe_poke_dw(AWE_HWCF4, 0); | |
4366 | awe_poke_dw(AWE_HWCF5, 0x83); | |
4367 | awe_poke_dw(AWE_HWCF6, 0x8000); | |
4368 | awe_send_array(init4); | |
4369 | } | |
4370 | ||
4371 | /* send an initialization array */ | |
4372 | static void | |
4373 | awe_send_array(unsigned short *data) | |
4374 | { | |
4375 | int i; | |
4376 | unsigned short *p; | |
4377 | ||
4378 | p = data; | |
4379 | for (i = 0; i < AWE_MAX_VOICES; i++, p++) | |
4380 | awe_poke(AWE_INIT1(i), *p); | |
4381 | for (i = 0; i < AWE_MAX_VOICES; i++, p++) | |
4382 | awe_poke(AWE_INIT2(i), *p); | |
4383 | for (i = 0; i < AWE_MAX_VOICES; i++, p++) | |
4384 | awe_poke(AWE_INIT3(i), *p); | |
4385 | for (i = 0; i < AWE_MAX_VOICES; i++, p++) | |
4386 | awe_poke(AWE_INIT4(i), *p); | |
4387 | } | |
4388 | ||
4389 | ||
4390 | /* | |
4391 | * set up awe32 channels to some known state. | |
4392 | */ | |
4393 | ||
4394 | /* set the envelope & LFO parameters to the default values; see ADIP */ | |
4395 | static void | |
4396 | awe_tweak_voice(int i) | |
4397 | { | |
4398 | /* set all mod/vol envelope shape to minimum */ | |
4399 | awe_poke(AWE_ENVVOL(i), 0x8000); | |
4400 | awe_poke(AWE_ENVVAL(i), 0x8000); | |
4401 | awe_poke(AWE_DCYSUS(i), 0x7F7F); | |
4402 | awe_poke(AWE_ATKHLDV(i), 0x7F7F); | |
4403 | awe_poke(AWE_ATKHLD(i), 0x7F7F); | |
4404 | awe_poke(AWE_PEFE(i), 0); /* mod envelope height to zero */ | |
4405 | awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */ | |
4406 | awe_poke(AWE_LFO2VAL(i), 0x8000); | |
4407 | awe_poke(AWE_IP(i), 0xE000); /* no pitch shift */ | |
4408 | awe_poke(AWE_IFATN(i), 0xFF00); /* volume to minimum */ | |
4409 | awe_poke(AWE_FMMOD(i), 0); | |
4410 | awe_poke(AWE_TREMFRQ(i), 0); | |
4411 | awe_poke(AWE_FM2FRQ2(i), 0); | |
4412 | } | |
4413 | ||
4414 | static void | |
4415 | awe_tweak(void) | |
4416 | { | |
4417 | int i; | |
4418 | /* reset all channels */ | |
4419 | for (i = 0; i < awe_max_voices; i++) | |
4420 | awe_tweak_voice(i); | |
4421 | } | |
4422 | ||
4423 | ||
4424 | /* | |
4425 | * initializes the FM section of AWE32; | |
4426 | * see Vince Vu's unofficial AWE32 programming guide | |
4427 | */ | |
4428 | ||
4429 | static void | |
4430 | awe_init_fm(void) | |
4431 | { | |
4432 | #ifndef AWE_ALWAYS_INIT_FM | |
4433 | /* if no extended memory is on board.. */ | |
4434 | if (memsize <= 0) | |
4435 | return; | |
4436 | #endif | |
4437 | DEBUG(3,printk("AWE32: initializing FM\n")); | |
4438 | ||
4439 | /* Initialize the last two channels for DRAM refresh and producing | |
4440 | the reverb and chorus effects for Yamaha OPL-3 synthesizer */ | |
4441 | ||
4442 | /* 31: FM left channel, 0xffffe0-0xffffe8 */ | |
4443 | awe_poke(AWE_DCYSUSV(30), 0x80); | |
4444 | awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */ | |
4445 | awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 | | |
4446 | (DEF_FM_CHORUS_DEPTH << 24)); | |
4447 | awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8)); | |
4448 | awe_poke_dw(AWE_CPF(30), 0); | |
4449 | awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3); | |
4450 | ||
4451 | /* 32: FM right channel, 0xfffff0-0xfffff8 */ | |
4452 | awe_poke(AWE_DCYSUSV(31), 0x80); | |
4453 | awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */ | |
4454 | awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 | | |
4455 | (DEF_FM_CHORUS_DEPTH << 24)); | |
4456 | awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8)); | |
4457 | awe_poke_dw(AWE_CPF(31), 0x8000); | |
4458 | awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3); | |
4459 | ||
4460 | /* skew volume & cutoff */ | |
4461 | awe_poke_dw(AWE_VTFT(30), 0x8000FFFF); | |
4462 | awe_poke_dw(AWE_VTFT(31), 0x8000FFFF); | |
4463 | ||
4464 | voices[30].state = AWE_ST_FM; | |
4465 | voices[31].state = AWE_ST_FM; | |
4466 | ||
4467 | /* change maximum channels to 30 */ | |
4468 | awe_max_voices = AWE_NORMAL_VOICES; | |
4469 | if (playing_mode == AWE_PLAY_DIRECT) | |
4470 | awe_info.nr_voices = awe_max_voices; | |
4471 | else | |
4472 | awe_info.nr_voices = AWE_MAX_CHANNELS; | |
4473 | voice_alloc->max_voice = awe_max_voices; | |
4474 | } | |
4475 | ||
4476 | /* | |
4477 | * AWE32 DRAM access routines | |
4478 | */ | |
4479 | ||
4480 | /* open DRAM write accessing mode */ | |
4481 | static int | |
4482 | awe_open_dram_for_write(int offset, int channels) | |
4483 | { | |
4484 | int vidx[AWE_NORMAL_VOICES]; | |
4485 | int i; | |
4486 | ||
4487 | if (channels < 0 || channels >= AWE_NORMAL_VOICES) { | |
4488 | channels = AWE_NORMAL_VOICES; | |
4489 | for (i = 0; i < AWE_NORMAL_VOICES; i++) | |
4490 | vidx[i] = i; | |
4491 | } else { | |
4492 | for (i = 0; i < channels; i++) { | |
4493 | vidx[i] = awe_clear_voice(); | |
4494 | voices[vidx[i]].state = AWE_ST_MARK; | |
4495 | } | |
4496 | } | |
4497 | ||
4498 | /* use all channels for DMA transfer */ | |
4499 | for (i = 0; i < channels; i++) { | |
4500 | if (vidx[i] < 0) continue; | |
4501 | awe_poke(AWE_DCYSUSV(vidx[i]), 0x80); | |
4502 | awe_poke_dw(AWE_VTFT(vidx[i]), 0); | |
4503 | awe_poke_dw(AWE_CVCF(vidx[i]), 0); | |
4504 | awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000); | |
4505 | awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000); | |
4506 | awe_poke_dw(AWE_PSST(vidx[i]), 0); | |
4507 | awe_poke_dw(AWE_CSL(vidx[i]), 0); | |
4508 | awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000); | |
4509 | voices[vidx[i]].state = AWE_ST_DRAM; | |
4510 | } | |
4511 | /* point channels 31 & 32 to ROM samples for DRAM refresh */ | |
4512 | awe_poke_dw(AWE_VTFT(30), 0); | |
4513 | awe_poke_dw(AWE_PSST(30), 0x1d8); | |
4514 | awe_poke_dw(AWE_CSL(30), 0x1e0); | |
4515 | awe_poke_dw(AWE_CCCA(30), 0x1d8); | |
4516 | awe_poke_dw(AWE_VTFT(31), 0); | |
4517 | awe_poke_dw(AWE_PSST(31), 0x1d8); | |
4518 | awe_poke_dw(AWE_CSL(31), 0x1e0); | |
4519 | awe_poke_dw(AWE_CCCA(31), 0x1d8); | |
4520 | voices[30].state = AWE_ST_FM; | |
4521 | voices[31].state = AWE_ST_FM; | |
4522 | ||
4523 | /* if full bit is on, not ready to write on */ | |
4524 | if (awe_peek_dw(AWE_SMALW) & 0x80000000) { | |
4525 | for (i = 0; i < channels; i++) { | |
4526 | awe_poke_dw(AWE_CCCA(vidx[i]), 0); | |
4527 | voices[vidx[i]].state = AWE_ST_OFF; | |
4528 | } | |
4529 | printk("awe: not ready to write..\n"); | |
4530 | return -EPERM; | |
4531 | } | |
4532 | ||
4533 | /* set address to write */ | |
4534 | awe_poke_dw(AWE_SMALW, offset); | |
4535 | ||
4536 | return 0; | |
4537 | } | |
4538 | ||
4539 | /* open DRAM for RAM size detection */ | |
4540 | static void | |
4541 | awe_open_dram_for_check(void) | |
4542 | { | |
4543 | int i; | |
4544 | for (i = 0; i < AWE_NORMAL_VOICES; i++) { | |
4545 | awe_poke(AWE_DCYSUSV(i), 0x80); | |
4546 | awe_poke_dw(AWE_VTFT(i), 0); | |
4547 | awe_poke_dw(AWE_CVCF(i), 0); | |
4548 | awe_poke_dw(AWE_PTRX(i), 0x40000000); | |
4549 | awe_poke_dw(AWE_CPF(i), 0x40000000); | |
4550 | awe_poke_dw(AWE_PSST(i), 0); | |
4551 | awe_poke_dw(AWE_CSL(i), 0); | |
4552 | if (i & 1) /* DMA write */ | |
4553 | awe_poke_dw(AWE_CCCA(i), 0x06000000); | |
4554 | else /* DMA read */ | |
4555 | awe_poke_dw(AWE_CCCA(i), 0x04000000); | |
4556 | voices[i].state = AWE_ST_DRAM; | |
4557 | } | |
4558 | } | |
4559 | ||
4560 | ||
4561 | /* close dram access */ | |
4562 | static void | |
4563 | awe_close_dram(void) | |
4564 | { | |
4565 | int i; | |
4566 | /* wait until FULL bit in SMAxW register be false */ | |
4567 | for (i = 0; i < 10000; i++) { | |
4568 | if (!(awe_peek_dw(AWE_SMALW) & 0x80000000)) | |
4569 | break; | |
4570 | awe_wait(10); | |
4571 | } | |
4572 | ||
4573 | for (i = 0; i < AWE_NORMAL_VOICES; i++) { | |
4574 | if (voices[i].state == AWE_ST_DRAM) { | |
4575 | awe_poke_dw(AWE_CCCA(i), 0); | |
4576 | awe_poke(AWE_DCYSUSV(i), 0x807F); | |
4577 | voices[i].state = AWE_ST_OFF; | |
4578 | } | |
4579 | } | |
4580 | } | |
4581 | ||
4582 | ||
4583 | /* | |
4584 | * check dram size on AWE board | |
4585 | */ | |
4586 | ||
4587 | /* any three numbers you like */ | |
4588 | #define UNIQUE_ID1 0x1234 | |
4589 | #define UNIQUE_ID2 0x4321 | |
4590 | #define UNIQUE_ID3 0xABCD | |
4591 | ||
4592 | static void __init | |
4593 | awe_check_dram(void) | |
4594 | { | |
4595 | if (awe_present) /* already initialized */ | |
4596 | return; | |
4597 | ||
4598 | if (memsize >= 0) { /* given by config file or module option */ | |
4599 | memsize *= 1024; /* convert to Kbytes */ | |
4600 | return; | |
4601 | } | |
4602 | ||
4603 | awe_open_dram_for_check(); | |
4604 | ||
4605 | memsize = 0; | |
4606 | ||
4607 | /* set up unique two id numbers */ | |
4608 | awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET); | |
4609 | awe_poke(AWE_SMLD, UNIQUE_ID1); | |
4610 | awe_poke(AWE_SMLD, UNIQUE_ID2); | |
4611 | ||
4612 | while (memsize < AWE_MAX_DRAM_SIZE) { | |
4613 | awe_wait(5); | |
4614 | /* read a data on the DRAM start address */ | |
4615 | awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET); | |
4616 | awe_peek(AWE_SMLD); /* discard stale data */ | |
4617 | if (awe_peek(AWE_SMLD) != UNIQUE_ID1) | |
4618 | break; | |
4619 | if (awe_peek(AWE_SMLD) != UNIQUE_ID2) | |
4620 | break; | |
4621 | memsize += 512; /* increment 512kbytes */ | |
4622 | /* Write a unique data on the test address; | |
4623 | * if the address is out of range, the data is written on | |
4624 | * 0x200000(=AWE_DRAM_OFFSET). Then the two id words are | |
4625 | * broken by this data. | |
4626 | */ | |
4627 | awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L); | |
4628 | awe_poke(AWE_SMLD, UNIQUE_ID3); | |
4629 | awe_wait(5); | |
4630 | /* read a data on the just written DRAM address */ | |
4631 | awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L); | |
4632 | awe_peek(AWE_SMLD); /* discard stale data */ | |
4633 | if (awe_peek(AWE_SMLD) != UNIQUE_ID3) | |
4634 | break; | |
4635 | } | |
4636 | awe_close_dram(); | |
4637 | ||
4638 | DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize)); | |
4639 | ||
4640 | /* convert to Kbytes */ | |
4641 | memsize *= 1024; | |
4642 | } | |
4643 | ||
4644 | ||
4645 | /*----------------------------------------------------------------*/ | |
4646 | ||
4647 | /* | |
4648 | * chorus and reverb controls; from VV's guide | |
4649 | */ | |
4650 | ||
4651 | /* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */ | |
4652 | static char chorus_defined[AWE_CHORUS_NUMBERS]; | |
4653 | static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = { | |
4654 | {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */ | |
4655 | {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */ | |
4656 | {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */ | |
4657 | {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */ | |
4658 | {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */ | |
4659 | {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */ | |
4660 | {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */ | |
4661 | {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */ | |
4662 | }; | |
4663 | ||
4664 | static int | |
4665 | awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count) | |
4666 | { | |
4667 | if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) { | |
4668 | printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg); | |
4669 | return -EINVAL; | |
4670 | } | |
4671 | if (count < sizeof(awe_chorus_fx_rec)) { | |
4672 | printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n"); | |
4673 | return -EINVAL; | |
4674 | } | |
4675 | if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, | |
4676 | sizeof(awe_chorus_fx_rec))) | |
4677 | return -EFAULT; | |
4678 | chorus_defined[patch->optarg] = TRUE; | |
4679 | return 0; | |
4680 | } | |
4681 | ||
4682 | static void | |
4683 | awe_set_chorus_mode(int effect) | |
4684 | { | |
4685 | if (effect < 0 || effect >= AWE_CHORUS_NUMBERS || | |
4686 | (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect])) | |
4687 | return; | |
4688 | awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback); | |
4689 | awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset); | |
4690 | awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth); | |
4691 | awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay); | |
4692 | awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq); | |
4693 | awe_poke_dw(AWE_HWCF6, 0x8000); | |
4694 | awe_poke_dw(AWE_HWCF7, 0x0000); | |
4695 | } | |
4696 | ||
4697 | static void | |
4698 | awe_update_chorus_mode(void) | |
4699 | { | |
4700 | awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]); | |
4701 | } | |
4702 | ||
4703 | /*----------------------------------------------------------------*/ | |
4704 | ||
4705 | /* reverb mode settings; write the following 28 data of 16 bit length | |
4706 | * on the corresponding ports in the reverb_cmds array | |
4707 | */ | |
4708 | static char reverb_defined[AWE_CHORUS_NUMBERS]; | |
4709 | static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = { | |
4710 | {{ /* room 1 */ | |
4711 | 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4, | |
4712 | 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516, | |
4713 | 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, | |
4714 | 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, | |
4715 | }}, | |
4716 | {{ /* room 2 */ | |
4717 | 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284, | |
4718 | 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, | |
4719 | 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, | |
4720 | 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, | |
4721 | }}, | |
4722 | {{ /* room 3 */ | |
4723 | 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284, | |
4724 | 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516, | |
4725 | 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B, | |
4726 | 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A, | |
4727 | }}, | |
4728 | {{ /* hall 1 */ | |
4729 | 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284, | |
4730 | 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, | |
4731 | 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A, | |
4732 | 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, | |
4733 | }}, | |
4734 | {{ /* hall 2 */ | |
4735 | 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254, | |
4736 | 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3, | |
4737 | 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, | |
4738 | 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, | |
4739 | }}, | |
4740 | {{ /* plate */ | |
4741 | 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234, | |
4742 | 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548, | |
4743 | 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, | |
4744 | 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528, | |
4745 | }}, | |
4746 | {{ /* delay */ | |
4747 | 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204, | |
4748 | 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, | |
4749 | 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, | |
4750 | 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, | |
4751 | }}, | |
4752 | {{ /* panning delay */ | |
4753 | 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204, | |
4754 | 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, | |
4755 | 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, | |
4756 | 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, | |
4757 | }}, | |
4758 | }; | |
4759 | ||
4760 | static struct ReverbCmdPair { | |
4761 | unsigned short cmd, port; | |
4762 | } reverb_cmds[28] = { | |
4763 | {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)}, | |
4764 | {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)}, | |
4765 | {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)}, | |
4766 | {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)}, | |
4767 | {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)}, | |
4768 | {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)}, | |
4769 | {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)}, | |
4770 | }; | |
4771 | ||
4772 | static int | |
4773 | awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count) | |
4774 | { | |
4775 | if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) { | |
4776 | printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg); | |
4777 | return -EINVAL; | |
4778 | } | |
4779 | if (count < sizeof(awe_reverb_fx_rec)) { | |
4780 | printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n"); | |
4781 | return -EINVAL; | |
4782 | } | |
4783 | if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, | |
4784 | sizeof(awe_reverb_fx_rec))) | |
4785 | return -EFAULT; | |
4786 | reverb_defined[patch->optarg] = TRUE; | |
4787 | return 0; | |
4788 | } | |
4789 | ||
4790 | static void | |
4791 | awe_set_reverb_mode(int effect) | |
4792 | { | |
4793 | int i; | |
4794 | if (effect < 0 || effect >= AWE_REVERB_NUMBERS || | |
4795 | (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect])) | |
4796 | return; | |
4797 | for (i = 0; i < 28; i++) | |
4798 | awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port, | |
4799 | reverb_parm[effect].parms[i]); | |
4800 | } | |
4801 | ||
4802 | static void | |
4803 | awe_update_reverb_mode(void) | |
4804 | { | |
4805 | awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]); | |
4806 | } | |
4807 | ||
4808 | /* | |
4809 | * treble/bass equalizer control | |
4810 | */ | |
4811 | ||
4812 | static unsigned short bass_parm[12][3] = { | |
4813 | {0xD26A, 0xD36A, 0x0000}, /* -12 dB */ | |
4814 | {0xD25B, 0xD35B, 0x0000}, /* -8 */ | |
4815 | {0xD24C, 0xD34C, 0x0000}, /* -6 */ | |
4816 | {0xD23D, 0xD33D, 0x0000}, /* -4 */ | |
4817 | {0xD21F, 0xD31F, 0x0000}, /* -2 */ | |
4818 | {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */ | |
4819 | {0xC219, 0xC319, 0x0001}, /* +2 */ | |
4820 | {0xC22A, 0xC32A, 0x0001}, /* +4 */ | |
4821 | {0xC24C, 0xC34C, 0x0001}, /* +6 */ | |
4822 | {0xC26E, 0xC36E, 0x0001}, /* +8 */ | |
4823 | {0xC248, 0xC348, 0x0002}, /* +10 */ | |
4824 | {0xC26A, 0xC36A, 0x0002}, /* +12 dB */ | |
4825 | }; | |
4826 | ||
4827 | static unsigned short treble_parm[12][9] = { | |
4828 | {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */ | |
4829 | {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, | |
4830 | {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, | |
4831 | {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, | |
4832 | {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, | |
4833 | {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002}, | |
4834 | {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002}, | |
4835 | {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002}, | |
4836 | {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002}, | |
4837 | {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */ | |
4838 | {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, | |
4839 | {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */ | |
4840 | }; | |
4841 | ||
4842 | ||
4843 | /* | |
4844 | * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB] | |
4845 | */ | |
4846 | static void | |
4847 | awe_equalizer(int bass, int treble) | |
4848 | { | |
4849 | unsigned short w; | |
4850 | ||
4851 | if (bass < 0 || bass > 11 || treble < 0 || treble > 11) | |
4852 | return; | |
4853 | awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]); | |
4854 | awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]); | |
4855 | awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]); | |
4856 | awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]); | |
4857 | awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]); | |
4858 | awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]); | |
4859 | awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]); | |
4860 | awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]); | |
4861 | awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]); | |
4862 | awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]); | |
4863 | w = bass_parm[bass][2] + treble_parm[treble][8]; | |
4864 | awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262)); | |
4865 | awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362)); | |
4866 | } | |
4867 | ||
4868 | static void awe_update_equalizer(void) | |
4869 | { | |
4870 | awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]); | |
4871 | } | |
4872 | ||
4873 | ||
4874 | /*----------------------------------------------------------------*/ | |
4875 | ||
4876 | #ifdef CONFIG_AWE32_MIDIEMU | |
4877 | ||
4878 | /* | |
4879 | * Emu8000 MIDI Emulation | |
4880 | */ | |
4881 | ||
4882 | /* | |
4883 | * midi queue record | |
4884 | */ | |
4885 | ||
4886 | /* queue type */ | |
4887 | enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, }; | |
4888 | ||
4889 | #define MAX_MIDIBUF 64 | |
4890 | ||
4891 | /* midi status */ | |
4892 | typedef struct MidiStatus { | |
4893 | int queue; /* queue type */ | |
4894 | int qlen; /* queue length */ | |
4895 | int read; /* chars read */ | |
4896 | int status; /* current status */ | |
4897 | int chan; /* current channel */ | |
4898 | unsigned char buf[MAX_MIDIBUF]; | |
4899 | } MidiStatus; | |
4900 | ||
4901 | /* MIDI mode type */ | |
4902 | enum { MODE_GM, MODE_GS, MODE_XG, }; | |
4903 | ||
4904 | /* NRPN / CC -> Emu8000 parameter converter */ | |
4905 | typedef struct { | |
4906 | int control; | |
4907 | int awe_effect; | |
4908 | unsigned short (*convert)(int val); | |
4909 | } ConvTable; | |
4910 | ||
4911 | ||
4912 | /* | |
4913 | * prototypes | |
4914 | */ | |
4915 | ||
4916 | static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int)); | |
4917 | static void awe_midi_close(int dev); | |
4918 | static int awe_midi_ioctl(int dev, unsigned cmd, void __user * arg); | |
4919 | static int awe_midi_outputc(int dev, unsigned char midi_byte); | |
4920 | ||
4921 | static void init_midi_status(MidiStatus *st); | |
4922 | static void clear_rpn(void); | |
4923 | static void get_midi_char(MidiStatus *st, int c); | |
4924 | /*static void queue_varlen(MidiStatus *st, int c);*/ | |
4925 | static void special_event(MidiStatus *st, int c); | |
4926 | static void queue_read(MidiStatus *st, int c); | |
4927 | static void midi_note_on(MidiStatus *st); | |
4928 | static void midi_note_off(MidiStatus *st); | |
4929 | static void midi_key_pressure(MidiStatus *st); | |
4930 | static void midi_channel_pressure(MidiStatus *st); | |
4931 | static void midi_pitch_wheel(MidiStatus *st); | |
4932 | static void midi_program_change(MidiStatus *st); | |
4933 | static void midi_control_change(MidiStatus *st); | |
4934 | static void midi_select_bank(MidiStatus *st, int val); | |
4935 | static void midi_nrpn_event(MidiStatus *st); | |
4936 | static void midi_rpn_event(MidiStatus *st); | |
4937 | static void midi_detune(int chan, int coarse, int fine); | |
4938 | static void midi_system_exclusive(MidiStatus *st); | |
4939 | static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val); | |
4940 | static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val); | |
4941 | static int xg_control_change(MidiStatus *st, int cmd, int val); | |
4942 | ||
4943 | #define numberof(ary) (sizeof(ary)/sizeof(ary[0])) | |
4944 | ||
4945 | ||
4946 | /* | |
4947 | * OSS Midi device record | |
4948 | */ | |
4949 | ||
4950 | static struct midi_operations awe_midi_operations = | |
4951 | { | |
4952 | .owner = THIS_MODULE, | |
4953 | .info = {"AWE Midi Emu", 0, 0, SNDCARD_SB}, | |
4954 | .in_info = {0}, | |
4955 | .open = awe_midi_open, /*open*/ | |
4956 | .close = awe_midi_close, /*close*/ | |
4957 | .ioctl = awe_midi_ioctl, /*ioctl*/ | |
4958 | .outputc = awe_midi_outputc, /*outputc*/ | |
4959 | }; | |
4960 | ||
4961 | static int my_mididev = -1; | |
4962 | ||
4963 | static void __init attach_midiemu(void) | |
4964 | { | |
4965 | if ((my_mididev = sound_alloc_mididev()) < 0) | |
4966 | printk ("Sound: Too many midi devices detected\n"); | |
4967 | else | |
4968 | midi_devs[my_mididev] = &awe_midi_operations; | |
4969 | } | |
4970 | ||
4971 | static void unload_midiemu(void) | |
4972 | { | |
4973 | if (my_mididev >= 0) | |
4974 | sound_unload_mididev(my_mididev); | |
4975 | } | |
4976 | ||
4977 | ||
4978 | /* | |
4979 | * open/close midi device | |
4980 | */ | |
4981 | ||
4982 | static int midi_opened = FALSE; | |
4983 | ||
4984 | static int midi_mode; | |
4985 | static int coarsetune, finetune; | |
4986 | ||
4987 | static int xg_mapping = TRUE; | |
4988 | static int xg_bankmode; | |
4989 | ||
4990 | /* effect sensitivity */ | |
4991 | ||
4992 | #define FX_CUTOFF 0 | |
4993 | #define FX_RESONANCE 1 | |
4994 | #define FX_ATTACK 2 | |
4995 | #define FX_RELEASE 3 | |
4996 | #define FX_VIBRATE 4 | |
4997 | #define FX_VIBDEPTH 5 | |
4998 | #define FX_VIBDELAY 6 | |
4999 | #define FX_NUMS 7 | |
5000 | ||
5001 | #define DEF_FX_CUTOFF 170 | |
5002 | #define DEF_FX_RESONANCE 6 | |
5003 | #define DEF_FX_ATTACK 50 | |
5004 | #define DEF_FX_RELEASE 50 | |
5005 | #define DEF_FX_VIBRATE 30 | |
5006 | #define DEF_FX_VIBDEPTH 4 | |
5007 | #define DEF_FX_VIBDELAY 1500 | |
5008 | ||
5009 | /* effect sense: */ | |
5010 | static int gs_sense[] = | |
5011 | { | |
5012 | DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE, | |
5013 | DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY | |
5014 | }; | |
5015 | static int xg_sense[] = | |
5016 | { | |
5017 | DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE, | |
5018 | DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY | |
5019 | }; | |
5020 | ||
5021 | ||
5022 | /* current status */ | |
5023 | static MidiStatus curst; | |
5024 | ||
5025 | ||
5026 | static int | |
5027 | awe_midi_open (int dev, int mode, | |
5028 | void (*input)(int,unsigned char), | |
5029 | void (*output)(int)) | |
5030 | { | |
5031 | if (midi_opened) | |
5032 | return -EBUSY; | |
5033 | ||
5034 | midi_opened = TRUE; | |
5035 | ||
5036 | midi_mode = MODE_GM; | |
5037 | ||
5038 | curst.queue = Q_NONE; | |
5039 | curst.qlen = 0; | |
5040 | curst.read = 0; | |
5041 | curst.status = 0; | |
5042 | curst.chan = 0; | |
5043 | memset(curst.buf, 0, sizeof(curst.buf)); | |
5044 | ||
5045 | init_midi_status(&curst); | |
5046 | ||
5047 | return 0; | |
5048 | } | |
5049 | ||
5050 | static void | |
5051 | awe_midi_close (int dev) | |
5052 | { | |
5053 | midi_opened = FALSE; | |
5054 | } | |
5055 | ||
5056 | ||
5057 | static int | |
5058 | awe_midi_ioctl (int dev, unsigned cmd, void __user *arg) | |
5059 | { | |
5060 | return -EPERM; | |
5061 | } | |
5062 | ||
5063 | static int | |
5064 | awe_midi_outputc (int dev, unsigned char midi_byte) | |
5065 | { | |
5066 | if (! midi_opened) | |
5067 | return 1; | |
5068 | ||
5069 | /* force to change playing mode */ | |
5070 | playing_mode = AWE_PLAY_MULTI; | |
5071 | ||
5072 | get_midi_char(&curst, midi_byte); | |
5073 | return 1; | |
5074 | } | |
5075 | ||
5076 | ||
5077 | /* | |
5078 | * initialize | |
5079 | */ | |
5080 | ||
5081 | static void init_midi_status(MidiStatus *st) | |
5082 | { | |
5083 | clear_rpn(); | |
5084 | coarsetune = 0; | |
5085 | finetune = 0; | |
5086 | } | |
5087 | ||
5088 | ||
5089 | /* | |
5090 | * RPN & NRPN | |
5091 | */ | |
5092 | ||
5093 | #define MAX_MIDI_CHANNELS 16 | |
5094 | ||
5095 | /* RPN & NRPN */ | |
5096 | static unsigned char nrpn[MAX_MIDI_CHANNELS]; /* current event is NRPN? */ | |
5097 | static int msb_bit; /* current event is msb for RPN/NRPN */ | |
5098 | /* RPN & NRPN indeces */ | |
5099 | static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS]; | |
5100 | /* RPN & NRPN values */ | |
5101 | static int rpn_val[MAX_MIDI_CHANNELS]; | |
5102 | ||
5103 | static void clear_rpn(void) | |
5104 | { | |
5105 | int i; | |
5106 | for (i = 0; i < MAX_MIDI_CHANNELS; i++) { | |
5107 | nrpn[i] = 0; | |
5108 | rpn_msb[i] = 127; | |
5109 | rpn_lsb[i] = 127; | |
5110 | rpn_val[i] = 0; | |
5111 | } | |
5112 | msb_bit = 0; | |
5113 | } | |
5114 | ||
5115 | ||
5116 | /* | |
5117 | * process midi queue | |
5118 | */ | |
5119 | ||
5120 | /* status event types */ | |
5121 | typedef void (*StatusEvent)(MidiStatus *st); | |
5122 | static struct StatusEventList { | |
5123 | StatusEvent process; | |
5124 | int qlen; | |
5125 | } status_event[8] = { | |
5126 | {midi_note_off, 2}, | |
5127 | {midi_note_on, 2}, | |
5128 | {midi_key_pressure, 2}, | |
5129 | {midi_control_change, 2}, | |
5130 | {midi_program_change, 1}, | |
5131 | {midi_channel_pressure, 1}, | |
5132 | {midi_pitch_wheel, 2}, | |
5133 | {NULL, 0}, | |
5134 | }; | |
5135 | ||
5136 | ||
5137 | /* read a char from fifo and process it */ | |
5138 | static void get_midi_char(MidiStatus *st, int c) | |
5139 | { | |
5140 | if (c == 0xfe) { | |
5141 | /* ignore active sense */ | |
5142 | st->queue = Q_NONE; | |
5143 | return; | |
5144 | } | |
5145 | ||
5146 | switch (st->queue) { | |
5147 | /* case Q_VARLEN: queue_varlen(st, c); break;*/ | |
5148 | case Q_READ: | |
5149 | case Q_SYSEX: | |
5150 | queue_read(st, c); | |
5151 | break; | |
5152 | case Q_NONE: | |
5153 | st->read = 0; | |
5154 | if ((c & 0xf0) == 0xf0) { | |
5155 | special_event(st, c); | |
5156 | } else if (c & 0x80) { /* status change */ | |
5157 | st->status = (c >> 4) & 0x07; | |
5158 | st->chan = c & 0x0f; | |
5159 | st->queue = Q_READ; | |
5160 | st->qlen = status_event[st->status].qlen; | |
5161 | if (st->qlen == 0) | |
5162 | st->queue = Q_NONE; | |
5163 | } | |
5164 | break; | |
5165 | } | |
5166 | } | |
5167 | ||
5168 | /* 0xfx events */ | |
5169 | static void special_event(MidiStatus *st, int c) | |
5170 | { | |
5171 | switch (c) { | |
5172 | case 0xf0: /* system exclusive */ | |
5173 | st->queue = Q_SYSEX; | |
5174 | st->qlen = 0; | |
5175 | break; | |
5176 | case 0xf1: /* MTC quarter frame */ | |
5177 | case 0xf3: /* song select */ | |
5178 | st->queue = Q_READ; | |
5179 | st->qlen = 1; | |
5180 | break; | |
5181 | case 0xf2: /* song position */ | |
5182 | st->queue = Q_READ; | |
5183 | st->qlen = 2; | |
5184 | break; | |
5185 | } | |
5186 | } | |
5187 | ||
5188 | #if 0 | |
5189 | /* read variable length value */ | |
5190 | static void queue_varlen(MidiStatus *st, int c) | |
5191 | { | |
5192 | st->qlen += (c & 0x7f); | |
5193 | if (c & 0x80) { | |
5194 | st->qlen <<= 7; | |
5195 | return; | |
5196 | } | |
5197 | if (st->qlen <= 0) { | |
5198 | st->qlen = 0; | |
5199 | st->queue = Q_NONE; | |
5200 | } | |
5201 | st->queue = Q_READ; | |
5202 | st->read = 0; | |
5203 | } | |
5204 | #endif | |
5205 | ||
5206 | ||
5207 | /* read a char */ | |
5208 | static void queue_read(MidiStatus *st, int c) | |
5209 | { | |
5210 | if (st->read < MAX_MIDIBUF) { | |
5211 | if (st->queue != Q_SYSEX) | |
5212 | c &= 0x7f; | |
5213 | st->buf[st->read] = (unsigned char)c; | |
5214 | } | |
5215 | st->read++; | |
5216 | if (st->queue == Q_SYSEX && c == 0xf7) { | |
5217 | midi_system_exclusive(st); | |
5218 | st->queue = Q_NONE; | |
5219 | } else if (st->queue == Q_READ && st->read >= st->qlen) { | |
5220 | if (status_event[st->status].process) | |
5221 | status_event[st->status].process(st); | |
5222 | st->queue = Q_NONE; | |
5223 | } | |
5224 | } | |
5225 | ||
5226 | ||
5227 | /* | |
5228 | * status events | |
5229 | */ | |
5230 | ||
5231 | /* note on */ | |
5232 | static void midi_note_on(MidiStatus *st) | |
5233 | { | |
5234 | DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1])); | |
5235 | if (st->buf[1] == 0) | |
5236 | midi_note_off(st); | |
5237 | else | |
5238 | awe_start_note(0, st->chan, st->buf[0], st->buf[1]); | |
5239 | } | |
5240 | ||
5241 | /* note off */ | |
5242 | static void midi_note_off(MidiStatus *st) | |
5243 | { | |
5244 | DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1])); | |
5245 | awe_kill_note(0, st->chan, st->buf[0], st->buf[1]); | |
5246 | } | |
5247 | ||
5248 | /* key pressure change */ | |
5249 | static void midi_key_pressure(MidiStatus *st) | |
5250 | { | |
5251 | awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]); | |
5252 | } | |
5253 | ||
5254 | /* channel pressure change */ | |
5255 | static void midi_channel_pressure(MidiStatus *st) | |
5256 | { | |
5257 | channels[st->chan].chan_press = st->buf[0]; | |
5258 | awe_modwheel_change(st->chan, st->buf[0]); | |
5259 | } | |
5260 | ||
5261 | /* pitch wheel change */ | |
5262 | static void midi_pitch_wheel(MidiStatus *st) | |
5263 | { | |
5264 | int val = (int)st->buf[1] * 128 + st->buf[0]; | |
5265 | awe_bender(0, st->chan, val); | |
5266 | } | |
5267 | ||
5268 | /* program change */ | |
5269 | static void midi_program_change(MidiStatus *st) | |
5270 | { | |
5271 | int preset; | |
5272 | preset = st->buf[0]; | |
5273 | if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127) | |
5274 | preset = 0; | |
5275 | else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan)) | |
5276 | preset += 64; | |
5277 | ||
5278 | awe_set_instr(0, st->chan, preset); | |
5279 | } | |
5280 | ||
5281 | #define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val) | |
5282 | #define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val) | |
5283 | #define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0) | |
5284 | ||
5285 | /* midi control change */ | |
5286 | static void midi_control_change(MidiStatus *st) | |
5287 | { | |
5288 | int cmd = st->buf[0]; | |
5289 | int val = st->buf[1]; | |
5290 | ||
5291 | DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val)); | |
5292 | if (midi_mode == MODE_XG) { | |
5293 | if (xg_control_change(st, cmd, val)) | |
5294 | return; | |
5295 | } | |
5296 | ||
5297 | /* controls #31 - #64 are LSB of #0 - #31 */ | |
5298 | msb_bit = 1; | |
5299 | if (cmd >= 0x20 && cmd < 0x40) { | |
5300 | msb_bit = 0; | |
5301 | cmd -= 0x20; | |
5302 | } | |
5303 | ||
5304 | switch (cmd) { | |
5305 | case CTL_SOFT_PEDAL: | |
5306 | if (val == 127) | |
5307 | add_effect(st->chan, AWE_FX_CUTOFF, -160); | |
5308 | else | |
5309 | unset_effect(st->chan, AWE_FX_CUTOFF); | |
5310 | break; | |
5311 | ||
5312 | case CTL_BANK_SELECT: | |
5313 | midi_select_bank(st, val); | |
5314 | break; | |
5315 | ||
5316 | /* set RPN/NRPN parameter */ | |
5317 | case CTL_REGIST_PARM_NUM_MSB: | |
5318 | nrpn[st->chan]=0; rpn_msb[st->chan]=val; | |
5319 | break; | |
5320 | case CTL_REGIST_PARM_NUM_LSB: | |
5321 | nrpn[st->chan]=0; rpn_lsb[st->chan]=val; | |
5322 | break; | |
5323 | case CTL_NONREG_PARM_NUM_MSB: | |
5324 | nrpn[st->chan]=1; rpn_msb[st->chan]=val; | |
5325 | break; | |
5326 | case CTL_NONREG_PARM_NUM_LSB: | |
5327 | nrpn[st->chan]=1; rpn_lsb[st->chan]=val; | |
5328 | break; | |
5329 | ||
5330 | /* send RPN/NRPN entry */ | |
5331 | case CTL_DATA_ENTRY: | |
5332 | if (msb_bit) | |
5333 | rpn_val[st->chan] = val * 128; | |
5334 | else | |
5335 | rpn_val[st->chan] |= val; | |
5336 | if (nrpn[st->chan]) | |
5337 | midi_nrpn_event(st); | |
5338 | else | |
5339 | midi_rpn_event(st); | |
5340 | break; | |
5341 | ||
5342 | /* increase/decrease data entry */ | |
5343 | case CTL_DATA_INCREMENT: | |
5344 | rpn_val[st->chan]++; | |
5345 | midi_rpn_event(st); | |
5346 | break; | |
5347 | case CTL_DATA_DECREMENT: | |
5348 | rpn_val[st->chan]--; | |
5349 | midi_rpn_event(st); | |
5350 | break; | |
5351 | ||
5352 | /* default */ | |
5353 | default: | |
5354 | awe_controller(0, st->chan, cmd, val); | |
5355 | break; | |
5356 | } | |
5357 | } | |
5358 | ||
5359 | /* tone bank change */ | |
5360 | static void midi_select_bank(MidiStatus *st, int val) | |
5361 | { | |
5362 | if (midi_mode == MODE_XG && msb_bit) { | |
5363 | xg_bankmode = val; | |
5364 | /* XG MSB value; not normal bank selection */ | |
5365 | switch (val) { | |
5366 | case 127: /* remap to drum channel */ | |
5367 | awe_controller(0, st->chan, CTL_BANK_SELECT, 128); | |
5368 | break; | |
5369 | default: /* remap to normal channel */ | |
5370 | awe_controller(0, st->chan, CTL_BANK_SELECT, val); | |
5371 | break; | |
5372 | } | |
5373 | return; | |
5374 | } else if (midi_mode == MODE_GS && !msb_bit) | |
5375 | /* ignore LSB bank in GS mode (used for mapping) */ | |
5376 | return; | |
5377 | ||
5378 | /* normal bank controls; accept both MSB and LSB */ | |
5379 | if (! IS_DRUM_CHANNEL(st->chan)) { | |
5380 | if (midi_mode == MODE_XG) { | |
5381 | if (xg_bankmode) return; | |
5382 | if (val == 64 || val == 126) | |
5383 | val = 0; | |
5384 | } else if (midi_mode == MODE_GS && val == 127) | |
5385 | val = 0; | |
5386 | awe_controller(0, st->chan, CTL_BANK_SELECT, val); | |
5387 | } | |
5388 | } | |
5389 | ||
5390 | ||
5391 | /* | |
5392 | * RPN events | |
5393 | */ | |
5394 | ||
5395 | static void midi_rpn_event(MidiStatus *st) | |
5396 | { | |
5397 | int type; | |
5398 | type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan]; | |
5399 | switch (type) { | |
5400 | case 0x0000: /* Pitch bend sensitivity */ | |
5401 | /* MSB only / 1 semitone per 128 */ | |
5402 | if (msb_bit) { | |
5403 | channels[st->chan].bender_range = | |
5404 | rpn_val[st->chan] * 100 / 128; | |
5405 | } | |
5406 | break; | |
5407 | ||
5408 | case 0x0001: /* fine tuning: */ | |
5409 | /* MSB/LSB, 8192=center, 100/8192 cent step */ | |
5410 | finetune = rpn_val[st->chan] - 8192; | |
5411 | midi_detune(st->chan, coarsetune, finetune); | |
5412 | break; | |
5413 | ||
5414 | case 0x0002: /* coarse tuning */ | |
5415 | /* MSB only / 8192=center, 1 semitone per 128 */ | |
5416 | if (msb_bit) { | |
5417 | coarsetune = rpn_val[st->chan] - 8192; | |
5418 | midi_detune(st->chan, coarsetune, finetune); | |
5419 | } | |
5420 | break; | |
5421 | ||
5422 | case 0x7F7F: /* "lock-in" RPN */ | |
5423 | break; | |
5424 | } | |
5425 | } | |
5426 | ||
5427 | ||
5428 | /* tuning: | |
5429 | * coarse = -8192 to 8192 (100 cent per 128) | |
5430 | * fine = -8192 to 8192 (max=100cent) | |
5431 | */ | |
5432 | static void midi_detune(int chan, int coarse, int fine) | |
5433 | { | |
5434 | /* 4096 = 1200 cents in AWE parameter */ | |
5435 | int val; | |
5436 | val = coarse * 4096 / (12 * 128); | |
5437 | val += fine / 24; | |
5438 | if (val) | |
5439 | send_effect(chan, AWE_FX_INIT_PITCH, val); | |
5440 | else | |
5441 | unset_effect(chan, AWE_FX_INIT_PITCH); | |
5442 | } | |
5443 | ||
5444 | ||
5445 | /* | |
5446 | * system exclusive message | |
5447 | * GM/GS/XG macros are accepted | |
5448 | */ | |
5449 | ||
5450 | static void midi_system_exclusive(MidiStatus *st) | |
5451 | { | |
5452 | /* GM on */ | |
5453 | static unsigned char gm_on_macro[] = { | |
5454 | 0x7e,0x7f,0x09,0x01, | |
5455 | }; | |
5456 | /* XG on */ | |
5457 | static unsigned char xg_on_macro[] = { | |
5458 | 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00, | |
5459 | }; | |
5460 | /* GS prefix | |
5461 | * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off | |
5462 | * reverb mode: XX=0x01, YY=0x30, ZZ=0-7 | |
5463 | * chorus mode: XX=0x01, YY=0x38, ZZ=0-7 | |
5464 | */ | |
5465 | static unsigned char gs_pfx_macro[] = { | |
5466 | 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/ | |
5467 | }; | |
5468 | ||
5469 | #if 0 | |
5470 | /* SC88 system mode set | |
5471 | * single module mode: XX=1 | |
5472 | * double module mode: XX=0 | |
5473 | */ | |
5474 | static unsigned char gs_mode_macro[] = { | |
5475 | 0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/ | |
5476 | }; | |
5477 | /* SC88 display macro: XX=01:bitmap, 00:text | |
5478 | */ | |
5479 | static unsigned char gs_disp_macro[] = { | |
5480 | 0x41,0x10,0x45,0x12,0x10,/*XX,00*/ | |
5481 | }; | |
5482 | #endif | |
5483 | ||
5484 | /* GM on */ | |
5485 | if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) { | |
5486 | if (midi_mode != MODE_GS && midi_mode != MODE_XG) | |
5487 | midi_mode = MODE_GM; | |
5488 | init_midi_status(st); | |
5489 | } | |
5490 | ||
5491 | /* GS macros */ | |
5492 | else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) { | |
5493 | if (midi_mode != MODE_GS && midi_mode != MODE_XG) | |
5494 | midi_mode = MODE_GS; | |
5495 | ||
5496 | if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) { | |
5497 | /* GS reset */ | |
5498 | init_midi_status(st); | |
5499 | } | |
5500 | ||
5501 | else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) { | |
5502 | /* drum pattern */ | |
5503 | int p = st->buf[5] & 0x0f; | |
5504 | if (p == 0) p = 9; | |
5505 | else if (p < 10) p--; | |
5506 | if (st->buf[7] == 0) | |
5507 | DRUM_CHANNEL_OFF(p); | |
5508 | else | |
5509 | DRUM_CHANNEL_ON(p); | |
5510 | ||
5511 | } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) { | |
5512 | /* program */ | |
5513 | int p = st->buf[5] & 0x0f; | |
5514 | if (p == 0) p = 9; | |
5515 | else if (p < 10) p--; | |
5516 | if (! IS_DRUM_CHANNEL(p)) | |
5517 | awe_set_instr(0, p, st->buf[7]); | |
5518 | ||
5519 | } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) { | |
5520 | /* reverb mode */ | |
5521 | awe_set_reverb_mode(st->buf[7]); | |
5522 | ||
5523 | } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) { | |
5524 | /* chorus mode */ | |
5525 | awe_set_chorus_mode(st->buf[7]); | |
5526 | ||
5527 | } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) { | |
5528 | /* master volume */ | |
5529 | awe_change_master_volume(st->buf[7]); | |
5530 | ||
5531 | } | |
5532 | } | |
5533 | ||
5534 | /* XG on */ | |
5535 | else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) { | |
5536 | midi_mode = MODE_XG; | |
5537 | xg_mapping = TRUE; | |
5538 | xg_bankmode = 0; | |
5539 | } | |
5540 | } | |
5541 | ||
5542 | ||
5543 | /*----------------------------------------------------------------*/ | |
5544 | ||
5545 | /* | |
5546 | * convert NRPN/control values | |
5547 | */ | |
5548 | ||
5549 | static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val) | |
5550 | { | |
5551 | int i, cval; | |
5552 | for (i = 0; i < num_tables; i++) { | |
5553 | if (table[i].control == type) { | |
5554 | cval = table[i].convert(val); | |
5555 | send_effect(st->chan, table[i].awe_effect, cval); | |
5556 | return TRUE; | |
5557 | } | |
5558 | } | |
5559 | return FALSE; | |
5560 | } | |
5561 | ||
5562 | static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val) | |
5563 | { | |
5564 | int i, cval; | |
5565 | for (i = 0; i < num_tables; i++) { | |
5566 | if (table[i].control == type) { | |
5567 | cval = table[i].convert(val); | |
5568 | add_effect(st->chan, table[i].awe_effect|0x80, cval); | |
5569 | return TRUE; | |
5570 | } | |
5571 | } | |
5572 | return FALSE; | |
5573 | } | |
5574 | ||
5575 | ||
5576 | /* | |
5577 | * AWE32 NRPN effects | |
5578 | */ | |
5579 | ||
5580 | static unsigned short fx_delay(int val); | |
5581 | static unsigned short fx_attack(int val); | |
5582 | static unsigned short fx_hold(int val); | |
5583 | static unsigned short fx_decay(int val); | |
5584 | static unsigned short fx_the_value(int val); | |
5585 | static unsigned short fx_twice_value(int val); | |
5586 | static unsigned short fx_conv_pitch(int val); | |
5587 | static unsigned short fx_conv_Q(int val); | |
5588 | ||
5589 | /* function for each NRPN */ /* [range] units */ | |
5590 | #define fx_env1_delay fx_delay /* [0,5900] 4msec */ | |
5591 | #define fx_env1_attack fx_attack /* [0,5940] 1msec */ | |
5592 | #define fx_env1_hold fx_hold /* [0,8191] 1msec */ | |
5593 | #define fx_env1_decay fx_decay /* [0,5940] 4msec */ | |
5594 | #define fx_env1_release fx_decay /* [0,5940] 4msec */ | |
5595 | #define fx_env1_sustain fx_the_value /* [0,127] 0.75dB */ | |
5596 | #define fx_env1_pitch fx_the_value /* [-127,127] 9.375cents */ | |
5597 | #define fx_env1_cutoff fx_the_value /* [-127,127] 56.25cents */ | |
5598 | ||
5599 | #define fx_env2_delay fx_delay /* [0,5900] 4msec */ | |
5600 | #define fx_env2_attack fx_attack /* [0,5940] 1msec */ | |
5601 | #define fx_env2_hold fx_hold /* [0,8191] 1msec */ | |
5602 | #define fx_env2_decay fx_decay /* [0,5940] 4msec */ | |
5603 | #define fx_env2_release fx_decay /* [0,5940] 4msec */ | |
5604 | #define fx_env2_sustain fx_the_value /* [0,127] 0.75dB */ | |
5605 | ||
5606 | #define fx_lfo1_delay fx_delay /* [0,5900] 4msec */ | |
5607 | #define fx_lfo1_freq fx_twice_value /* [0,127] 84mHz */ | |
5608 | #define fx_lfo1_volume fx_twice_value /* [0,127] 0.1875dB */ | |
5609 | #define fx_lfo1_pitch fx_the_value /* [-127,127] 9.375cents */ | |
5610 | #define fx_lfo1_cutoff fx_twice_value /* [-64,63] 56.25cents */ | |
5611 | ||
5612 | #define fx_lfo2_delay fx_delay /* [0,5900] 4msec */ | |
5613 | #define fx_lfo2_freq fx_twice_value /* [0,127] 84mHz */ | |
5614 | #define fx_lfo2_pitch fx_the_value /* [-127,127] 9.375cents */ | |
5615 | ||
5616 | #define fx_init_pitch fx_conv_pitch /* [-8192,8192] cents */ | |
5617 | #define fx_chorus fx_the_value /* [0,255] -- */ | |
5618 | #define fx_reverb fx_the_value /* [0,255] -- */ | |
5619 | #define fx_cutoff fx_twice_value /* [0,127] 62Hz */ | |
5620 | #define fx_filterQ fx_conv_Q /* [0,127] -- */ | |
5621 | ||
5622 | static unsigned short fx_delay(int val) | |
5623 | { | |
5624 | return (unsigned short)calc_parm_delay(val); | |
5625 | } | |
5626 | ||
5627 | static unsigned short fx_attack(int val) | |
5628 | { | |
5629 | return (unsigned short)calc_parm_attack(val); | |
5630 | } | |
5631 | ||
5632 | static unsigned short fx_hold(int val) | |
5633 | { | |
5634 | return (unsigned short)calc_parm_hold(val); | |
5635 | } | |
5636 | ||
5637 | static unsigned short fx_decay(int val) | |
5638 | { | |
5639 | return (unsigned short)calc_parm_decay(val); | |
5640 | } | |
5641 | ||
5642 | static unsigned short fx_the_value(int val) | |
5643 | { | |
5644 | return (unsigned short)(val & 0xff); | |
5645 | } | |
5646 | ||
5647 | static unsigned short fx_twice_value(int val) | |
5648 | { | |
5649 | return (unsigned short)((val * 2) & 0xff); | |
5650 | } | |
5651 | ||
5652 | static unsigned short fx_conv_pitch(int val) | |
5653 | { | |
5654 | return (short)(val * 4096 / 1200); | |
5655 | } | |
5656 | ||
5657 | static unsigned short fx_conv_Q(int val) | |
5658 | { | |
5659 | return (unsigned short)((val / 8) & 0xff); | |
5660 | } | |
5661 | ||
5662 | ||
5663 | static ConvTable awe_effects[] = | |
5664 | { | |
5665 | { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay}, | |
5666 | { 1, AWE_FX_LFO1_FREQ, fx_lfo1_freq}, | |
5667 | { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay}, | |
5668 | { 3, AWE_FX_LFO2_FREQ, fx_lfo2_freq}, | |
5669 | ||
5670 | { 4, AWE_FX_ENV1_DELAY, fx_env1_delay}, | |
5671 | { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack}, | |
5672 | { 6, AWE_FX_ENV1_HOLD, fx_env1_hold}, | |
5673 | { 7, AWE_FX_ENV1_DECAY, fx_env1_decay}, | |
5674 | { 8, AWE_FX_ENV1_SUSTAIN, fx_env1_sustain}, | |
5675 | { 9, AWE_FX_ENV1_RELEASE, fx_env1_release}, | |
5676 | ||
5677 | {10, AWE_FX_ENV2_DELAY, fx_env2_delay}, | |
5678 | {11, AWE_FX_ENV2_ATTACK, fx_env2_attack}, | |
5679 | {12, AWE_FX_ENV2_HOLD, fx_env2_hold}, | |
5680 | {13, AWE_FX_ENV2_DECAY, fx_env2_decay}, | |
5681 | {14, AWE_FX_ENV2_SUSTAIN, fx_env2_sustain}, | |
5682 | {15, AWE_FX_ENV2_RELEASE, fx_env2_release}, | |
5683 | ||
5684 | {16, AWE_FX_INIT_PITCH, fx_init_pitch}, | |
5685 | {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch}, | |
5686 | {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch}, | |
5687 | {19, AWE_FX_ENV1_PITCH, fx_env1_pitch}, | |
5688 | {20, AWE_FX_LFO1_VOLUME, fx_lfo1_volume}, | |
5689 | {21, AWE_FX_CUTOFF, fx_cutoff}, | |
5690 | {22, AWE_FX_FILTERQ, fx_filterQ}, | |
5691 | {23, AWE_FX_LFO1_CUTOFF, fx_lfo1_cutoff}, | |
5692 | {24, AWE_FX_ENV1_CUTOFF, fx_env1_cutoff}, | |
5693 | {25, AWE_FX_CHORUS, fx_chorus}, | |
5694 | {26, AWE_FX_REVERB, fx_reverb}, | |
5695 | }; | |
5696 | ||
5697 | static int num_awe_effects = numberof(awe_effects); | |
5698 | ||
5699 | ||
5700 | /* | |
5701 | * GS(SC88) NRPN effects; still experimental | |
5702 | */ | |
5703 | ||
5704 | /* cutoff: quarter semitone step, max=255 */ | |
5705 | static unsigned short gs_cutoff(int val) | |
5706 | { | |
5707 | return (val - 64) * gs_sense[FX_CUTOFF] / 50; | |
5708 | } | |
5709 | ||
5710 | /* resonance: 0 to 15(max) */ | |
5711 | static unsigned short gs_filterQ(int val) | |
5712 | { | |
5713 | return (val - 64) * gs_sense[FX_RESONANCE] / 50; | |
5714 | } | |
5715 | ||
5716 | /* attack: */ | |
5717 | static unsigned short gs_attack(int val) | |
5718 | { | |
5719 | return -(val - 64) * gs_sense[FX_ATTACK] / 50; | |
5720 | } | |
5721 | ||
5722 | /* decay: */ | |
5723 | static unsigned short gs_decay(int val) | |
5724 | { | |
5725 | return -(val - 64) * gs_sense[FX_RELEASE] / 50; | |
5726 | } | |
5727 | ||
5728 | /* release: */ | |
5729 | static unsigned short gs_release(int val) | |
5730 | { | |
5731 | return -(val - 64) * gs_sense[FX_RELEASE] / 50; | |
5732 | } | |
5733 | ||
5734 | /* vibrato freq: 0.042Hz step, max=255 */ | |
5735 | static unsigned short gs_vib_rate(int val) | |
5736 | { | |
5737 | return (val - 64) * gs_sense[FX_VIBRATE] / 50; | |
5738 | } | |
5739 | ||
5740 | /* vibrato depth: max=127, 1 octave */ | |
5741 | static unsigned short gs_vib_depth(int val) | |
5742 | { | |
5743 | return (val - 64) * gs_sense[FX_VIBDEPTH] / 50; | |
5744 | } | |
5745 | ||
5746 | /* vibrato delay: -0.725msec step */ | |
5747 | static unsigned short gs_vib_delay(int val) | |
5748 | { | |
5749 | return -(val - 64) * gs_sense[FX_VIBDELAY] / 50; | |
5750 | } | |
5751 | ||
5752 | static ConvTable gs_effects[] = | |
5753 | { | |
5754 | {32, AWE_FX_CUTOFF, gs_cutoff}, | |
5755 | {33, AWE_FX_FILTERQ, gs_filterQ}, | |
5756 | {99, AWE_FX_ENV2_ATTACK, gs_attack}, | |
5757 | {100, AWE_FX_ENV2_DECAY, gs_decay}, | |
5758 | {102, AWE_FX_ENV2_RELEASE, gs_release}, | |
5759 | {8, AWE_FX_LFO1_FREQ, gs_vib_rate}, | |
5760 | {9, AWE_FX_LFO1_VOLUME, gs_vib_depth}, | |
5761 | {10, AWE_FX_LFO1_DELAY, gs_vib_delay}, | |
5762 | }; | |
5763 | ||
5764 | static int num_gs_effects = numberof(gs_effects); | |
5765 | ||
5766 | ||
5767 | /* | |
5768 | * NRPN events: accept as AWE32/SC88 specific controls | |
5769 | */ | |
5770 | ||
5771 | static void midi_nrpn_event(MidiStatus *st) | |
5772 | { | |
5773 | if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) { | |
5774 | if (! msb_bit) /* both MSB/LSB necessary */ | |
5775 | send_converted_effect(awe_effects, num_awe_effects, | |
5776 | st, rpn_lsb[st->chan], | |
5777 | rpn_val[st->chan] - 8192); | |
5778 | } else if (rpn_msb[st->chan] == 1) { | |
5779 | if (msb_bit) /* only MSB is valid */ | |
5780 | add_converted_effect(gs_effects, num_gs_effects, | |
5781 | st, rpn_lsb[st->chan], | |
5782 | rpn_val[st->chan] / 128); | |
5783 | } | |
5784 | } | |
5785 | ||
5786 | ||
5787 | /* | |
5788 | * XG control effects; still experimental | |
5789 | */ | |
5790 | ||
5791 | /* cutoff: quarter semitone step, max=255 */ | |
5792 | static unsigned short xg_cutoff(int val) | |
5793 | { | |
5794 | return (val - 64) * xg_sense[FX_CUTOFF] / 64; | |
5795 | } | |
5796 | ||
5797 | /* resonance: 0(open) to 15(most nasal) */ | |
5798 | static unsigned short xg_filterQ(int val) | |
5799 | { | |
5800 | return (val - 64) * xg_sense[FX_RESONANCE] / 64; | |
5801 | } | |
5802 | ||
5803 | /* attack: */ | |
5804 | static unsigned short xg_attack(int val) | |
5805 | { | |
5806 | return -(val - 64) * xg_sense[FX_ATTACK] / 64; | |
5807 | } | |
5808 | ||
5809 | /* release: */ | |
5810 | static unsigned short xg_release(int val) | |
5811 | { | |
5812 | return -(val - 64) * xg_sense[FX_RELEASE] / 64; | |
5813 | } | |
5814 | ||
5815 | static ConvTable xg_effects[] = | |
5816 | { | |
5817 | {71, AWE_FX_CUTOFF, xg_cutoff}, | |
5818 | {74, AWE_FX_FILTERQ, xg_filterQ}, | |
5819 | {72, AWE_FX_ENV2_RELEASE, xg_release}, | |
5820 | {73, AWE_FX_ENV2_ATTACK, xg_attack}, | |
5821 | }; | |
5822 | ||
5823 | static int num_xg_effects = numberof(xg_effects); | |
5824 | ||
5825 | static int xg_control_change(MidiStatus *st, int cmd, int val) | |
5826 | { | |
5827 | return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val); | |
5828 | } | |
5829 | ||
5830 | #endif /* CONFIG_AWE32_MIDIEMU */ | |
5831 | ||
5832 | ||
5833 | /*----------------------------------------------------------------*/ | |
5834 | ||
5835 | ||
5836 | /* | |
5837 | * initialization of AWE driver | |
5838 | */ | |
5839 | ||
5840 | static void | |
5841 | awe_initialize(void) | |
5842 | { | |
5843 | DEBUG(0,printk("AWE32: initializing..\n")); | |
5844 | ||
5845 | /* initialize hardware configuration */ | |
5846 | awe_poke(AWE_HWCF1, 0x0059); | |
5847 | awe_poke(AWE_HWCF2, 0x0020); | |
5848 | ||
5849 | /* disable audio; this seems to reduce a clicking noise a bit.. */ | |
5850 | awe_poke(AWE_HWCF3, 0); | |
5851 | ||
5852 | /* initialize audio channels */ | |
5853 | awe_init_audio(); | |
5854 | ||
5855 | /* initialize DMA */ | |
5856 | awe_init_dma(); | |
5857 | ||
5858 | /* initialize init array */ | |
5859 | awe_init_array(); | |
5860 | ||
5861 | /* check DRAM memory size */ | |
5862 | awe_check_dram(); | |
5863 | ||
5864 | /* initialize the FM section of the AWE32 */ | |
5865 | awe_init_fm(); | |
5866 | ||
5867 | /* set up voice envelopes */ | |
5868 | awe_tweak(); | |
5869 | ||
5870 | /* enable audio */ | |
5871 | awe_poke(AWE_HWCF3, 0x0004); | |
5872 | ||
5873 | /* set default values */ | |
5874 | awe_init_ctrl_parms(TRUE); | |
5875 | ||
5876 | /* set equalizer */ | |
5877 | awe_update_equalizer(); | |
5878 | ||
5879 | /* set reverb & chorus modes */ | |
5880 | awe_update_reverb_mode(); | |
5881 | awe_update_chorus_mode(); | |
5882 | } | |
5883 | ||
5884 | ||
5885 | /* | |
5886 | * Core Device Management Functions | |
5887 | */ | |
5888 | ||
5889 | /* store values to i/o port array */ | |
5890 | static void setup_ports(int port1, int port2, int port3) | |
5891 | { | |
5892 | awe_ports[0] = port1; | |
5893 | if (port2 == 0) | |
5894 | port2 = port1 + 0x400; | |
5895 | awe_ports[1] = port2; | |
5896 | awe_ports[2] = port2 + 2; | |
5897 | if (port3 == 0) | |
5898 | port3 = port1 + 0x800; | |
5899 | awe_ports[3] = port3; | |
5900 | awe_ports[4] = port3 + 2; | |
5901 | ||
5902 | port_setuped = TRUE; | |
5903 | } | |
5904 | ||
5905 | /* | |
5906 | * port request | |
5907 | * 0x620-623, 0xA20-A23, 0xE20-E23 | |
5908 | */ | |
5909 | ||
5910 | static int | |
5911 | awe_request_region(void) | |
5912 | { | |
5913 | if (! port_setuped) | |
5914 | return 0; | |
5915 | if (! request_region(awe_ports[0], 4, "sound driver (AWE32)")) | |
5916 | return 0; | |
5917 | if (! request_region(awe_ports[1], 4, "sound driver (AWE32)")) | |
5918 | goto err_out; | |
5919 | if (! request_region(awe_ports[3], 4, "sound driver (AWE32)")) | |
5920 | goto err_out1; | |
5921 | return 1; | |
5922 | err_out1: | |
5923 | release_region(awe_ports[1], 4); | |
5924 | err_out: | |
5925 | release_region(awe_ports[0], 4); | |
5926 | return 0; | |
5927 | } | |
5928 | ||
5929 | static void | |
5930 | awe_release_region(void) | |
5931 | { | |
5932 | if (! port_setuped) return; | |
5933 | release_region(awe_ports[0], 4); | |
5934 | release_region(awe_ports[1], 4); | |
5935 | release_region(awe_ports[3], 4); | |
5936 | } | |
5937 | ||
5938 | static int awe_attach_device(void) | |
5939 | { | |
5940 | if (awe_present) return 0; /* for OSS38.. called twice? */ | |
5941 | ||
5942 | /* reserve I/O ports for awedrv */ | |
5943 | if (! awe_request_region()) { | |
5944 | printk(KERN_ERR "AWE32: I/O area already used.\n"); | |
5945 | return 0; | |
5946 | } | |
5947 | ||
5948 | /* set buffers to NULL */ | |
5949 | sfhead = sftail = NULL; | |
5950 | ||
5951 | my_dev = sound_alloc_synthdev(); | |
5952 | if (my_dev == -1) { | |
5953 | printk(KERN_ERR "AWE32 Error: too many synthesizers\n"); | |
5954 | awe_release_region(); | |
5955 | return 0; | |
5956 | } | |
5957 | ||
5958 | voice_alloc = &awe_operations.alloc; | |
5959 | voice_alloc->max_voice = awe_max_voices; | |
5960 | synth_devs[my_dev] = &awe_operations; | |
5961 | ||
5962 | #ifdef CONFIG_AWE32_MIXER | |
5963 | attach_mixer(); | |
5964 | #endif | |
5965 | #ifdef CONFIG_AWE32_MIDIEMU | |
5966 | attach_midiemu(); | |
5967 | #endif | |
5968 | ||
5969 | /* clear all samples */ | |
5970 | awe_reset_samples(); | |
5971 | ||
5972 | /* initialize AWE32 hardware */ | |
5973 | awe_initialize(); | |
5974 | ||
5975 | sprintf(awe_info.name, "AWE32-%s (RAM%dk)", | |
5976 | AWEDRV_VERSION, memsize/1024); | |
5977 | printk(KERN_INFO "<SoundBlaster EMU8000 (RAM%dk)>\n", memsize/1024); | |
5978 | ||
5979 | awe_present = TRUE; | |
5980 | ||
5981 | return 1; | |
5982 | } | |
5983 | ||
5984 | static void awe_dettach_device(void) | |
5985 | { | |
5986 | if (awe_present) { | |
5987 | awe_reset_samples(); | |
5988 | awe_release_region(); | |
5989 | free_tables(); | |
5990 | #ifdef CONFIG_AWE32_MIXER | |
5991 | unload_mixer(); | |
5992 | #endif | |
5993 | #ifdef CONFIG_AWE32_MIDIEMU | |
5994 | unload_midiemu(); | |
5995 | #endif | |
5996 | sound_unload_synthdev(my_dev); | |
5997 | awe_present = FALSE; | |
5998 | } | |
5999 | } | |
6000 | ||
6001 | ||
6002 | /* | |
6003 | * Legacy device Probing | |
6004 | */ | |
6005 | ||
6006 | /* detect emu8000 chip on the specified address; from VV's guide */ | |
6007 | ||
6008 | static int __init | |
6009 | awe_detect_base(int addr) | |
6010 | { | |
6011 | setup_ports(addr, 0, 0); | |
6012 | if ((awe_peek(AWE_U1) & 0x000F) != 0x000C) | |
6013 | return 0; | |
6014 | if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058) | |
6015 | return 0; | |
6016 | if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003) | |
6017 | return 0; | |
6018 | DEBUG(0,printk("AWE32 found at %x\n", addr)); | |
6019 | return 1; | |
6020 | } | |
6021 | ||
6022 | static int __init awe_detect_legacy_devices(void) | |
6023 | { | |
6024 | int base; | |
6025 | for (base = 0x620; base <= 0x680; base += 0x20) | |
6026 | if (awe_detect_base(base)) { | |
6027 | awe_attach_device(); | |
6028 | return 1; | |
6029 | } | |
6030 | DEBUG(0,printk("AWE32 Legacy detection failed\n")); | |
6031 | return 0; | |
6032 | } | |
6033 | ||
6034 | ||
6035 | /* | |
6036 | * PnP device Probing | |
6037 | */ | |
6038 | ||
6039 | static struct pnp_device_id awe_pnp_ids[] = { | |
6040 | {.id = "CTL0021", .driver_data = 0}, /* AWE32 WaveTable */ | |
6041 | {.id = "CTL0022", .driver_data = 0}, /* AWE64 WaveTable */ | |
6042 | {.id = "CTL0023", .driver_data = 0}, /* AWE64 Gold WaveTable */ | |
6043 | { } /* terminator */ | |
6044 | }; | |
6045 | ||
6046 | MODULE_DEVICE_TABLE(pnp, awe_pnp_ids); | |
6047 | ||
6048 | static int awe_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) | |
6049 | { | |
6050 | int io1, io2, io3; | |
6051 | ||
6052 | if (awe_present) { | |
6053 | printk(KERN_ERR "AWE32: This driver only supports one AWE32 device, skipping.\n"); | |
6054 | } | |
6055 | ||
6056 | if (!pnp_port_valid(dev,0) || | |
6057 | !pnp_port_valid(dev,1) || | |
6058 | !pnp_port_valid(dev,2)) { | |
6059 | printk(KERN_ERR "AWE32: The PnP device does not have the required resources.\n"); | |
6060 | return -EINVAL; | |
6061 | } | |
6062 | io1 = pnp_port_start(dev,0); | |
6063 | io2 = pnp_port_start(dev,1); | |
6064 | io3 = pnp_port_start(dev,2); | |
6065 | printk(KERN_INFO "AWE32: A PnP Wave Table was detected at IO's %#x,%#x,%#x\n.", | |
6066 | io1, io2, io3); | |
6067 | setup_ports(io1, io2, io3); | |
6068 | ||
6069 | awe_attach_device(); | |
6070 | return 0; | |
6071 | } | |
6072 | ||
6073 | static void awe_pnp_remove(struct pnp_dev *dev) | |
6074 | { | |
6075 | awe_dettach_device(); | |
6076 | } | |
6077 | ||
6078 | static struct pnp_driver awe_pnp_driver = { | |
6079 | .name = "AWE32", | |
6080 | .id_table = awe_pnp_ids, | |
6081 | .probe = awe_pnp_probe, | |
6082 | .remove = awe_pnp_remove, | |
6083 | }; | |
6084 | ||
6085 | static int __init awe_detect_pnp_devices(void) | |
6086 | { | |
6087 | int ret; | |
6088 | ||
6089 | ret = pnp_register_driver(&awe_pnp_driver); | |
6090 | if (ret<0) | |
6091 | printk(KERN_ERR "AWE32: PnP support is unavailable.\n"); | |
6092 | return ret; | |
6093 | } | |
6094 | ||
6095 | ||
6096 | /* | |
6097 | * device / lowlevel (module) interface | |
6098 | */ | |
6099 | ||
6100 | static int __init | |
6101 | awe_detect(void) | |
6102 | { | |
6103 | printk(KERN_INFO "AWE32: Probing for WaveTable...\n"); | |
6104 | if (isapnp) { | |
6105 | if (awe_detect_pnp_devices()>=0) | |
6106 | return 1; | |
6107 | } else | |
6108 | printk(KERN_INFO "AWE32: Skipping PnP detection.\n"); | |
6109 | ||
6110 | if (awe_detect_legacy_devices()) | |
6111 | return 1; | |
6112 | ||
6113 | return 0; | |
6114 | } | |
6115 | ||
6116 | static int __init attach_awe(void) | |
6117 | { | |
6118 | return awe_detect() ? 0 : -ENODEV; | |
6119 | } | |
6120 | ||
6121 | static void __exit unload_awe(void) | |
6122 | { | |
6123 | pnp_unregister_driver(&awe_pnp_driver); | |
6124 | awe_dettach_device(); | |
6125 | } | |
6126 | ||
6127 | ||
6128 | module_init(attach_awe); | |
6129 | module_exit(unload_awe); | |
6130 | ||
6131 | #ifndef MODULE | |
6132 | static int __init setup_awe(char *str) | |
6133 | { | |
6134 | /* io, memsize, isapnp */ | |
6135 | int ints[4]; | |
6136 | ||
6137 | str = get_options(str, ARRAY_SIZE(ints), ints); | |
6138 | ||
6139 | io = ints[1]; | |
6140 | memsize = ints[2]; | |
6141 | isapnp = ints[3]; | |
6142 | ||
6143 | return 1; | |
6144 | } | |
6145 | ||
6146 | __setup("awe=", setup_awe); | |
6147 | #endif |