dosgus.c
来自「这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔」· C语言 代码 · 共 1,872 行 · 第 1/4 页
C
1,872 行
__gus_mem_clear();
gus.t1_callback = __gus_timer_update;
gus.wt_callback = __gus_wavetable_update;
gus.vl_callback = __gus_volume_update;
gus_do_tempo(60); /* Default is 60 Hz */
return 0;
}
int gus_close(int card)
{
__dpmi_meminfo struct_info;
if (!gus.open || card != 0)
return -1;
/* First reset the card: disable any operation it can currently perform */
__gus_reset(0);
gus.open--;
/* Stop the timer */
gus_timer_stop();
/* Free DMA buffer if used */
if (gus.dma_buff)
dma_free(gus.dma_buff);
/* And unhook the GF1 interrupt */
irq_unhook(gus.gf1_irq);
gus.gf1_irq = NULL;
/* Unlock the gus structure */
struct_info.address = __djgpp_base_address + (unsigned long)&gus;
struct_info.size = sizeof(gus);
__dpmi_unlock_linear_region(&struct_info);
__gus_mem_clear();
__gus_instruments_clear();
return 0;
}
int gus_select(int card)
{
if (!gus.open || (card != 0))
return -1;
return 0;
}
/* return value: same as gus_reset function
note: this command doesn't change number of active voices and doesn't do
hardware reset */
int gus_reset_engine_only()
{
gus.timer_base = 100;
return 0;
}
int gus_reset(int voices, unsigned int channel_voices)
{
static unsigned short freq_table[32 - 14 + 1] = {
44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
};
int voice;
int timer;
/* No support for dynamically allocated voices for now */
gus.dynmask = channel_voices;
if (voices < 14)
voices = 14;
if (voices > 32)
voices = 32;
/* Stop the timer so that GUS IRQ won't clobber registers */
timer = (gus.timer_ctl_reg & GF1M_TIMER1);
if (timer)
gus_timer_stop();
/* Stop all voices */
for (voice = 0; voice < 32; voice++) {
__gus_select_voice(voice);
__gus_stop_voice();
gus.cur_wave[voice] = NULL;
gus.cur_vol[voice] = 0;
__gus_delay();
/* Reset voice parameters to reasonable values */
__gus_set_current(0, 0);
__gus_set_loop_start(0, 0);
__gus_set_loop_end(0, 0);
__gus_outregw(GF1R_VOLUME, 0);
__gus_outregb(GF1R_VOLUME_RATE, 0);
__gus_outregb(GF1R_VOLUME_START, 0);
__gus_outregb(GF1R_VOLUME_END, 0);
__gus_outregb(GF1R_BALANCE, 0x7);
}
voice = (__gus_inregb(GF1R_VOICES) & 0x1f) + 1;
if (voice != voices) {
int reset = __gus_inregb(GF1R_RESET);
__gus_outregb(GF1R_RESET, reset & ~GF1M_OUTPUT_ENABLE);
__gus_delay();
__gus_outregb(GF1R_VOICES, 0xc0 | (voices - 1));
__gus_delay();
__gus_outregb(GF1R_RESET, reset);
}
/* Compute the discretization frequence */
gus.voices = voices;
if (gus.interwave)
gus.freq = 44100;
else
gus.freq = freq_table[voices - 14];
gus_reset_engine_only();
if (timer)
gus_timer_continue();
return gus.voices;
}
int gus_do_flush()
{
DEBUG_PRINT(("gus_do_flush: top = %d\n", gus.cmd_pool_top))
gus.cmd_pool_ready = 1;
return 0;
}
/* set new tempo */
void gus_do_tempo(unsigned int tempo)
{
DEBUG_PRINT(("gus_do_tempo (%d)\n", tempo))
gus_timer_tempo(tempo);
gus_timer_start();
}
/* set voice frequency in Hz */
void gus_do_voice_frequency(unsigned char voice, unsigned int freq)
{
DEBUG_PRINT(("gus_do_voice_frequency (%d, %d)\n", voice, freq))
__pool_select_voice(voice);
__pool_command_w(PCMD_FREQ,
(((freq << 9) + (gus.freq >> 1)) / gus.freq) << 1);
}
/* set voice pan (0-16384) (full left - full right) */
void gus_do_voice_pan(unsigned char voice, unsigned short pan)
{
DEBUG_PRINT(("gus_do_voice_pan (%d, %d)\n", voice, pan))
pan >>= 10;
if (pan > 15)
pan = 15;
__pool_select_voice(voice);
__pool_command_b(PCMD_PAN, pan);
}
/* set voice volume level 0-16384 (linear) */
void gus_do_voice_volume(unsigned char voice, unsigned short vol)
{
DEBUG_PRINT(("gus_do_voice_volume (%d, %d)\n", voice, vol))
if (vol > 0x3fff)
vol = 0x3fff;
__pool_select_voice(voice);
__pool_command_w(PCMD_VOLUME, __gus_volume_table[vol >> 5]);
}
/* start voice
* voice : voice #
* program : program # or ~0 = current
* freq : frequency in Hz
* volume : volume level (0-16384) or ~0 = current
* pan : pan level (0-16384) or ~0 = current
*/
void gus_do_voice_start(unsigned char voice, unsigned int program,
unsigned int freq, unsigned short volume,
unsigned short pan)
{
gus_do_voice_start_position(voice, program, freq, volume, pan, 0);
}
/* start voice
* voice : voice #
* program : program # or ~0 = current
* freq : frequency in Hz
* volume : volume level (0-16384) or ~0 = current
* pan : pan level (0-16384) or ~0 = current
* position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
*/
void gus_do_voice_start_position(unsigned char voice, unsigned int program,
unsigned int freq, unsigned short volume,
unsigned short pan, unsigned int position)
{
gus_instrument_t *instrument;
gus_wave_t *wave;
DEBUG_PRINT(
("gus_do_voice_start_position (%d, %d, pos: %d)\n", voice,
program, position))
instrument = __gus_instrument_get(program);
if (!instrument
|| !instrument->info.layer
|| !instrument->info.layer->wave
|| instrument->flags == GUS_INSTR_F_NOT_FOUND
|| instrument->flags == GUS_INSTR_F_NOT_LOADED) return;
gus_do_voice_frequency(voice, freq);
gus_do_voice_pan(voice, pan);
/* We have to set volume different way, to avoid unneeded work in handler */
if (volume > 0x3fff)
volume = 0x3fff;
__pool_command_w(PCMD_VOLUME_PREPARE, __gus_volume_table[volume >> 5]);
switch (instrument->mode) {
case GUS_INSTR_SIMPLE:
wave = instrument->info.layer->wave;
if (position)
__pool_command_l(PCMD_OFFSET, position);
__pool_command_l(PCMD_START, (unsigned long)wave);
break;
}
}
/* stop voice
* mode = 0 : stop voice now
* mode = 1 : disable wave loop and finish it
*/
void gus_do_voice_stop(unsigned char voice, unsigned char mode)
{
__pool_select_voice(voice);
if (mode)
__pool_command(PCMD_STOP_LOOP);
else
__pool_command(PCMD_STOP);
}
/* wait x ticks - this command is block separator
all commands between blocks are interpreted in the begining of one tick */
void gus_do_wait(unsigned int ticks)
{
DEBUG_PRINT(("gus_do_wait (%d)\n", ticks))
ticks += gus.t1_ticks;
while ((int)(ticks - gus.t1_ticks) > 0);
}
int gus_get_voice_status(int voice)
{
__gus_select_voice(voice);
return __gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED ? 0 : 1;
}
/* return value: file handle (descriptor) for /dev/gus */
int gus_get_handle()
{
/* Return stdout handle so that select() will "work" with it */
return 0;
}
/* return value: zero if instrument was successfully allocated */
int gus_memory_alloc(gus_instrument_t * instrument)
{
gus_instrument_t *instr = __gus_instrument_copy(instrument);
gus_layer_t *cur_layer;
gus_wave_t *cur_wave;
DEBUG_PRINT(("gus_memory_alloc (%d)\n", instrument->number.instrument))
if (!instr)
return -1;
for (cur_layer = instr->info.layer; cur_layer;
cur_layer = cur_layer->next) for (cur_wave = cur_layer->wave;
cur_wave;
cur_wave = cur_wave->next) {
if (cur_layer->mode == GUS_INSTR_SIMPLE) {
cur_wave->begin.memory = __gus_mem_alloc(cur_wave->size,
cur_wave->format &
GUS_WAVE_16BIT);
if (cur_wave->begin.memory == (unsigned int)-1) {
__gus_instrument_free(instr);
return -1;
}
gus.transfer(cur_wave->begin.memory, cur_wave->begin.ptr,
cur_wave->size, cur_wave->format);
} else if (cur_layer->mode == GUS_INSTR_PATCH)
/* not supported yet */ ;
}
return 0;
}
/* return value: zero if instrument was successfully removed */
int gus_memory_free(gus_instrument_t * instrument)
{
gus_instrument_t *cur_instr = gus.instr;
DEBUG_PRINT(("gus_memory_free (%d)\n", instrument->number.instrument))
for (; cur_instr; cur_instr = cur_instr->next)
if (cur_instr->number.instrument == instrument->number.instrument)
return __gus_instrument_free(cur_instr);
return -1;
}
/* return value: unused gus memory in bytes */
int gus_memory_free_size()
{
return __gus_mem_get_free();
}
/* return value: zero if success */
int gus_memory_pack()
{
__gus_mem_pack();
return 0;
}
/* return value: gus memory size in bytes */
int gus_memory_size()
{
return gus.ram * 1024;
}
/* return value: current largest free block for 8-bit or 16-bit wave */
int gus_memory_free_block(int w_16bit)
{
return w_16bit ? __gus_mem_get_free_16() : __gus_mem_get_free_8();
}
/* input value: see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
return value: zero if samples & instruments was successfully removed from
GF1 memory manager */
int gus_memory_reset(int mode)
{
__gus_mem_clear();
__gus_instruments_clear();
return 0;
}
/* return value: zero if command queue was successfully flushed */
int gus_queue_flush()
{
return 0;
}
/* input value: echo buffer size in items (if 0 - erase echo buffer) */
int gus_queue_read_set_size(int items)
{
return 0;
}
/* input value: write queue size in items (each item have 8 bytes) */
int gus_queue_write_set_size(int items)
{
return 0;
}
/* return value: zero if successfull */
int gus_timer_start()
{
gus.timer_ctl_reg |= GF1M_TIMER1;
__gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
gus.timer_ctl = gus.timer_ctl & ~GF1M_MASK_TIMER1;
outportb(GF1_TIMER_CTRL, 0x04);
outportb(GF1_TIMER_DATA, gus.timer_ctl | GF1M_START_TIMER1);
return 0;
}
/* return value: zero if timer was stoped */
int gus_timer_stop()
{
gus.timer_ctl_reg &= ~GF1M_TIMER1;
__gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
gus.timer_ctl = gus.timer_ctl | GF1M_MASK_TIMER1;
outportb(GF1_TIMER_CTRL, 0x04);
outportb(GF1_TIMER_DATA, gus.timer_ctl);
return 0;
}
/* return value: zero if setup was success */
int gus_timer_tempo(int ticks)
{
unsigned int counter;
/* Limit ticks per second to 1..1000 range */
if (ticks < 1)
ticks = 1;
if (ticks > 1000)
ticks = 1000;
/* GF1 timer1 period is 80 usecs, 12500 times per second */
counter = 1250000 / (ticks * gus.timer_base);
gus.t1_multiple = 1;
while (counter > 255) {
counter >>= 1;
gus.t1_multiple <<= 1;
}
gus.t1_countdown = gus.t1_multiple;
__gus_outregb(GF1R_TIMER1, 256 - counter);
return 0;
}
/* return value: zero if timer will be continue */
int gus_timer_continue()
{
return gus_timer_start();
}
/* return value: zero if setup was success (default timebase = 100) */
int gus_timer_base(int base)
{
gus.timer_base = base;
return 0;
}
void gus_timer_callback(void (*timer_callback) ())
{
gus.timer_callback = timer_callback;
}
void gus_convert_delta(unsigned int type, unsigned char *dest,
unsigned char *src, size_t size)
{
if (!(type & GUS_WAVE_DELTA))
return;
/* This doesn't depend much on wave signedness, since addition/subtraction
do not depend on operand signedness */
if (type & GUS_WAVE_16BIT) {
unsigned short delta = type & GUS_WAVE_UNSIGNED ? 0x8000 : 0;
while (size--) {
delta = *(unsigned short *)dest = *(unsigned short *)src + delta;
src += sizeof(unsigned short);
dest += sizeof(unsigned short);
}
} else {
unsigned char delta = type & GUS_WAVE_UNSIGNED ? 0x80 : 0;
while (size--) {
delta = *(unsigned char *)dest = *(unsigned char *)src + delta;
src++;
dest++;
}
}
}
int gus_dma_usage (int use)
{
if (gus.dma_buff)
return -1;
gus.transfer = __gus_transfer_io;
return 0;
}
/* ex:set ts=4: */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?