dosgus.c
来自「这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔」· C语言 代码 · 共 1,872 行 · 第 1/4 页
C
1,872 行
static unsigned int __gus_mem_get_free_16()
{
__gus_mcb *cur = gus.mcb;
unsigned int size = 0;
if (!gus.open)
return 0;
while (cur) {
if (cur->free) {
unsigned int size16 = cur->size;
unsigned int tmp;
/* 16-bit samples cannot cross 256K boundaries */
tmp = 0x40000 - (cur->addr & 0x3ffff);
if (size16 > tmp)
size16 = tmp;
/* 16-bit samples should be aligned on a 32-byte boundary */
size16 -= (32 - cur->addr) & 0x1f;
if (size16 > size)
size = size16;
/* Now try vice versa: skip a portion of aligned memory */
size16 =
(cur->addr + cur->size) - ((cur->addr + 0x3ffff) & ~0x3ffff);
if ((size16 < 0x7fffffff) && (size16 > size))
size = size16;
}
cur = cur->next;
}
return size;
}
/* Allocate a segment of GUS DRAM for a sample with given bits per sample.
* The algorithm tries to find the smallest free block that fits requested
* size; but if found free block is larger by some (large) delta than
* requested block size, the largest possible block is preffered.
*/
static unsigned int __gus_mem_alloc(unsigned int size, int bits16)
{
__gus_mcb *cur = gus.mcb;
__gus_mcb *best_max = NULL, *best_min = NULL;
unsigned int best_max_delta = 0, best_min_delta = 0xffffffff;
unsigned int best_max_prefix = 0, best_min_prefix = 0;
unsigned int memaddr, memsize;
if (!gus.open || !size || (bits16 && size > 0x40000))
return -1;
/* Round block size up to nearest acceptable DMA bound */
if (bits16)
size = (size + 0x1f) & ~0x1f;
else
size = (size + 0x0f) & ~0x0f;
while (cur) {
if (cur->free) {
unsigned char fits = 0;
memsize = cur->size;
memaddr = cur->addr;
if (bits16) {
/* 16-bit samples cannot cross 256K boundaries */
unsigned int tmp = 256 * 1024 - (memaddr & 0x3ffff);
if (memsize > tmp)
memsize = tmp;
/* 16-bit samples should be aligned on a 32-byte boundary */
memsize -= (32 - memaddr) & 0x1f;
memaddr = (memaddr + 0x1f) & ~0x1f;
}
/* If block fits, analyze it */
if (size <= memsize)
fits = 1;
/* Look if we still can complete the request by creating a free
block */
else if (size <= cur->size) {
/* Align start address to next 256k boundary */
unsigned int endaddr = cur->addr + cur->size;
memaddr = (cur->addr + 0x3ffff) & ~0x3ffff;
/* Can we split current block by inserting a free block at the
beginning? */
if ((memaddr < endaddr) && (memaddr + size <= endaddr))
fits = 1;
}
if (fits) {
unsigned int size_delta = cur->size - size;
unsigned int size_prefix = memaddr - cur->addr;
if (size_delta < best_min_delta)
best_min = cur, best_min_delta =
size_delta, best_min_prefix = size_prefix;
if (size_delta > best_max_delta)
best_max = cur, best_max_delta =
size_delta, best_max_prefix = size_prefix;
}
}
cur = cur->next;
}
if (!best_min)
return -1;
/* If minimal block that fits is too large, use largest block that fits */
/* But if using the maximal block is going to create a small hole, forget
it */
if ((best_max_prefix == 0)
|| (best_max_prefix >= DRAM_HOLE_THRESHOLD)
|| (best_min_prefix != 0))
if (
((best_min_delta < DRAM_HOLE_THRESHOLD) &&
(best_max_delta >= DRAM_HOLE_THRESHOLD)) ||
((best_min_prefix > 0) && (best_min_prefix < DRAM_HOLE_THRESHOLD)
&& ((best_max_prefix == 0) ||
(best_max_prefix > best_min_prefix))) ||
((best_min_prefix != 0) && (best_max_prefix == 0))) {
best_min = best_max;
best_min_delta = best_max_delta;
best_min_prefix = best_max_prefix;
}
/* Compute the DRAM address to return */
memaddr = best_min->addr + best_min_prefix;
if (bits16)
memaddr = (memaddr + 0x1f) & ~0x1f;
else
memaddr = (memaddr + 0x0f) & ~0x0f;
/* If we have a considerable hole at the beginning of sample,
create a free node describing the hole */
if (memaddr - best_min->addr >= DRAM_SPLIT_THRESHOLD) {
__gus_mcb *newmcb = malloc(sizeof(__gus_mcb));
newmcb->prev = best_min->prev;
newmcb->next = best_min;
newmcb->addr = best_min->addr;
newmcb->size = memaddr - best_min->addr;
newmcb->free = 1;
best_min->addr = memaddr;
best_min->size -= newmcb->size;
best_min->prev = newmcb;
if (newmcb->prev)
newmcb->prev->next = newmcb;
}
/* Compute the size of hole at the end of block */
memsize = (best_min->addr + best_min->size) - (memaddr + size);
/* Split the block if the block is larger than requested amount */
if (memsize > DRAM_SPLIT_THRESHOLD) {
/* The next node cannot be free since free blocks are always glued
together */
__gus_mcb *newmcb = malloc(sizeof(__gus_mcb));
best_min->size -= memsize;
newmcb->prev = best_min;
newmcb->next = best_min->next;
newmcb->addr = best_min->addr + best_min->size;
newmcb->size = memsize;
newmcb->free = 1;
if (best_min->next)
best_min->next->prev = newmcb;
best_min->next = newmcb;
}
best_min->free = 0;
return memaddr;
}
static void __gus_mem_free(unsigned int addr)
{
__gus_mcb *cur = gus.mcb;
while (cur) {
if (!cur->free && (cur->addr <= addr) &&
(cur->addr + cur->size > addr)) {
cur->free = 1;
/* If next block is free as well, link them together */
if (cur->next && cur->next->free) {
__gus_mcb *next = cur->next;
cur->size += next->size;
cur->next = next->next;
if (next->next)
next->next->prev = cur;
free(next);
}
/* If previous block is free, link current block with it */
if (cur->prev && cur->prev->free) {
cur->prev->size += cur->size;
cur->prev->next = cur->next;
if (cur->next)
cur->next->prev = cur->prev;
free(cur);
}
return;
}
cur = cur->next;
}
}
static void __gus_mem_pack()
{
}
#ifdef MIKMOD_DEBUG
/* Debug dump of GUS DRAM heap */
void __gus_mem_dump()
{
__gus_mcb *cur = gus.mcb;
fprintf(stderr, "/-- Offset --+-- Prev --+-- Size --+-- Free --\\\n");
while (cur) {
fprintf(stderr, "| %08X | %08X | %6d | %s |\n",
cur->addr, cur->prev ? cur->prev->addr : -1, cur->size,
cur->free ? "yes" : " no");
cur = cur->next;
}
fprintf(stderr, "\\------------+----------+----------+----------/\n");
}
#endif
/************************************************** Middle-level routines *****/
static int __gus_instrument_free(gus_instrument_t * instrument)
{
gus_instrument_t **cur_instr;
gus_layer_t *cur_layer;
gus_wave_t *cur_wave, *wave_head;
/* Remove the instrument from the list of registered instruments */
cur_instr = (gus_instrument_t **) & gus.instr;
while (*cur_instr) {
if (*cur_instr == instrument) {
*cur_instr = instrument->next;
goto instr_loaded;
}
cur_instr = &(*cur_instr)->next;
}
return -1;
instr_loaded:
wave_head = NULL;
for (cur_layer = instrument->info.layer; cur_layer;
cur_layer = cur_layer->next)
/* Free all waves */
for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
if (!wave_head)
wave_head = cur_wave;
if (cur_wave->begin.memory != (unsigned int)-1)
__gus_mem_free(cur_wave->begin.memory);
}
if (wave_head)
free(wave_head);
free(instrument->info.layer);
if (instrument->name)
free(instrument->name);
free(instrument);
return 0;
}
static gus_instrument_t *__gus_instrument_get(int program)
{
gus_instrument_t *cur_instr = (gus_instrument_t *) gus.instr;
while (cur_instr) {
if (cur_instr->number.instrument == program)
return cur_instr;
cur_instr = cur_instr->next;
}
return NULL;
}
static gus_instrument_t *__gus_instrument_copy(gus_instrument_t * instrument)
{
gus_instrument_t **cur_instr, *instr;
gus_layer_t *cur_layer, *dest_layer;
gus_wave_t *cur_wave, *dest_wave;
unsigned int waves, layers;
if (!instrument || !instrument->info.layer || !gus.open)
return NULL;
if (__gus_instrument_get(instrument->number.instrument))
return NULL;
instr = malloc(sizeof(gus_instrument_t));
*instr = *instrument;
if (instrument->name)
instr->name = strdup(instrument->name);
/* Make a copy of all layers at once */
for (layers = 0, cur_layer = instrument->info.layer; cur_layer; layers++)
cur_layer = cur_layer->next;
if (!(dest_layer = instr->info.layer = malloc(sizeof(gus_layer_t) * layers))) {
if (instr->name)
free(instr->name);
free(instr);
return NULL;
}
for (waves = 0, cur_layer = instrument->info.layer; cur_layer;
cur_layer = cur_layer->next) {
*dest_layer = *cur_layer;
dest_layer->wave = NULL;
/* Count the total number of waves */
for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next)
waves++;
if (cur_layer->next)
dest_layer->next = dest_layer + 1;
else
dest_layer->next = NULL;
dest_layer++;
}
/* Allocate memory for waves */
if (!(dest_wave = malloc(sizeof(gus_wave_t) * waves))) {
free(instr->info.layer);
if (instr->name)
free(instr->name);
free(instr);
return NULL;
}
for (cur_layer = instrument->info.layer, dest_layer = instr->info.layer;
cur_layer; cur_layer = cur_layer->next, dest_layer = dest_layer->next)
/* Copy all waves */
for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
if (!dest_layer->wave)
dest_layer->wave = dest_wave;
*dest_wave = *cur_wave;
/* Mark DRAM address as unallocated */
dest_wave->begin.memory = -1;
if (cur_wave->next)
dest_wave->next = (dest_wave + 1);
else
dest_wave->next = NULL;
dest_wave++;
}
/* Insert the instrument into list of registered instruments */
cur_instr = (gus_instrument_t **) & gus.instr;
while (*cur_instr)
cur_instr = &(*cur_instr)->next;
*cur_instr = instr;
return instr;
}
static void __gus_instruments_clear()
{
gus_instrument_t *next_instr, *cur_instr = (gus_instrument_t *) gus.instr;
while (cur_instr) {
next_instr = cur_instr->next;
__gus_instrument_free(cur_instr);
cur_instr = next_instr;
}
}
/******************************************************* libGUS interface *****/
/* return value: number of GUS cards installed in system */
int gus_cards()
{
if (!gus.ok)
__gus_init();
return gus.ok ? 1 : 0;
}
int gus_info(gus_info_t * info, int reread)
{
if (!gus.ok)
__gus_init();
if (!gus.ok)
return -1;
strcpy(info->id, "gus0");
info->flags = (gus.ram ? GUS_STRU_INFO_F_PCM : 0);
info->version = gus.version;
info->port = gus.port;
info->irq = gus.irq[0];
info->dma1 = gus.dma[0];
info->dma2 = gus.dma[1];
info->mixing_freq = gus.freq;
info->memory_size = gus.ram * 1024;
info->memory_free = __gus_mem_get_free();
info->memory_block_8 = __gus_mem_get_free_8();
info->memory_block_16 = __gus_mem_get_free_16();
return 0;
}
int gus_open(int card, size_t queue_buffer_size, int non_block)
{
__dpmi_meminfo struct_info, pool_info;
if (!gus.ok)
__gus_init();
if (!gus.ok || gus.open || card != 0)
return -1;
/* Now lock the gus structure in memory */
struct_info.address = __djgpp_base_address + (unsigned long)&gus;
struct_info.size = sizeof(gus);
if (__dpmi_lock_linear_region(&struct_info))
return -1;
/* And hook the GF1 interrupt */
__irq_stack_count = 4;
gus.gf1_irq =
irq_hook(gus.irq[0], gf1_irq, (long)gf1_irq_end - (long)gf1_irq);
__irq_stack_count = 1;
if (!gus.gf1_irq) {
__dpmi_unlock_linear_region(&struct_info);
return -1;
}
/* Enable the interrupt */
irq_enable(gus.gf1_irq);
if (gus.irq[0] > 7)
_irq_enable(2);
/* Allocate a DMA buffer: if we fail, we just use I/O so don't fail */
if ((gus.transfer == NULL) || (gus.transfer == __gus_transfer_dma))
gus.dma_buff = dma_allocate(gus.dma[0], GF1_DMA_BUFFER_SIZE);
else
gus.dma_buff = NULL;
/* Detect the best available RAM -> DRAM transfer function */
if (!gus.transfer) {
__gus_detect_transfer();
if (gus.transfer != __gus_transfer_dma || !gus.transfer)
dma_free(gus.dma_buff), gus.dma_buff = NULL;
/* If no transfer function worked, fail */
if (!gus.transfer) {
if (gus.dma_buff)
dma_free(gus.dma_buff);
__dpmi_unlock_linear_region(&struct_info);
irq_unhook(gus.gf1_irq);
return -1;
}
}
/* Allocate and lock command pool buffer */
if (queue_buffer_size < 64)
queue_buffer_size = 64;
if (queue_buffer_size > 16384)
queue_buffer_size = 16384;
gus.cmd_pool = malloc(queue_buffer_size);
pool_info.address = __djgpp_base_address + (unsigned long)&gus.cmd_pool;
pool_info.size = sizeof(queue_buffer_size);
if (__dpmi_lock_linear_region(&pool_info)) {
if (gus.dma_buff)
dma_free(gus.dma_buff);
__dpmi_unlock_linear_region(&struct_info);
irq_unhook(gus.gf1_irq);
return -1;
}
gus.open++;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?