📄 drv_ultra.c
字号:
/* MikMod sound library (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for complete list. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//*============================================================================== $Id: drv_ultra.c,v 1.4 2004/02/05 17:34:49 raph Exp $ Driver for Gravis Ultrasound cards using libGUS. A subset of libGUS is provided for DOS/DJGPP and OS/2==============================================================================*//* Written by Andy Lo A Foe <andy@alsa-project.org> Updated to work with later versions of both the ultrasound driver and libmikmod by C. Ray C. <crayc@pyro.net> Major fixes by Andrew Zabolotny <bit@eltech.ru> + Ported to OS/2 and DOS. + Eight-bit samples are not converted to 16-bit anymore. + Samples are no longer kept in normal memory. + Removed sample 'unclick' logic... libGUS does unclick internally.*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "mikmod_internals.h"#ifdef DRV_ULTRA#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_MEMORY_H#include <memory.h>#endif#ifdef MIKMOD_DYNAMIC#include <dlfcn.h>#endif#include <errno.h>#include <stdlib.h>#include <string.h>#include <libgus.h>/* DOS/DJGPP and OS/2 libGUS'es have gus_get_voice_status() */#if defined (__EMX__) || defined (__DJGPP__)#define HAVE_VOICE_STATUS#else#include <time.h>#endif#ifdef MIKMOD_DYNAMIC/* runtime link with libgus */static int (*libgus_cards) (void);static int (*libgus_close) (int);static int (*libgus_do_flush) (void);static void (*libgus_do_tempo) (unsigned int);static void (*libgus_do_voice_frequency) (unsigned char, unsigned int);static void (*libgus_do_voice_pan) (unsigned char, unsigned short);static void (*libgus_do_voice_start) (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short);static void (*libgus_do_voice_start_position) (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short, unsigned int);static void (*libgus_do_voice_stop) (unsigned char, unsigned char);static void (*libgus_do_voice_volume) (unsigned char, unsigned short);static void (*libgus_do_wait) (unsigned int);static int (*libgus_get_handle) (void);static int (*libgus_info) (gus_info_t *, int);static int (*libgus_memory_alloc) (gus_instrument_t *);static int (*libgus_memory_free) (gus_instrument_t *);static int (*libgus_memory_free_size) (void);static int (*libgus_memory_pack) (void);static int (*libgus_open) (int, size_t, int);static int (*libgus_queue_flush) (void);static int (*libgus_queue_read_set_size) (int);static int (*libgus_queue_write_set_size) (int);static int (*libgus_reset) (int, unsigned int);static int (*libgus_select) (int);static int (*libgus_timer_start) (void);static int (*libgus_timer_stop) (void);static int (*libgus_timer_tempo) (int);static void *libgus = NULL;#ifndef HAVE_RTLD_GLOBAL#define RTLD_GLOBAL 0#endif#else/* compile-time link with libgus */#define libgus_cards gus_cards#define libgus_close gus_close#define libgus_do_flush gus_do_flush#define libgus_do_tempo gus_do_tempo#define libgus_do_voice_frequency gus_do_voice_frequency#define libgus_do_voice_pan gus_do_voice_pan#define libgus_do_voice_start gus_do_voice_start#define libgus_do_voice_start_position gus_do_voice_start_position#define libgus_do_voice_stop gus_do_voice_stop#define libgus_do_voice_volume gus_do_voice_volume#define libgus_do_wait gus_do_wait#define libgus_get_handle gus_get_handle#define libgus_info gus_info#define libgus_memory_alloc gus_memory_alloc#define libgus_memory_free gus_memory_free#define libgus_memory_free_size gus_memory_free_size#define libgus_memory_pack gus_memory_pack#define libgus_open gus_open#define libgus_queue_flush gus_queue_flush#define libgus_queue_read_set_size gus_queue_read_set_size#define libgus_queue_write_set_size gus_queue_write_set_size#define libgus_reset gus_reset#define libgus_select gus_select#define libgus_timer_start gus_timer_start#define libgus_timer_stop gus_timer_stop#define libgus_timer_tempo gus_timer_tempo#endif#define GUS_SAMPLES 256 /* Max. GUS samples loadable */#define GUS_CHANNELS 32 /* Max. GUS channels available */#define SIZE_OF_SEQBUF (8 * 1024) /* Size of the sequence buffer */#define ULTRA_PAN_MIDDLE (16383 >> 1) /* Middle balance position */#define CH_FREQ 1#define CH_VOL 2#define CH_PAN 4/* This structure holds the current state of a GUS voice channel. */typedef struct GUS_VOICE { UBYTE kick; UBYTE active; UWORD flags; SWORD handle; ULONG start; ULONG size; ULONG reppos; ULONG repend; ULONG frq; int vol; int decvol; int pan; int changes;#ifndef HAVE_VOICE_STATUS time_t started;#endif} GUS_VOICE;/* Global declarations follow */static SAMPLE *samples[GUS_SAMPLES]; /* sample handles */static GUS_VOICE voices[GUS_CHANNELS]; /* channel status */static int ultra_dev = 0; /* GUS index, if more than one card */static int ultra_handle = -1; /* GUS handle */static int ultra_fd = -1; /* GUS file descriptor */#ifdef MIKMOD_DYNAMICstatic BOOL Ultra_Link(void){ if (libgus) return 0; /* load libgus.so */ libgus = dlopen("libgus.so", RTLD_LAZY | RTLD_GLOBAL); if (!libgus) return 1; /* resolve function references */#define IMPORT_SYMBOL(x) \ if (!(lib##x = dlsym(libgus, #x))) return 1 IMPORT_SYMBOL(gus_cards); IMPORT_SYMBOL(gus_close); IMPORT_SYMBOL(gus_do_flush); IMPORT_SYMBOL(gus_do_tempo); IMPORT_SYMBOL(gus_do_voice_frequency); IMPORT_SYMBOL(gus_do_voice_pan); IMPORT_SYMBOL(gus_do_voice_start); IMPORT_SYMBOL(gus_do_voice_start_position); IMPORT_SYMBOL(gus_do_voice_stop); IMPORT_SYMBOL(gus_do_voice_volume); IMPORT_SYMBOL(gus_do_wait); IMPORT_SYMBOL(gus_get_handle); IMPORT_SYMBOL(gus_info); IMPORT_SYMBOL(gus_memory_alloc); IMPORT_SYMBOL(gus_memory_free); IMPORT_SYMBOL(gus_memory_free_size); IMPORT_SYMBOL(gus_memory_pack); IMPORT_SYMBOL(gus_open); IMPORT_SYMBOL(gus_queue_flush); IMPORT_SYMBOL(gus_queue_read_set_size); IMPORT_SYMBOL(gus_queue_write_set_size); IMPORT_SYMBOL(gus_reset); IMPORT_SYMBOL(gus_select); IMPORT_SYMBOL(gus_timer_start); IMPORT_SYMBOL(gus_timer_stop); IMPORT_SYMBOL(gus_timer_tempo);#undef IMPORT_SYMBOL return 0;}static void Ultra_Unlink(void){ libgus_cards = NULL; libgus_close = NULL; libgus_do_flush = NULL; libgus_do_tempo = NULL; libgus_do_voice_frequency = NULL; libgus_do_voice_pan = NULL; libgus_do_voice_start = NULL; libgus_do_voice_start_position = NULL; libgus_do_voice_stop = NULL; libgus_do_voice_volume = NULL; libgus_do_wait = NULL; libgus_get_handle = NULL; libgus_info = NULL; libgus_memory_alloc = NULL; libgus_memory_free = NULL; libgus_memory_free_size = NULL; libgus_memory_pack = NULL; libgus_open = NULL; libgus_queue_flush = NULL; libgus_queue_read_set_size = NULL; libgus_queue_write_set_size = NULL; libgus_reset = NULL; libgus_select = NULL; libgus_timer_start = NULL; libgus_timer_stop = NULL; libgus_timer_tempo = NULL; if (libgus) { dlclose(libgus); libgus = NULL; }}#endifstatic void Ultra_CommandLine(CHAR *cmdline){ CHAR *ptr = MD_GetAtom("card", cmdline, 0); if (ptr) { int buf = atoi(ptr); if (buf >= 0 && buf <= 8) ultra_dev = buf; free(ptr); }#ifdef __DJGPP__ if ((ptr = MD_GetAtom("dma", cmdline, 0))) { gus_dma_usage (atoi(ptr)); free(ptr); }#endif}/* Checks for the presence of GUS cards */static BOOL Ultra_IsThere(void){ int retval;#ifdef MIKMOD_DYNAMIC if (Ultra_Link()) return 0;#endif retval = libgus_cards()? 1 : 0;#ifdef MIKMOD_DYNAMIC Ultra_Unlink();#endif return retval;}/* Load a new sample directly into GUS DRAM and return a handle */static SWORD Ultra_SampleLoad(struct SAMPLOAD *sload){ int handle; SAMPLE *s = sload->sample; gus_instrument_t instrument; gus_layer_t layer; gus_wave_t wave; unsigned char *buffer; unsigned int length, loopstart, loopend; /* Find empty slot to put sample in */ for (handle = 0; handle < GUS_SAMPLES; handle++) if (!samples[handle]) break; if (handle == GUS_SAMPLES) { _mm_errno = MMERR_OUT_OF_HANDLES; return -1; } /* Fill an gus_instrument_t structure and feed it to libgus. We can download 8 and 16 bit, both signed and unsigned samples into GUS, so don't bother much about formats here. */ /* convert position/length data from samples to bytes */ length = s->length; loopstart = s->loopstart; loopend = s->loopend ? s->loopend : length; /* sanity checks */ if (loopend > length) loopend = length; if (loopstart > loopend) loopstart = loopend; if (s->flags & SF_16BITS) { length <<= 1; loopstart <<= 1; loopend <<= 1; } /* Load sample into normal memory */ if (!(buffer = _mm_malloc(length))) { _mm_errno = MMERR_SAMPLE_TOO_BIG; return -1; } if (SL_Load(buffer, sload, s->length)) { free(buffer); return -1; } samples[handle] = s; memset(&wave, 0, sizeof(wave)); memset(&layer, 0, sizeof(layer)); memset(&instrument, 0, sizeof(instrument)); wave.format = ((s->flags & SF_SIGNED) ? 0 : GUS_WAVE_INVERT) | ((s->flags & SF_16BITS) ? GUS_WAVE_16BIT : 0) | ((s->flags & SF_DELTA ) ? GUS_WAVE_DELTA : 0) | ((s->flags & SF_LOOP ) ? GUS_WAVE_LOOP : 0) | ((s->flags & SF_BIDI ) ? GUS_WAVE_BIDIR : 0); wave.begin.ptr = buffer; wave.loop_start = loopstart << 4; wave.loop_end = loopend << 4; wave.size = length; layer.wave = &wave; instrument.mode = layer.mode = wave.mode = GUS_INSTR_SIMPLE; instrument.number.instrument = handle; instrument.info.layer = &layer; /* Download the sample to GUS RAM */ if (libgus_memory_alloc(&instrument)) { free(buffer); _mm_errno = MMERR_SAMPLE_TOO_BIG; return -1; } free(buffer); return handle;}/* Discards a sample from the GUS memory and mark handle as free */static void Ultra_SampleUnload(SWORD handle){ gus_instrument_t instrument; if (handle >= GUS_SAMPLES || handle < 0 || !samples[handle]) return; memset(&instrument, 0, sizeof(instrument)); instrument.mode = GUS_INSTR_SIMPLE; instrument.number.instrument = handle; libgus_memory_free(&instrument); samples[handle] = NULL;}/* Reports available sample space */static ULONG Ultra_SampleSpace(void){ libgus_memory_pack(); return (libgus_memory_free_size());}/* Reports the size of a sample */static ULONG Ultra_SampleLength(SAMPLE *s){ if (!s) return 0; if (s->flags & SF_16BITS) return ((s->length << 1) + 31) & ~31; else return ( s->length + 15) & ~15;}/* Initializes the driver */static BOOL Ultra_Init_internal(void){ gus_info_t info; /* Open the GUS card */ if ((ultra_handle = libgus_open(ultra_dev, SIZE_OF_SEQBUF, 0)) < 0) { _mm_errno = (errno == ENOMEM) ? MMERR_OUT_OF_MEMORY : MMERR_INVALID_DEVICE; return 1; } libgus_select(ultra_handle); ultra_fd = libgus_get_handle(); /* Get card information */ libgus_info(&info, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -