📄 dosgus.c
字号:
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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -