📄 dosgus.h
字号:
* issue between gus_do_flush (...); this should not be an issue however
* because each voice has a limited (little) set of parameters that
* you can change (freq, vol, pan... what else?)
*
* The pool is a pseudo-CPU code that gets executed once per timer interrupt.
*/
/* Below are definitions for commands placed in GUS command pool */
#define PCMD_NOP 0x00 /* Traditionally ... */
#define PCMD_VOICE 0x01 /* +B: select voice */
#define PCMD_START 0x02 /* +L: start voice */
#define PCMD_STOP 0x03 /* stop voice */
#define PCMD_FREQ 0x04 /* +W: set frequence */
#define PCMD_VOLUME 0x05 /* +W: set volume */
#define PCMD_VOLUME_PREPARE 0x06 /* +W: prepare to set volume on (soon to follow) kick */
#define PCMD_PAN 0x07 /* +B: set panning */
#define PCMD_OFFSET 0x08 /* +L: set DRAM offset */
#define PCMD_STOP_LOOP 0x09 /* stop looping */
#define GUS_VOLCHANGE_RAMP 0x20 /* Volume change ramp speed */
/* Definition for the boolean type */
typedef unsigned char boolean;
/* Prototype for functions that do block transfers to GUS DRAM:
flags can contain any of the following bits:
GUS_WAVE_16BIT - sample is 16-bit
GUS_WAVE_UNSIGNED - do not invert sign bit while downloading
*/
typedef void (*__gus_transfer_func) (unsigned long address,
unsigned char *source,
unsigned long size, int flags);
typedef void (*__gus_callback) ();
typedef void (*__gus_callback_3) (unsigned int, unsigned int, unsigned int);
/* Structure used to keep track of all on-board GUS memory */
typedef struct __struct_gus_mcb {
struct __struct_gus_mcb *next; /* Next MCB in chain */
struct __struct_gus_mcb *prev; /* Previous MCB in chain */
unsigned int addr; /* GUS DRAM address */
unsigned int size; /* Memory block size */
int free; /* 1: block is free */
} __gus_mcb;
/* Structure defining overall GUS state/information */
typedef struct {
unsigned int port; /* Base I/O port (0x220, 0x240, ...) */
unsigned int irq[2]; /* GF1 IRQ and MIDI IRQ */
unsigned int dma[2]; /* Play / record DMA */
unsigned int ram; /* Memory size (K), i.e. 256, 1024 etc */
unsigned int version; /* GUS version (see GUS_CARD_VERSION_XXX in libgus.h */
unsigned int freq; /* Current mixing frequency */
unsigned int voices; /* Active voices (14-32) */
unsigned int dynmask; /* Dynamically allocated voices mask */
unsigned int timer_base; /* The relative timer speed in percents (def: 100) */
volatile unsigned int t1_ticks; /* Incremented per each timer1 tick */
volatile unsigned int t2_ticks; /* Incremented per each timer2 tick */
volatile unsigned int t1_countdown; /* t1_callback is called when this reaches zero */
volatile unsigned int t2_countdown; /* t2_callback is called when this reaches zero */
unsigned int t1_multiple; /* Timer1 handler is called once per such many ticks */
unsigned int t2_multiple; /* Timer2 handler is called once per such many ticks */
irq_handle *gf1_irq; /* The interrupt handler for GF1 events */
dma_buffer *dma_buff; /* Pre-allocated DMA buffer */
__gus_callback dma_callback; /* Routine called at end of DMA transfers */
__gus_callback t1_callback; /* Routine called on Timer1 events */
__gus_callback t2_callback; /* Routine called on Timer1 events */
__gus_callback timer_callback; /* Called once per TEMPO ticks */
__gus_callback_3 wt_callback; /* Routine called on WaveTable events */
__gus_callback_3 vl_callback; /* Routine called on Volume ramp events */
__gus_mcb *mcb; /* Chained list of memory control blocks */
__gus_transfer_func transfer; /* Best working function for DRAM transfer */
gus_instrument_t *instr; /* The list of registered instruments */
unsigned short mixer; /* Current mixer register state */
unsigned char dma_rate; /* One of GF1M_DMAR_RATEX constants defined above */
unsigned char timer_ctl; /* Timer control register value (2x8/2x9) */
unsigned char timer_ctl_reg; /* Timer control register value (GF1/0x45) */
boolean ok; /* Is the information below okay? */
boolean open; /* 1 if between gus_open() and gus_close() */
boolean ics; /* Is it equipped with an ICS mixer? */
boolean ics_flipped; /* rev 5 (3.7) has flipped R/L mixer */
boolean codec; /* Is it equipped with a GUS MAX codec? */
boolean interwave; /* GUS InterWave card */
volatile boolean dma_active; /* DMA is transferring data */
volatile boolean cmd_pool_ready; /* Flush cmd_pool during timer interrupt */
unsigned char cmd_voice; /* Pool selection index cache */
unsigned int cmd_pool_top; /* Command pool top */
unsigned char *cmd_pool; /* Async commands pool */
/* The following data is for private use only by interrupt routines! */
gus_wave_t *cur_wave[32]; /* Currently played waves */
boolean voice_kick[32]; /* Kick wave on next volume ramp IRQ */
unsigned int kick_offs[32]; /* Sample start position on kick */
unsigned short cur_vol[32]; /* Current voice volumes */
unsigned int cur_voice; /* Current voice */
unsigned int eow_ignore; /* Temp ignore end-of-wave IRQ for these voices */
} __gus_state;
extern __gus_state gus;
extern void __gus_delay();
static unsigned long __gus_convert_addr16(unsigned long address)
{
return ((address & 0x0003ffff) >> 1) | (address & ~0x0003ffff);
}
/* The XXX_slow routines cannot be used outside IRQ handler! */
static inline void __gus_outregb_slow(unsigned char reg, unsigned char value)
{
outportb(GF1_REGSEL, reg);
outportb(GF1_DATA_HIGH, value);
__gus_delay();
outportb(GF1_DATA_HIGH, value);
}
static inline void __gus_outregw_slow(unsigned char reg, unsigned short value)
{
outportb(GF1_REGSEL, reg);
outportw(GF1_DATA, value);
__gus_delay();
outportw(GF1_DATA, value);
}
static inline void __gus_outregb(unsigned char reg, unsigned char value)
{
outportb(GF1_REGSEL, reg);
outportb(GF1_DATA_HIGH, value);
}
static inline void __gus_outregw(unsigned char reg, unsigned short value)
{
outportb(GF1_REGSEL, reg);
outportw(GF1_DATA, value);
}
static inline unsigned char __gus_inregb(unsigned char reg)
{
if (reg < 0x10)
reg |= GF1R_READ_MASK;
outportb(GF1_REGSEL, reg);
return inportb(GF1_DATA_HIGH);
}
static inline unsigned short __gus_inregw(unsigned char reg)
{
if (reg < 0x10)
reg |= GF1R_READ_MASK;
outportb(GF1_REGSEL, reg);
return inportw(GF1_DATA);
}
static inline void __gus_set_dram_address(unsigned int address)
{
__gus_outregb(GF1R_DRAM_HIGH, address >> 16);
__gus_outregw(GF1R_DRAM_LOW, address);
}
static inline unsigned char __gus_peek(unsigned int address)
{
__gus_set_dram_address(address);
return inportb(GF1_DRAM);
}
static inline void __gus_poke(unsigned int address, unsigned char value)
{
__gus_set_dram_address(address);
outportb(GF1_DRAM, value);
}
static inline void __gus_select_voice(unsigned char voice)
{
outportb(GF1_VOICESEL, voice);
}
static inline void __gus_set_current(unsigned char mode,
unsigned long address)
{
if (mode & GF1VC_DATA16)
address = __gus_convert_addr16(address);
__gus_outregw_slow(GF1R_ACC_HIGH, address >> 11);
__gus_outregw_slow(GF1R_ACC_LOW, address << 5);
}
static inline void __gus_set_loop_start(unsigned char mode,
unsigned long address)
{
if (mode & GF1VC_DATA16)
address = __gus_convert_addr16(address);
__gus_outregw_slow(GF1R_START_HIGH, address >> 11);
__gus_outregw_slow(GF1R_START_LOW, address << 5);
}
static inline void __gus_set_loop_end(unsigned char mode,
unsigned long address)
{
address--;
if (mode & GF1VC_DATA16)
address = __gus_convert_addr16(address);
__gus_outregw_slow(GF1R_END_HIGH, address >> 11);
__gus_outregw_slow(GF1R_END_LOW, address << 5);
}
static inline void __gus_mixer_output(boolean state)
{
if (state)
gus.mixer &= ~GF1M_MIXER_NO_OUTPUT;
else
gus.mixer |= GF1M_MIXER_NO_OUTPUT;
outportb(GF1_MIX_CTRL, gus.mixer);
/* Dummy read to avoid touching DMA latches */
__gus_inregb(GF1R_BALANCE);
}
/* Inline routines for working with command pools */
/* WARNING: no bounds checking due to performance reasons */
#define __POOL_VALUE(type,value) \
*((unsigned type *)&gus.cmd_pool [gus.cmd_pool_top]) = value; \
gus.cmd_pool_top += sizeof (type);
static inline void __pool_command(unsigned char command)
{
__POOL_VALUE(char, command);
}
static inline void __pool_command_b(unsigned char command, unsigned char arg)
{
__POOL_VALUE(char, command);
__POOL_VALUE(char, arg);
}
static inline void __pool_command_w(unsigned char command, unsigned short arg)
{
__POOL_VALUE(char, command);
__POOL_VALUE(short, arg);
}
static inline void __pool_command_l(unsigned char command, unsigned long arg)
{
__POOL_VALUE(char, command);
__POOL_VALUE(long, arg);
}
static inline void __pool_select_voice(unsigned char voice)
{
if (gus.cmd_voice != voice)
__pool_command_b(PCMD_VOICE, gus.cmd_voice = voice);
}
#undef __POOL_VALUE
#ifdef DEBUG
/* Debug dump of GUS DRAM heap */
extern void __gus_mem_dump();
#endif
#endif /* __DOSGUS_H__ */
/* ex:set ts=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -