📄 awe_wave.c
字号:
/* * sound/awe_wave.c * * The low level driver for the AWE32/SB32/AWE64 wave table synth. * version 0.4.4; Jan. 4, 2000 * * Copyright (C) 1996-2000 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/awe_voice.h>#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include <linux/string.h>#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE#include <linux/isapnp.h>#endif#include "sound_config.h"#include "awe_wave.h"#include "awe_hw.h"#ifdef AWE_HAS_GUS_COMPATIBILITY#include "tuning.h"#include <linux/ultrasound.h>#endif/* * debug message */#ifdef AWE_DEBUG_ON#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}#define FATALERR(XXX) XXX#else#define DEBUG(LVL,XXX) /**/#define ERRMSG(XXX) XXX#define FATALERR(XXX) XXX#endif/* * bank and voice record */typedef struct _sf_list sf_list;typedef struct _awe_voice_list awe_voice_list;typedef struct _awe_sample_list awe_sample_list;/* soundfont record */struct _sf_list { unsigned short sf_id; /* id number */ unsigned short type; /* lock & shared flags */ int num_info; /* current info table index */ int num_sample; /* current sample table index */ int mem_ptr; /* current word byte pointer */ awe_voice_list *infos, *last_infos; /* instruments */ awe_sample_list *samples, *last_samples; /* samples */#ifdef AWE_ALLOW_SAMPLE_SHARING sf_list *shared; /* shared list */ unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */#endif sf_list *next, *prev;};/* instrument list */struct _awe_voice_list { awe_voice_info v; /* instrument information */ sf_list *holder; /* parent sf_list of this record */ unsigned char bank, instr; /* preset number information */ char type, disabled; /* type=normal/mapped, disabled=boolean */ awe_voice_list *next; /* linked list with same sf_id */ awe_voice_list *next_instr; /* instrument list */ awe_voice_list *next_bank; /* hash table list */};/* voice list type */#define V_ST_NORMAL 0#define V_ST_MAPPED 1/* sample list */struct _awe_sample_list { awe_sample_info v; /* sample information */ sf_list *holder; /* parent sf_list of this record */ awe_sample_list *next; /* linked list with same sf_id */};/* sample and information table */static int current_sf_id = 0; /* current number of fonts */static int locked_sf_id = 0; /* locked position */static sf_list *sfhead = NULL, *sftail = NULL; /* linked-lists */#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0)#define awe_free_info() (sftail ? sftail->num_info : 0)#define awe_free_sample() (sftail ? sftail->num_sample : 0)#define AWE_MAX_PRESETS 256#define AWE_DEFAULT_PRESET 0#define AWE_DEFAULT_BANK 0#define AWE_DEFAULT_DRUM 0#define AWE_DRUM_BANK 128#define MAX_LAYERS AWE_MAX_VOICES/* preset table index */static awe_voice_list *preset_table[AWE_MAX_PRESETS];/* * voice table *//* effects table */typedef struct FX_Rec { /* channel effects */ unsigned char flags[AWE_FX_END]; short val[AWE_FX_END];} FX_Rec;/* channel parameters */typedef struct _awe_chan_info { int channel; /* channel number */ int bank; /* current tone bank */ int instr; /* current program */ int bender; /* midi pitchbend (-8192 - 8192) */ int bender_range; /* midi bender range (x100) */ int panning; /* panning (0-127) */ int main_vol; /* channel volume (0-127) */ int expression_vol; /* midi expression (0-127) */ int chan_press; /* channel pressure */ int sustained; /* sustain status in MIDI */ FX_Rec fx; /* effects */ FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */} awe_chan_info;/* voice parameters */typedef struct _voice_info { int state;#define AWE_ST_OFF (1<<0) /* no sound */#define AWE_ST_ON (1<<1) /* playing */#define AWE_ST_STANDBY (1<<2) /* stand by for playing */#define AWE_ST_SUSTAINED (1<<3) /* sustained */#define AWE_ST_MARK (1<<4) /* marked for allocation */#define AWE_ST_DRAM (1<<5) /* DRAM read/write */#define AWE_ST_FM (1<<6) /* reserved for FM */#define AWE_ST_RELEASED (1<<7) /* released */ int ch; /* midi channel */ int key; /* internal key for search */ int layer; /* layer number (for channel mode only) */ int time; /* allocated time */ awe_chan_info *cinfo; /* channel info */ int note; /* midi key (0-127) */ int velocity; /* midi velocity (0-127) */ int sostenuto; /* sostenuto on/off */ awe_voice_info *sample; /* assigned voice */ /* EMU8000 parameters */ int apitch; /* pitch parameter */ int avol; /* volume parameter */ int apan; /* panning parameter */ int acutoff; /* cutoff parameter */ short aaux; /* aux word */} voice_info;/* voice information */static voice_info voices[AWE_MAX_VOICES];#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))#define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON)#define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))#define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))/* MIDI channel effects information (for hw control) */static awe_chan_info channels[AWE_MAX_CHANNELS];/* * global variables */#ifndef AWE_DEFAULT_BASE_ADDR#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */#endif#ifndef AWE_DEFAULT_MEM_SIZE#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */#endifint io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULEstatic int isapnp = -1;#elsestatic int isapnp = 0;#endifMODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");MODULE_LICENSE("GPL");MODULE_PARM(io, "i");MODULE_PARM_DESC(io, "base i/o port of Emu8000");MODULE_PARM(memsize, "i");MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");MODULE_PARM(isapnp, "i");MODULE_PARM_DESC(isapnp, "use ISAPnP detection");EXPORT_NO_SYMBOLS;/* DRAM start offset */static int awe_mem_start = AWE_DRAM_OFFSET;/* maximum channels for playing */static int awe_max_voices = AWE_MAX_VOICES;static int patch_opened = 0; /* sample already loaded? */static char atten_relative = FALSE;static short atten_offset = 0;static int awe_present = FALSE; /* awe device present? */static int awe_busy = FALSE; /* awe device opened? */static int my_dev = -1; #define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25))#define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c)))#define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c)))#define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c)))static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */static int playing_mode = AWE_PLAY_INDIRECT;#define SINGLE_LAYER_MODE() (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT)#define MULTI_LAYER_MODE() (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2)static int current_alloc_time = 0; /* voice allocation index for channel mode */static struct synth_info awe_info = { "AWE32 Synth", /* name */ 0, /* device */ SYNTH_TYPE_SAMPLE, /* synth_type */ SAMPLE_TYPE_AWE32, /* synth_subtype */ 0, /* perc_mode (obsolete) */ AWE_MAX_VOICES, /* nr_voices */ 0, /* nr_drums (obsolete) */ 400 /* instr_bank_size */};static struct voice_alloc_info *voice_alloc; /* set at initialization *//* * function prototypes */static int awe_check_port(void);static void awe_request_region(void);static void awe_release_region(void);static void awe_reset_samples(void);/* emu8000 chip i/o access */static void setup_ports(int p1, int p2, int p3);static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data);static unsigned short awe_peek(unsigned short cmd, unsigned short port);static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port);static void awe_wait(unsigned short delay);/* initialize emu8000 chip */static int _attach_awe(void);static void _unload_awe(void);static void awe_initialize(void);/* set voice parameters */static void awe_init_ctrl_parms(int init_all);static void awe_init_voice_info(awe_voice_info *vp);static void awe_init_voice_parm(awe_voice_parm *pp);#ifdef AWE_HAS_GUS_COMPATIBILITYstatic int freq_to_note(int freq);static int calc_rate_offset(int Hz);/*static int calc_parm_delay(int msec);*/static int calc_parm_hold(int msec);static int calc_parm_attack(int msec);static int calc_parm_decay(int msec);static int calc_parm_search(int msec, short *table);#endif /* gus compat *//* turn on/off note */static void awe_note_on(int voice);static void awe_note_off(int voice);static void awe_terminate(int voice);static void awe_exclusive_off(int voice);static void awe_note_off_all(int do_sustain);/* calculate voice parameters */typedef void (*fx_affect_func)(int voice, int forced);static void awe_set_pitch(int voice, int forced);static void awe_set_voice_pitch(int voice, int forced);static void awe_set_volume(int voice, int forced);static void awe_set_voice_vol(int voice, int forced);static void awe_set_pan(int voice, int forced);static void awe_fx_fmmod(int voice, int forced);static void awe_fx_tremfrq(int voice, int forced);static void awe_fx_fm2frq2(int voice, int forced);static void awe_fx_filterQ(int voice, int forced);static void awe_calc_pitch(int voice);#ifdef AWE_HAS_GUS_COMPATIBILITYstatic void awe_calc_pitch_from_freq(int voice, int freq);#endifstatic void awe_calc_volume(int voice);static void awe_update_volume(void);static void awe_change_master_volume(short val);static void awe_voice_init(int voice, int init_all);static void awe_channel_init(int ch, int init_all);static void awe_fx_init(int ch);static void awe_send_effect(int voice, int layer, int type, int val);static void awe_modwheel_change(int voice, int value);/* sequencer interface */static int awe_open(int dev, int mode);static void awe_close(int dev);static int awe_ioctl(int dev, unsigned int cmd, caddr_t arg);static int awe_kill_note(int dev, int voice, int note, int velocity);static int awe_start_note(int dev, int v, int note_num, int volume);static int awe_set_instr(int dev, int voice, int instr_no);static int awe_set_instr_2(int dev, int voice, int instr_no);static void awe_reset(int dev);static void awe_hw_control(int dev, unsigned char *event);static int awe_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag);static void awe_aftertouch(int dev, int voice, int pressure);static void awe_controller(int dev, int voice, int ctrl_num, int value);static void awe_panning(int dev, int voice, int value);static void awe_volume_method(int dev, int mode);static void awe_bender(int dev, int voice, int value);static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);static void awe_setup_voice(int dev, int voice, int chn);#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press)/* hardware controls */#ifdef AWE_HAS_GUS_COMPATIBILITYstatic void awe_hw_gus_control(int dev, int cmd, unsigned char *event);#endifstatic void awe_hw_awe_control(int dev, int cmd, unsigned char *event);static void awe_voice_change(int voice, fx_affect_func func);static void awe_sostenuto_on(int voice, int forced);static void awe_sustain_off(int voice, int forced);static void awe_terminate_and_init(int voice, int forced);/* voice search */static int awe_search_key(int bank, int preset, int note);static awe_voice_list *awe_search_instr(int bank, int preset, int note);static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist);static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);static void awe_alloc_one_voice(int voice, int note, int velocity);static int awe_clear_voice(void);/* load / remove patches */static int awe_open_patch(awe_patch_info *patch, const char *addr, int count);static int awe_close_patch(awe_patch_info *patch, const char *addr, int count);static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count);static int awe_load_info(awe_patch_info *patch, const char *addr, int count);static int awe_remove_info(awe_patch_info *patch, const char *addr, int count);static int awe_load_data(awe_patch_info *patch, const char *addr, int count);static int awe_replace_data(awe_patch_info *patch, const char *addr, int count);static int awe_load_map(awe_patch_info *patch, const char *addr, int count);#ifdef AWE_HAS_GUS_COMPATIBILITYstatic int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag);#endif/*static int awe_probe_info(awe_patch_info *patch, const char *addr, int count);*/static int awe_probe_data(awe_patch_info *patch, const char *addr, int count);static sf_list *check_patch_opened(int type, char *name);static int awe_write_wave_data(const char *addr, int offset, awe_sample_list *sp, int channels);static int awe_create_sf(int type, char *name);static void awe_free_sf(sf_list *sf);static void add_sf_info(sf_list *sf, awe_voice_list *rec);static void add_sf_sample(sf_list *sf, awe_sample_list *smp);static void purge_old_list(awe_voice_list *rec, awe_voice_list *next);static void add_info_list(awe_voice_list *rec);static void awe_remove_samples(int sf_id);static void rebuild_preset_list(void);static short awe_set_sample(awe_voice_list *rec);static awe_sample_list *search_sample_index(sf_list *sf, int sample);static int is_identical_holder(sf_list *sf1, sf_list *sf2);#ifdef AWE_ALLOW_SAMPLE_SHARINGstatic int is_identical_name(unsigned char *name, sf_list *p);static int is_shared_sf(unsigned char *name);static int info_duplicated(sf_list *sf, awe_voice_list *rec);#endif /* allow sharing *//* lowlevel functions */static void awe_init_audio(void);static void awe_init_dma(void);static void awe_init_array(void);static void awe_send_array(unsigned short *data);static void awe_tweak_voice(int voice);static void awe_tweak(void);static void awe_init_fm(void);static int awe_open_dram_for_write(int offset, int channels);static void awe_open_dram_for_check(void);static void awe_close_dram(void);/*static void awe_write_dram(unsigned short c);*/static int awe_detect_base(int addr);static int awe_detect(void);static void awe_check_dram(void);static int awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count);static void awe_set_chorus_mode(int mode);static void awe_update_chorus_mode(void);static int awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count);static void awe_set_reverb_mode(int mode);static void awe_update_reverb_mode(void);static void awe_equalizer(int bass, int treble);static void awe_update_equalizer(void);#ifdef CONFIG_AWE32_MIXERstatic void attach_mixer(void);static void unload_mixer(void);#endif#ifdef CONFIG_AWE32_MIDIEMUstatic void attach_midiemu(void);static void unload_midiemu(void);#endif#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)/* * control parameters */#ifdef AWE_USE_NEW_VOLUME_CALC#define DEF_VOLUME_CALC TRUE#else#define DEF_VOLUME_CALC FALSE#endif /* new volume */#define DEF_ZERO_ATTEN 32 /* 12dB below */#define DEF_MOD_SENSE 18#define DEF_CHORUS_MODE 2#define DEF_REVERB_MODE 4#define DEF_BASS_LEVEL 5#define DEF_TREBLE_LEVEL 9static struct CtrlParmsDef { int value; int init_each_time; void (*update)(void);} ctrl_parms[AWE_MD_END] = { {0,0, NULL}, {0,0, NULL}, /* <-- not used */ {AWE_VERSION_NUMBER, FALSE, NULL}, {TRUE, FALSE, NULL}, /* exclusive */ {TRUE, FALSE, NULL}, /* realpan */ {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */ {FALSE, TRUE, NULL}, /* keep effect */ {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */ {FALSE, FALSE, NULL}, /* chn_prior */ {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */ {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */ {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */ {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */ {FALSE, FALSE, NULL}, /* toggle_drum_bank */ {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */ {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */ {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */ {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */ {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */ {0, FALSE, NULL}, /* debug mode */ {FALSE, FALSE, NULL}, /* pan exchange */};static int ctrls[AWE_MD_END];/* * synth operation table
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -