⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dosgus.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
📖 第 1 页 / 共 4 页
字号:

		__gus_outregb(GF1R_DRAM_HIGH, address >> 16);
		if (flags & GUS_WAVE_INVERT)
			if (flags & GUS_WAVE_16BIT)
				while (size64k-- && size64k--) {
					__gus_outregw(GF1R_DRAM_LOW, address++);
					outportb(GF1_DRAM, *source++);
					__gus_outregw(GF1R_DRAM_LOW, address++);
					outportb(GF1_DRAM, (*source++) ^ 0x80);
			} else
				while (size64k--) {
					__gus_outregw(GF1R_DRAM_LOW, address++);
					outportb(GF1_DRAM, (*source++) ^ 0x80);
		} else
			while (size64k--) {
				__gus_outregw(GF1R_DRAM_LOW, address++);
				outportb(GF1_DRAM, *source++);
			}
	}
}

/* Wait for DMA transfer to finish between 8-9 1/18sec timer ticks */
static int __gus_wait_dma()
{
	unsigned long timer;
	_farsetsel(_dos_ds);
	timer = _farnspeekl(0x46c);
	while (gus.dma_active)
		if (_farnspeekl(0x46c) - timer > 8) {
			/* Force DMA abort since something went wrong */
			__gus_reset(0);
			return -1;
		}

	return 0;
}

/* Transfer a block of data into GUS DRAM through DMA controller */
static void __gus_transfer_dma(unsigned long address, unsigned char *source,
                               unsigned long size, int flags)
{
	unsigned char dma_control;
	unsigned long bytes_left;
	unsigned long cur_size;
	unsigned long dest_addr;

	if ((gus.dma[0] > 3) || (flags & GUS_WAVE_16BIT))
		size = (size + 1) & ~1;

	bytes_left = size;
	while (bytes_left) {
		__gus_wait_dma();

		cur_size = gus.dma_buff->size;
		if (cur_size > bytes_left)
			cur_size = bytes_left;
		bytes_left -= cur_size;
		dest_addr = address;

		if (gus.dma_buff->linear != source)
			memmove(gus.dma_buff->linear, source, cur_size);
		source += cur_size;
		address += cur_size;

		/* Disable GUS -> DMA tie */
		__gus_outregb(GF1R_DMA_CONTROL, 0);
		__gus_delay();

		/* Set up the DMA */
		dma_start(gus.dma_buff, cur_size, DMA_MODE_WRITE);
		gus.dma_active = 1;

		/* Reset the DMA IRQ pending bit if set */
		__gus_inregb(GF1R_DMA_CONTROL);

		/* The 16-bit DMA channels needs a slightly different approach */
		dma_control = GF1M_DMAR_ENABLE | GF1M_DMAR_IRQ_ENABLE | gus.dma_rate;
		if (gus.dma[0] > 3) {
			dest_addr = __gus_convert_addr16(dest_addr);
			dma_control |= GF1M_DMAR_CHAN16;
		}

		__gus_outregw(GF1R_DMA_ADDRESS, dest_addr >> 4);

		if (flags & GUS_WAVE_16BIT)
			dma_control |= GF1M_DMAR_DATA16;
		if (flags & GUS_WAVE_INVERT)
			dma_control |= GF1M_DMAR_TOGGLE_SIGN;

		/* Tell GUS to start transfer */
		__gus_outregb(GF1R_DMA_CONTROL, dma_control);
	}
}

static void __gus_detect_version()
{
	unsigned char tmp;

	switch (gus.version = inportb(GF1_REVISION)) {
	  case 5:
		gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
		gus.ics = 1;
		gus.ics_flipped = 1;
		break;
	  case 6:
	  case 7:
	  case 8:
	  case 9:
		gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
		gus.ics = 1;
		break;
	  case 10:
		gus.version = GUS_CARD_VERSION_MAX;
		gus.codec = 1;
		break;
	  case 11:
		gus.version = GUS_CARD_VERSION_MAX1;
		gus.codec = 1;
		break;
	  case 0x30:
		gus.version = GUS_CARD_VERSION_ACE;
		break;
	  case 0x50:
		gus.version = GUS_CARD_VERSION_EXTREME;
		break;
	  case 0xff:
		/* Pre-3.7 board */
		outportb(GF1_REG_CTRL, 0x20);
		tmp = inportb(GF1_REG_CTRL);
		if ((tmp != 0xff) && (tmp & 0x06))
			gus.version = GUS_CARD_VERSION_CLASSIC1;
		else
			gus.version = GUS_CARD_VERSION_CLASSIC;
		break;
	  default:
		/* Hmm... unknown revision. Assume a safe Classic model */
#ifdef MIKMOD_DEBUG
		fprintf(stderr, "libgus: Unknown board revision (%02x)\n",
				gus.version);
#endif
		gus.version = GUS_CARD_VERSION_CLASSIC;
		break;
	}
}

static void __gus_detect_transfer()
{
	unsigned char *outbuff, *inbuff;
	unsigned int i, j, seed = 0x13243546;
	__gus_transfer_func func;

#define TRANSFER_SIZE	0x4000

	outbuff = malloc(TRANSFER_SIZE);
	inbuff = malloc(TRANSFER_SIZE);

	/* Suppose we have an malfunctioning GUS */
	gus.transfer = NULL;

	for (i = (gus.dma_buff ? 0 : 4); i <= 4; i++) {
		switch (i) {
		  case 0:
			gus.dma_rate = GF1M_DMAR_RATE0;
			func = __gus_transfer_dma;
			break;
		  case 1:
			gus.dma_rate = GF1M_DMAR_RATE1;
			func = __gus_transfer_dma;
			break;
		  case 2:
			gus.dma_rate = GF1M_DMAR_RATE2;
			func = __gus_transfer_dma;
			break;
		  case 3:
			gus.dma_rate = GF1M_DMAR_RATE3;
			func = __gus_transfer_dma;
			break;
		  case 4:
			func = __gus_transfer_io;
			break;
		}

		/* Fill data array each time with pseudo-random values */
		for (j = 0; j < TRANSFER_SIZE; j++)
			outbuff[j] = seed, seed =
			  ((seed + 358979323) ^ (seed >> 16)) * 314159265;

		/* Transfer the random array to GUS */
		/* Poke a security fence around dest block */
		__gus_poke(0x100 - 1, 0xAA);
		__gus_poke(0x100 - 2, 0x55);
		__gus_poke(0x100 + TRANSFER_SIZE + 0, 0xAA);
		__gus_poke(0x100 + TRANSFER_SIZE + 1, 0x55);

		func(0x100, outbuff, TRANSFER_SIZE, 0);

		if (__gus_wait_dma() == 0) {
			/* Check if the security fence was not damaged */
			if ((__gus_peek(0x100 - 1) != 0xAA)
				|| (__gus_peek(0x100 - 2) != 0x55)
				|| (__gus_peek(0x100 + TRANSFER_SIZE + 0) != 0xAA)
				|| (__gus_peek(0x100 + TRANSFER_SIZE + 1) != 0x55))
				continue;

			/* Now check if GUS DRAM really data that we expects to be transferred */
			__gus_transfer_io_in(0x100, inbuff, TRANSFER_SIZE);
			if (memcmp(outbuff, inbuff, TRANSFER_SIZE) == 0) {
				gus.transfer = func;
				break;
			}
		}
	}

#undef TRANSFER_SIZE

	free(inbuff);
	free(outbuff);
}

static void __gus_detect_memory()
{
	unsigned int size;
	for (size = 0; size < 1024; size += 256) {
		__gus_poke(size * 1024, 0xaa);
		if (__gus_peek(size * 1024) != 0xaa)
			break;
		__gus_poke(size * 1024, 0x55);
		if (__gus_peek(size * 1024) != 0x55)
			break;
	}
	gus.ram = size;
}

static void __gus_init()
{
	char *gusenv = getenv("ULTRASND");

	memset((void *)&gus, 0, sizeof(gus));
	gus.cmd_voice = -1;

	if (!gusenv)
		return;

	sscanf(gusenv, "%x,%d,%d,%d,%d", &gus.port, &gus.dma[0], &gus.dma[1],
		   &gus.irq[0], &gus.irq[1]);

	/* A relaxed sanity check */
	if ((gus.port < 0x100) || (gus.port > 0x1000)
		|| (gus.irq[0] < 2) || (gus.irq[0] > 15)
		|| (gus.irq[1] < 2) || (gus.irq[1] > 15)
		|| (gus.dma[0] < 0) || (gus.dma[0] > 7)
		|| (gus.dma[1] < 0) || (gus.dma[1] > 7))
		return;

	gus.voices = 32;
	gus.timer_ctl = GF1M_MASK_TIMER1 | GF1M_MASK_TIMER2;

	/* Detect if the card is really there */
	if (__gus_detect() == 0)
		return;

	/* Detect the version of Gravis Ultrasound */
	__gus_detect_version();

	/* Reset the card */
	__gus_reset(1);

	/* Detect the amount of on-board memory */
	__gus_detect_memory();

	gus.ok = 1;
}

static void __gus_kick(gus_wave_t * wave, unsigned int wave_offset)
{
	unsigned char vc;

	vc = GF1VC_IRQ;
	if (wave->format & GUS_WAVE_16BIT)
		vc |= GF1VC_DATA16;
	if (wave->format & GUS_WAVE_BACKWARD)
		vc |= GF1VC_BACKWARD;
	if (wave->format & GUS_WAVE_LOOP) {
		vc |= GF1VC_LOOP_ENABLE;
		if (wave->format & GUS_WAVE_BIDIR)
			vc |= GF1VC_BI_LOOP;
	}
	__gus_set_loop_start(vc, (wave->begin.memory << 4) + wave->loop_start);
	if (wave->format & GUS_WAVE_LOOP)
		__gus_set_loop_end(vc, (wave->begin.memory << 4) + wave->loop_end);
	else
		__gus_set_loop_end(vc, (wave->begin.memory + wave->size) << 4);
	__gus_set_current(vc, (wave->begin.memory << 4) + wave_offset + 100);
	__gus_outregb_slow(GF1R_VOICE_CONTROL, vc);
}

/* Timer 1 callback function (updates voices) */
static void __gus_timer_update()
{
	gus_wave_t *wave;
	unsigned long wave_offset;
	unsigned char *src, *top;
	unsigned int vmask = (1 << gus.cur_voice);

	if (!gus.cmd_pool_ready)
		return;

	__gus_select_voice(gus.cur_voice);
	wave_offset = 0;
	src = gus.cmd_pool;
	top = gus.cmd_pool + gus.cmd_pool_top;

#define GET_B	*src
#define GET_W	*((unsigned short *)src)
#define GET_L	*((unsigned long *)src)

	while (src < top) {
		__gus_delay();
		switch (GET_B++) {
		  case PCMD_VOICE:
			__gus_select_voice(gus.cur_voice = GET_B++);
			vmask = (1 << gus.cur_voice);
			break;
		  case PCMD_FREQ:
			__gus_outregw(GF1R_FREQUENCY, GET_W++);
			break;
		  case PCMD_PAN:
			__gus_outregb(GF1R_BALANCE, GET_B++);
			break;
		  case PCMD_VOLUME:
			__gus_volume_ramp_to(gus.cur_vol[gus.cur_voice] =
								 GET_W++, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
			break;
		  case PCMD_VOLUME_PREPARE:
			gus.cur_vol[gus.cur_voice] = GET_W++;
			break;
		  case PCMD_OFFSET:
			wave_offset = GET_L++;
			break;
		  case PCMD_START:
			wave = (gus_wave_t *) GET_L++;
			gus.cur_wave[gus.cur_voice] = wave;
			gus.kick_offs[gus.cur_voice] = wave_offset;
			if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) {
				__gus_kick(wave, wave_offset);
				__gus_volume_ramp_to(gus.cur_vol[gus.cur_voice],
									 GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
			} else
				gus.voice_kick[gus.cur_voice] = 1;
			wave_offset = 0;
			gus.eow_ignore |= vmask;
			break;
		  case PCMD_STOP:
			/* If volume is close to nothing, abort immediately instead of
			   ramping */
			gus.cur_vol[gus.cur_voice] = 0;
			gus.cur_wave[gus.cur_voice] = NULL;
			if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
				__gus_stop_voice();
			break;
		  case PCMD_STOP_LOOP:
			__gus_outregb_slow(GF1R_VOICE_CONTROL,
							   (__gus_inregb(GF1R_VOICE_CONTROL) | GF1VC_IRQ)
							   & ~GF1VC_LOOP_ENABLE);
			__gus_outregb_slow(GF1R_VOLUME_CONTROL,
							   __gus_inregb(GF1R_VOLUME_CONTROL) &
							   ~GF1VL_ROLLOVER);
			break;
		  default:
			/* Alarm! Break out immediately */
			src = top;
			break;
		}
	}

#undef GET_B
#undef GET_W
#undef GET_L

	gus.cmd_pool_ready = 0;
	gus.cmd_pool_top = 0;
}

static void __gus_wavetable_update(unsigned int voice, unsigned int voice_ctl,
								   unsigned int volume_ctl)
{
	gus_wave_t *wave = gus.cur_wave[voice];

	if (!wave || !(wave->format & GUS_WAVE_LOOP)) {
		__gus_stop_voice();
		gus.cur_wave[voice] = NULL;
		gus.cur_vol[voice] = 0;
		if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
			__gus_stop_voice();
	}
}

static void __gus_volume_update(unsigned int voice, unsigned int voice_ctl,
								unsigned int volume_ctl)
{
	__gus_volume_ramp_to(gus.cur_vol[voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
	if (!gus.cur_wave[voice])
		__gus_stop_voice();
	else if (gus.voice_kick[voice])
		__gus_kick(gus.cur_wave[voice], gus.kick_offs[voice]);
	gus.voice_kick[voice] = 0;
}

/***************************************************** GUS memory manager *****/

/* Mark all GUS memory as available */
static void __gus_mem_clear()
{
	__gus_mcb *cur = gus.mcb;

	while (cur) {
		__gus_mcb *next = cur->next;
		if (cur != gus.mcb)
			free(cur);
		cur = next;
	}

	if (!gus.mcb)
		gus.mcb = malloc(sizeof(__gus_mcb));

	gus.mcb->next = gus.mcb->prev = NULL;
	gus.mcb->addr = 0;
	gus.mcb->size = gus.ram * 1024;
	gus.mcb->free = 1;
}

/* Return amount of free memory */
static unsigned int __gus_mem_get_free()
{
	__gus_mcb *cur = gus.mcb;
	unsigned int size = 0;

	if (!gus.open)
		return gus.ram * 1024;

	while (cur) {
		if (cur->free)
			size += cur->size;
		cur = cur->next;
	}

	return size;
}

/* Return largest size for a 8-bit sample */
static unsigned int __gus_mem_get_free_8()
{
	__gus_mcb *cur = gus.mcb;
	unsigned int size = 0;

	if (!gus.open)
		return 0;

	while (cur) {
		if (cur->free && (cur->size > size))
			size = cur->size;
		cur = cur->next;
	}

	return size;
}

/* Return largest size for a 16-bit sample */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -