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 + -
显示快捷键?