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

📄 drv_ultra.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	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_DYNAMIC
static 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;
	}
}
#endif

static 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 + -