📄 mdriver.c
字号:
/* MikMod sound library
(c) 1998, 1999, 2000, 2001 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: mdriver.c,v 1.3 2004/02/18 13:29:19 raph Exp $
These routines are used to access the available soundcard drivers.
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined unix || (defined __APPLE__ && defined __MACH__)
#include <pwd.h>
#include <sys/stat.h>
#endif
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
static MDRIVER *firstdriver=NULL;
MIKMODAPI MDRIVER *md_driver=NULL;
extern MODULE *pf; /* modfile being played */
/* Initial global settings */
MIKMODAPI UWORD md_device = 0; /* autodetect */
MIKMODAPI UWORD md_mixfreq = 44100;
MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS |
DMODE_SURROUND |DMODE_SOFT_MUSIC |
DMODE_SOFT_SNDFX;
MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */
MIKMODAPI UBYTE md_reverb = 0; /* no reverb */
MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */
MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */
MIKMODAPI UBYTE md_sndfxvolume = 128; /* volume of sound effects */
UWORD md_bpm = 125; /* tempo */
/* Do not modify the numchn variables yourself! use MD_SetVoices() */
UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;
UBYTE md_hardchn=0,md_softchn=0;
void (*md_player)(void) = Player_HandleTick;
static BOOL isplaying=0, initialized = 0;
static UBYTE *sfxinfo;
static int sfxpool;
static SAMPLE **md_sample = NULL;
/* Previous driver in use */
static SWORD olddevice = -1;
/* Limits the number of hardware voices to the specified amount.
This function should only be used by the low-level drivers. */
static void LimitHardVoices(int limit)
{
int t=0;
if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
if (!(md_mode & DMODE_SOFT_SNDFX))
md_hardchn=md_sfxchn;
else
md_hardchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;
while (md_hardchn>limit) {
if (++t & 1) {
if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
} else {
if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
}
if (!(md_mode & DMODE_SOFT_SNDFX))
md_hardchn=md_sfxchn;
else
md_hardchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC))
md_hardchn+=md_sngchn;
}
md_numchn=md_hardchn+md_softchn;
}
/* Limits the number of hardware voices to the specified amount.
This function should only be used by the low-level drivers. */
static void LimitSoftVoices(int limit)
{
int t=0;
if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
if (md_mode & DMODE_SOFT_SNDFX)
md_softchn=md_sfxchn;
else
md_softchn=0;
if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;
while (md_softchn>limit) {
if (++t & 1) {
if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
} else {
if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
}
if (!(md_mode & DMODE_SOFT_SNDFX))
md_softchn=md_sfxchn;
else
md_softchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC))
md_softchn+=md_sngchn;
}
md_numchn=md_hardchn+md_softchn;
}
/* Note: 'type' indicates whether the returned value should be for music or for
sound effects. */
ULONG MD_SampleSpace(int type)
{
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
return md_driver->FreeSampleSpace(type);
}
ULONG MD_SampleLength(int type,SAMPLE* s)
{
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else
if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
return md_driver->RealSampleLength(type,s);
}
MIKMODAPI CHAR* MikMod_InfoDriver(void)
{
int t,len=0;
MDRIVER *l;
CHAR *list=NULL;
MUTEX_LOCK(lists);
/* compute size of buffer */
for(l=firstdriver;l;l=l->next)
len+=4+(l->next?1:0)+strlen(l->Version);
if(len)
if((list=_mm_malloc(len*sizeof(CHAR)))) {
list[0]=0;
/* list all registered device drivers : */
for(t=1,l=firstdriver;l;l=l->next,t++)
sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",
list,t,l->Version);
}
MUTEX_UNLOCK(lists);
return list;
}
void _mm_registerdriver(struct MDRIVER* drv)
{
MDRIVER *cruise = firstdriver;
/* don't register a MISSING() driver */
if ((drv->Name) && (drv->Version)) {
if (cruise) {
while (cruise->next) cruise = cruise->next;
cruise->next = drv;
} else
firstdriver = drv;
}
}
MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv)
{
/* if we try to register an invalid driver, or an already registered driver,
ignore this attempt */
if ((!drv)||(drv->next)||(!drv->Name))
return;
MUTEX_LOCK(lists);
_mm_registerdriver(drv);
MUTEX_UNLOCK(lists);
}
MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias)
{
int rank=1;
MDRIVER *cruise;
MUTEX_LOCK(lists);
cruise=firstdriver;
while(cruise) {
if (cruise->Alias) {
if (!(strcasecmp(alias,cruise->Alias))) break;
rank++;
}
cruise=cruise->next;
}
if(!cruise) rank=0;
MUTEX_UNLOCK(lists);
return rank;
}
MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal)
{
MDRIVER *cruise;
/* Allow only driver ordinals > 0 */
if (!ordinal)
return 0;
MUTEX_LOCK(lists);
cruise = firstdriver;
while (cruise && --ordinal)
cruise = cruise->next;
MUTEX_UNLOCK(lists);
return cruise;
}
SWORD MD_SampleLoad(SAMPLOAD* s, int type)
{
SWORD result;
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
SL_Init(s);
result=md_driver->SampleLoad(s,type);
SL_Exit(s);
return result;
}
void MD_SampleUnload(SWORD handle)
{
md_driver->SampleUnload(handle);
}
MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)
{
MikMod_player_t result;
MUTEX_LOCK(vars);
result=md_player;
md_player=player;
MUTEX_UNLOCK(vars);
return result;
}
MIKMODAPI void MikMod_Update(void)
{
MUTEX_LOCK(vars);
if(isplaying) {
if((!pf)||(!pf->forbid))
md_driver->Update();
else {
if (md_driver->Pause)
md_driver->Pause();
}
}
MUTEX_UNLOCK(vars);
}
void Voice_SetVolume_internal(SBYTE voice,UWORD vol)
{
ULONG tmp;
if((voice<0)||(voice>=md_numchn)) return;
/* range checks */
if(md_musicvolume>128) md_musicvolume=128;
if(md_sndfxvolume>128) md_sndfxvolume=128;
if(md_volume>128) md_volume=128;
tmp=(ULONG)vol*(ULONG)md_volume*
((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);
md_driver->VoiceSetVolume(voice,tmp/16384UL);
}
MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)
{
MUTEX_LOCK(vars);
Voice_SetVolume_internal(voice,vol);
MUTEX_UNLOCK(vars);
}
MIKMODAPI UWORD Voice_GetVolume(SBYTE voice)
{
UWORD result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetVolume(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)
{
if((voice<0)||(voice>=md_numchn)) return;
if((md_sample[voice])&&(md_sample[voice]->divfactor))
frq/=md_sample[voice]->divfactor;
md_driver->VoiceSetFrequency(voice,frq);
}
MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)
{
MUTEX_LOCK(vars);
Voice_SetFrequency_internal(voice,frq);
MUTEX_UNLOCK(vars);
}
MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice)
{
ULONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetFrequency(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_SetPanning_internal(SBYTE voice,ULONG pan)
{
if((voice<0)||(voice>=md_numchn)) return;
if(pan!=PAN_SURROUND) {
if(md_pansep>128) md_pansep=128;
if(md_mode & DMODE_REVERSE) pan=255-pan;
pan = (((SWORD)(pan-128)*md_pansep)/128)+128;
}
md_driver->VoiceSetPanning(voice, pan);
}
MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan)
{
#ifdef MIKMOD_DEBUG
if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255)))
fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan);
#endif
MUTEX_LOCK(vars);
Voice_SetPanning_internal(voice,pan);
MUTEX_UNLOCK(vars);
}
MIKMODAPI ULONG Voice_GetPanning(SBYTE voice)
{
ULONG result=PAN_CENTER;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetPanning(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)
{
ULONG repend;
if((voice<0)||(voice>=md_numchn)) return;
md_sample[voice]=s;
repend=s->loopend;
if(s->flags&SF_LOOP)
/* repend can't be bigger than size */
if(repend>s->length) repend=s->length;
md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
}
MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)
{
if(start>s->length) return;
MUTEX_LOCK(vars);
Voice_Play_internal(voice,s,start);
MUTEX_UNLOCK(vars);
}
void Voice_Stop_internal(SBYTE voice)
{
if((voice<0)||(voice>=md_numchn)) return;
if(voice>=md_sngchn)
/* It is a sound effects channel, so flag the voice as non-critical! */
sfxinfo[voice-md_sngchn]=0;
md_driver->VoiceStop(voice);
}
MIKMODAPI void Voice_Stop(SBYTE voice)
{
MUTEX_LOCK(vars);
Voice_Stop_internal(voice);
MUTEX_UNLOCK(vars);
}
BOOL Voice_Stopped_internal(SBYTE voice)
{
if((voice<0)||(voice>=md_numchn)) return 0;
return(md_driver->VoiceStopped(voice));
}
MIKMODAPI BOOL Voice_Stopped(SBYTE voice)
{
BOOL result;
MUTEX_LOCK(vars);
result=Voice_Stopped_internal(voice);
MUTEX_UNLOCK(vars);
return result;
}
MIKMODAPI SLONG Voice_GetPosition(SBYTE voice)
{
SLONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn)) {
if (md_driver->VoiceGetPosition)
result=(md_driver->VoiceGetPosition(voice));
else
result=-1;
}
MUTEX_UNLOCK(vars);
return result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -