--- /dev/null
+/* MikMod sound library\r
+ (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+ for complete list.\r
+\r
+ This library is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU Library General Public License as\r
+ published by the Free Software Foundation; either version 2 of\r
+ the License, or (at your option) any later version.\r
+ \r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU Library General Public License for more details.\r
+ \r
+ You should have received a copy of the GNU Library General Public\r
+ License along with this library; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+ 02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+ $Id: mdriver.c,v 1.3 2004/02/18 13:29:19 raph Exp $\r
+\r
+ These routines are used to access the available soundcard drivers.\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#if defined unix || (defined __APPLE__ && defined __MACH__)\r
+#include <pwd.h>\r
+#include <sys/stat.h>\r
+#endif\r
+\r
+#include <string.h>\r
+#ifdef HAVE_STRINGS_H\r
+#include <strings.h>\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+static MDRIVER *firstdriver=NULL;\r
+\r
+extern MODULE *pf; /* modfile being played */\r
+\r
+/* Initial global settings */\r
+MIKMODAPI UWORD md_device = 0; /* autodetect */\r
+MIKMODAPI UWORD md_mixfreq = 44100;\r
+MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS |\r
+ DMODE_SURROUND |DMODE_SOFT_MUSIC |\r
+ DMODE_SOFT_SNDFX;\r
+MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */\r
+MIKMODAPI UBYTE md_reverb = 0; /* no reverb */\r
+MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */\r
+MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */\r
+MIKMODAPI UBYTE md_sndfxvolume = 128; /* volume of sound effects */\r
+ UWORD md_bpm = 125; /* tempo */\r
+\r
+/* Do not modify the numchn variables yourself! use MD_SetVoices() */\r
+ UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;\r
+ UBYTE md_hardchn=0,md_softchn=0;\r
+\r
+ void (*md_player)(void) = Player_HandleTick;\r
+static BOOL isplaying=0, initialized = 0;\r
+static UBYTE *sfxinfo;\r
+static int sfxpool;\r
+\r
+static SAMPLE **md_sample = NULL;\r
+\r
+/* Previous driver in use *\r
+static SWORD olddevice = -1;\r
+*/\r
+/* Limits the number of hardware voices to the specified amount.\r
+ This function should only be used by the low-level drivers. */\r
+static void LimitHardVoices(int limit)\r
+{\r
+ int t=0;\r
+\r
+ if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;\r
+ if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;\r
+\r
+ if (!(md_mode & DMODE_SOFT_SNDFX))\r
+ md_hardchn=md_sfxchn;\r
+ else\r
+ md_hardchn=0;\r
+\r
+ if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;\r
+\r
+ while (md_hardchn>limit) {\r
+ if (++t & 1) {\r
+ if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;\r
+ } else {\r
+ if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;\r
+ }\r
+\r
+ if (!(md_mode & DMODE_SOFT_SNDFX))\r
+ md_hardchn=md_sfxchn;\r
+ else\r
+ md_hardchn=0;\r
+\r
+ if (!(md_mode & DMODE_SOFT_MUSIC))\r
+ md_hardchn+=md_sngchn;\r
+ }\r
+ md_numchn=md_hardchn+md_softchn;\r
+}\r
+\r
+/* Limits the number of hardware voices to the specified amount.\r
+ This function should only be used by the low-level drivers. */\r
+static void LimitSoftVoices(int limit)\r
+{\r
+ int t=0;\r
+\r
+ if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;\r
+ if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;\r
+\r
+ if (md_mode & DMODE_SOFT_SNDFX)\r
+ md_softchn=md_sfxchn;\r
+ else\r
+ md_softchn=0;\r
+\r
+ if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;\r
+\r
+ while (md_softchn>limit) {\r
+ if (++t & 1) {\r
+ if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;\r
+ } else {\r
+ if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;\r
+ }\r
+\r
+ if (!(md_mode & DMODE_SOFT_SNDFX))\r
+ md_softchn=md_sfxchn;\r
+ else\r
+ md_softchn=0;\r
+\r
+ if (!(md_mode & DMODE_SOFT_MUSIC))\r
+ md_softchn+=md_sngchn;\r
+ }\r
+ md_numchn=md_hardchn+md_softchn;\r
+}\r
+\r
+/* Note: 'type' indicates whether the returned value should be for music or for\r
+ sound effects. */\r
+ULONG MD_SampleSpace(int type)\r
+{\r
+ if(type==MD_MUSIC)\r
+ type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;\r
+ else if(type==MD_SNDFX)\r
+ type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;\r
+\r
+ return VC_SampleSpace(type);\r
+}\r
+\r
+ULONG MD_SampleLength(int type,SAMPLE* s)\r
+{\r
+ if(type==MD_MUSIC)\r
+ type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;\r
+ else\r
+ if(type==MD_SNDFX)\r
+ type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;\r
+\r
+ return VC_SampleLength(type,s);\r
+}\r
+/*\r
+MIKMODAPI CHAR* MikMod_InfoDriver(void)\r
+{\r
+ int t,len=0;\r
+ MDRIVER *l;\r
+ CHAR *list=NULL;\r
+\r
+ MUTEX_LOCK(lists);\r
+ /* compute size of buffer *\r
+ for(l=firstdriver;l;l=l->next)\r
+ len+=4+(l->next?1:0)+strlen(l->Version);\r
+\r
+ if(len)\r
+ if((list=_mm_malloc(len*sizeof(CHAR)))) {\r
+ list[0]=0;\r
+ /* list all registered device drivers : *\r
+ for(t=1,l=firstdriver;l;l=l->next,t++)\r
+ sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",\r
+ list,t,l->Version);\r
+ }\r
+ MUTEX_UNLOCK(lists);\r
+ return list;\r
+}\r
+*/\r
+void _mm_registerdriver(struct MDRIVER* drv)\r
+{\r
+ MDRIVER *cruise = firstdriver;\r
+\r
+ /* don't register a MISSING() driver */\r
+ if ((drv->Name) && (drv->Version)) {\r
+ if (cruise) {\r
+ while (cruise->next) cruise = cruise->next;\r
+ cruise->next = drv;\r
+ } else\r
+ firstdriver = drv; \r
+ }\r
+}\r
+\r
+MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv)\r
+{\r
+ /* if we try to register an invalid driver, or an already registered driver,\r
+ ignore this attempt */\r
+ if ((!drv)||(drv->next)||(!drv->Name))\r
+ return;\r
+\r
+ MUTEX_LOCK(lists);\r
+ _mm_registerdriver(drv);\r
+ MUTEX_UNLOCK(lists);\r
+}\r
+\r
+MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias)\r
+{\r
+ int rank=1;\r
+ MDRIVER *cruise;\r
+\r
+ MUTEX_LOCK(lists);\r
+ cruise=firstdriver;\r
+ while(cruise) {\r
+ if (cruise->Alias) {\r
+ if (!(strcasecmp(alias,cruise->Alias))) break;\r
+ rank++;\r
+ }\r
+ cruise=cruise->next;\r
+ }\r
+ if(!cruise) rank=0;\r
+ MUTEX_UNLOCK(lists);\r
+\r
+ return rank;\r
+}\r
+\r
+MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal)\r
+{\r
+ MDRIVER *cruise;\r
+\r
+ /* Allow only driver ordinals > 0 */\r
+ if (!ordinal)\r
+ return 0;\r
+\r
+ MUTEX_LOCK(lists);\r
+ cruise = firstdriver;\r
+ while (cruise && --ordinal)\r
+ cruise = cruise->next;\r
+ MUTEX_UNLOCK(lists);\r
+ return cruise;\r
+}\r
+\r
+SWORD MD_SampleLoad(SAMPLOAD* s, int type)\r
+{\r
+ SWORD result;\r
+\r
+ if(type==MD_MUSIC)\r
+ type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;\r
+ else if(type==MD_SNDFX)\r
+ type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;\r
+\r
+ SL_Init(s);\r
+ result=VC_SampleLoad(s,type);\r
+ SL_Exit(s);\r
+\r
+ return result;\r
+}\r
+\r
+void MD_SampleUnload(SWORD handle)\r
+{\r
+ VC_SampleUnload(handle);\r
+}\r
+\r
+MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)\r
+{\r
+ MikMod_player_t result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ result=md_player;\r
+ md_player=player;\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+MIKMODAPI void MikMod_Update(void)\r
+{\r
+ MUTEX_LOCK(vars);\r
+ /* FIXME - if I'm broken...\r
+ if(isplaying)\r
+ {\r
+ if((!pf)||(!pf->forbid))\r
+ {\r
+ md_driver->Update();\r
+ }\r
+ else\r
+ {\r
+ if (md_driver->Pause)\r
+ md_driver->Pause();\r
+ }\r
+ }\r
+ */\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+void Voice_SetVolume_internal(SBYTE voice,UWORD vol)\r
+{\r
+ ULONG tmp;\r
+\r
+ if((voice<0)||(voice>=md_numchn)) return;\r
+\r
+ /* range checks */\r
+ if(md_musicvolume>128) md_musicvolume=128;\r
+ if(md_sndfxvolume>128) md_sndfxvolume=128;\r
+ if(md_volume>128) md_volume=128;\r
+\r
+ tmp=(ULONG)vol*(ULONG)md_volume*\r
+ ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);\r
+ VC_VoiceSetVolume(voice,tmp/16384UL);\r
+}\r
+\r
+MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)\r
+{\r
+ MUTEX_LOCK(vars);\r
+ Voice_SetVolume_internal(voice,vol);\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI UWORD Voice_GetVolume(SBYTE voice)\r
+{\r
+ UWORD result=0;\r
+\r
+ MUTEX_LOCK(vars);\r
+ if((voice>=0)&&(voice<md_numchn))\r
+ result=VC_VoiceGetVolume(voice);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)\r
+{\r
+ if((voice<0)||(voice>=md_numchn)) return;\r
+ if((md_sample[voice])&&(md_sample[voice]->divfactor))\r
+ frq/=md_sample[voice]->divfactor;\r
+ VC_VoiceSetFrequency(voice,frq);\r
+}\r
+\r
+MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)\r
+{\r
+ MUTEX_LOCK(vars);\r
+ Voice_SetFrequency_internal(voice,frq);\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice)\r
+{\r
+ ULONG result=0;\r
+\r
+ MUTEX_LOCK(vars);\r
+ if((voice>=0)&&(voice<md_numchn))\r
+ result=VC_VoiceGetFrequency(voice);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+void Voice_SetPanning_internal(SBYTE voice,ULONG pan)\r
+{\r
+ if((voice<0)||(voice>=md_numchn)) return;\r
+ if(pan!=PAN_SURROUND) {\r
+ if(md_pansep>128) md_pansep=128;\r
+ if(md_mode & DMODE_REVERSE) pan=255-pan;\r
+ pan = (((SWORD)(pan-128)*md_pansep)/128)+128;\r
+ }\r
+ VC_VoiceSetPanning(voice, pan);\r
+}\r
+\r
+MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan)\r
+{\r
+#ifdef MIKMOD_DEBUG\r
+ if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255)))\r
+ fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan);\r
+#endif\r
+\r
+ MUTEX_LOCK(vars);\r
+ Voice_SetPanning_internal(voice,pan);\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI ULONG Voice_GetPanning(SBYTE voice)\r
+{\r
+ ULONG result=PAN_CENTER;\r
+\r
+ MUTEX_LOCK(vars);\r
+ if((voice>=0)&&(voice<md_numchn))\r
+ result=VC_VoiceGetPanning(voice);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)\r
+{\r
+ ULONG repend;\r
+\r
+ if((voice<0)||(voice>=md_numchn)) return;\r
+\r
+ md_sample[voice]=s;\r
+ repend=s->loopend;\r
+\r
+ if(s->flags&SF_LOOP)\r
+ /* repend can't be bigger than size */\r
+ if(repend>s->length) repend=s->length;\r
+\r
+ VC_VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);\r
+}\r
+\r
+MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)\r
+{\r
+ if(start>s->length) return;\r
+\r
+ MUTEX_LOCK(vars);\r
+ Voice_Play_internal(voice,s,start);\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+void Voice_Stop_internal(SBYTE voice)\r
+{\r
+ if((voice<0)||(voice>=md_numchn)) return;\r
+ if(voice>=md_sngchn)\r
+ /* It is a sound effects channel, so flag the voice as non-critical! */\r
+ sfxinfo[voice-md_sngchn]=0;\r
+ VC_VoiceStop(voice);\r
+}\r
+\r
+MIKMODAPI void Voice_Stop(SBYTE voice)\r
+{\r
+ MUTEX_LOCK(vars);\r
+ Voice_Stop_internal(voice);\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+BOOL Voice_Stopped_internal(SBYTE voice)\r
+{\r
+ if((voice<0)||(voice>=md_numchn)) return 0;\r
+ return(VC_VoiceStopped(voice));\r
+}\r
+\r
+MIKMODAPI BOOL Voice_Stopped(SBYTE voice)\r
+{\r
+ BOOL result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ result=Voice_Stopped_internal(voice);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+MIKMODAPI SLONG Voice_GetPosition(SBYTE voice)\r
+{\r
+ SLONG result=0;\r
+\r
+ MUTEX_LOCK(vars);\r
+ if((voice>=0)&&(voice<md_numchn)) {\r
+ /*if (VC_VoiceGetPosition)*/\r
+ result=(VC_VoiceGetPosition(voice));\r
+ /*else\r
+ result=-1;*/\r
+ }\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+MIKMODAPI ULONG Voice_RealVolume(SBYTE voice)\r
+{\r
+ ULONG result=0;\r
+\r
+ MUTEX_LOCK(vars);\r
+ if((voice>=0)&&(voice<md_numchn)/*&& VC_VoiceRealVolume*/)\r
+ result=(VC_VoiceRealVolume(voice));\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+static BOOL _mm_init(CHAR *cmdline)\r
+{\r
+ /* UWORD t; */\r
+ (void)cmdline;\r
+\r
+ _mm_critical = 1;\r
+/*\r
+ /* if md_device==0, try to find a device number *\r
+ if(!md_device) {\r
+ cmdline=NULL;\r
+\r
+ for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)\r
+ if(md_driver->IsPresent()) break;\r
+\r
+ if(!md_driver) {\r
+ _mm_errno = MMERR_DETECTING_DEVICE;\r
+ if(_mm_errorhandler) _mm_errorhandler();\r
+ md_driver = &drv_nos;\r
+ return 1;\r
+ }\r
+\r
+ md_device = t;\r
+ } else {\r
+ /* if n>0, use that driver *\r
+ for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next)\r
+ t++;\r
+\r
+ if(!md_driver) {\r
+ _mm_errno = MMERR_INVALID_DEVICE;\r
+ if(_mm_errorhandler) _mm_errorhandler();\r
+ md_driver = &drv_nos;\r
+ return 1;\r
+ }\r
+\r
+ /* arguments here might be necessary for the presence check to succeed *\r
+ if(cmdline&&(md_driver->CommandLine))\r
+ md_driver->CommandLine(cmdline);\r
+\r
+ if(!md_driver->IsPresent()) {\r
+ _mm_errno = MMERR_DETECTING_DEVICE;\r
+ if(_mm_errorhandler) _mm_errorhandler();\r
+ md_driver = &drv_nos;\r
+ return 1;\r
+ }\r
+ }\r
+\r
+ olddevice = md_device;\r
+*/\r
+ md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;\r
+\r
+ if(VC_Init()) {\r
+ MikMod_Exit_internal();\r
+ if(_mm_errorhandler) _mm_errorhandler();\r
+ return 1;\r
+ }\r
+\r
+ initialized=1;\r
+ _mm_critical=0;\r
+\r
+ return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_Init(CHAR *cmdline)\r
+{\r
+ BOOL result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ MUTEX_LOCK(lists);\r
+ result=_mm_init(cmdline);\r
+ MUTEX_UNLOCK(lists);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+void MikMod_Exit_internal(void)\r
+{\r
+ MikMod_DisableOutput_internal();\r
+ VC_Exit();\r
+ md_numchn = md_sfxchn = md_sngchn = 0;\r
+ //md_driver = &drv_nos;\r
+\r
+ if(sfxinfo) free(sfxinfo);\r
+ if(md_sample) free(md_sample);\r
+ md_sample = NULL;\r
+ sfxinfo = NULL;\r
+\r
+ initialized = 0;\r
+}\r
+\r
+MIKMODAPI void MikMod_Exit(void)\r
+{\r
+ MUTEX_LOCK(vars);\r
+ MUTEX_LOCK(lists);\r
+ MikMod_Exit_internal();\r
+ MUTEX_UNLOCK(lists);\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+/* Reset the driver using the new global variable settings. \r
+ If the driver has not been initialized, it will be now. */\r
+static BOOL _mm_reset(CHAR *cmdline)\r
+{\r
+ BOOL wasplaying = 0;\r
+\r
+ if(!initialized) return _mm_init(cmdline);\r
+ \r
+ if (isplaying) {\r
+ wasplaying = 1;\r
+ VC_PlayStop();\r
+ }\r
+/*\r
+ if((!md_driver->Reset)||(md_device != olddevice)) {\r
+ /* md_driver->Reset was NULL, or md_device was changed, so do a full\r
+ reset of the driver. *\r
+ md_driver->Exit();\r
+ if(_mm_init(cmdline)) {\r
+ MikMod_Exit_internal();\r
+ if(_mm_errno)\r
+ if(_mm_errorhandler) _mm_errorhandler();\r
+ return 1;\r
+ }\r
+ } else {\r
+ if(md_driver->Reset()) {\r
+ MikMod_Exit_internal();\r
+ if(_mm_errno)\r
+ if(_mm_errorhandler) _mm_errorhandler();\r
+ return 1;\r
+ }\r
+ }\r
+*/\r
+ if (wasplaying) VC_PlayStart();\r
+ return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_Reset(CHAR *cmdline)\r
+{\r
+ BOOL result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ MUTEX_LOCK(lists);\r
+ result=_mm_reset(cmdline);\r
+ MUTEX_UNLOCK(lists);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+/* If either parameter is -1, the current set value will be retained. */\r
+BOOL MikMod_SetNumVoices_internal(int music, int sfx)\r
+{\r
+ BOOL resume = 0;\r
+ int t, oldchn = 0;\r
+\r
+ if((!music)&&(!sfx)) return 1;\r
+ _mm_critical = 1;\r
+ if(isplaying) {\r
+ MikMod_DisableOutput_internal();\r
+ oldchn = md_numchn;\r
+ resume = 1;\r
+ }\r
+\r
+ if(sfxinfo) free(sfxinfo);\r
+ if(md_sample) free(md_sample);\r
+ md_sample = NULL;\r
+ sfxinfo = NULL;\r
+\r
+ if(music!=-1) md_sngchn = music;\r
+ if(sfx!=-1) md_sfxchn = sfx;\r
+ md_numchn = md_sngchn + md_sfxchn;\r
+/*\r
+ LimitHardVoices(md_driver->HardVoiceLimit);\r
+ LimitSoftVoices(md_driver->SoftVoiceLimit);\r
+*/\r
+ LimitHardVoices(0);\r
+ LimitSoftVoices(255);\r
+\r
+ if(VC_SetNumVoices()) {\r
+ MikMod_Exit_internal();\r
+ if(_mm_errno)\r
+ if(_mm_errorhandler!=NULL) _mm_errorhandler();\r
+ md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;\r
+ return 1;\r
+ }\r
+\r
+ if(md_sngchn+md_sfxchn)\r
+ md_sample=(SAMPLE**)_mm_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));\r
+ if(md_sfxchn)\r
+ sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn,sizeof(UBYTE));\r
+\r
+ /* make sure the player doesn't start with garbage */\r
+ for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t);\r
+\r
+ sfxpool = 0;\r
+ if(resume) MikMod_EnableOutput_internal();\r
+ _mm_critical = 0;\r
+\r
+ return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_SetNumVoices(int music, int sfx)\r
+{\r
+ BOOL result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ result=MikMod_SetNumVoices_internal(music,sfx);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+BOOL MikMod_EnableOutput_internal(void)\r
+{\r
+ _mm_critical = 1;\r
+ if(!isplaying) {\r
+ if(VC_PlayStart()) return 1;\r
+ isplaying = 1;\r
+ }\r
+ _mm_critical = 0;\r
+ return 0;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_EnableOutput(void)\r
+{\r
+ BOOL result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ result=MikMod_EnableOutput_internal();\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+void MikMod_DisableOutput_internal(void)\r
+{\r
+ if(isplaying/* && md_driver*/) {\r
+ isplaying = 0;\r
+ VC_PlayStop();\r
+ }\r
+}\r
+\r
+MIKMODAPI void MikMod_DisableOutput(void)\r
+{\r
+ MUTEX_LOCK(vars);\r
+ MikMod_DisableOutput_internal();\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+BOOL MikMod_Active_internal(void)\r
+{\r
+ return isplaying;\r
+}\r
+\r
+MIKMODAPI BOOL MikMod_Active(void)\r
+{\r
+ BOOL result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ result=MikMod_Active_internal();\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+/* Plays a sound effects sample. Picks a voice from the number of voices\r
+ allocated for use as sound effects (loops through voices, skipping all active\r
+ criticals).\r
+\r
+ Returns the voice that the sound is being played on. */\r
+SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags)\r
+{\r
+ int orig=sfxpool;/* for cases where all channels are critical */\r
+ int c;\r
+\r
+ if(!md_sfxchn) return -1;\r
+ if(s->volume>64) s->volume = 64;\r
+\r
+ /* check the first location after sfxpool */\r
+ do {\r
+ if(sfxinfo[sfxpool]&SFX_CRITICAL) {\r
+ if(VC_VoiceStopped(c=sfxpool+md_sngchn)) {\r
+ sfxinfo[sfxpool]=flags;\r
+ Voice_Play_internal(c,s,start);\r
+ VC_VoiceSetVolume(c,s->volume<<2);\r
+ Voice_SetPanning_internal(c,s->panning);\r
+ VC_VoiceSetFrequency(c,s->speed);\r
+ sfxpool++;\r
+ if(sfxpool>=md_sfxchn) sfxpool=0;\r
+ return c;\r
+ }\r
+ } else {\r
+ sfxinfo[sfxpool]=flags;\r
+ Voice_Play_internal(c=sfxpool+md_sngchn,s,start);\r
+ VC_VoiceSetVolume(c,s->volume<<2);\r
+ Voice_SetPanning_internal(c,s->panning);\r
+ VC_VoiceSetFrequency(c,s->speed);\r
+ sfxpool++;\r
+ if(sfxpool>=md_sfxchn) sfxpool=0;\r
+ return c;\r
+ }\r
+\r
+ sfxpool++;\r
+ if(sfxpool>=md_sfxchn) sfxpool = 0;\r
+ } while(sfxpool!=orig);\r
+\r
+ return -1;\r
+}\r
+\r
+MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)\r
+{\r
+ SBYTE result;\r
+\r
+ MUTEX_LOCK(vars);\r
+ result=Sample_Play_internal(s,start,flags);\r
+ MUTEX_UNLOCK(vars);\r
+\r
+ return result;\r
+}\r
+\r
+MIKMODAPI long MikMod_GetVersion(void)\r
+{\r
+ return LIBMIKMOD_VERSION;\r
+}\r
+\r
+/*========== MT-safe stuff */\r
+\r
+#ifdef HAVE_PTHREAD\r
+#define INIT_MUTEX(name) \\r
+ pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER\r
+#elif defined(__OS2__)||defined(__EMX__)\r
+#define INIT_MUTEX(name) \\r
+ HMTX _mm_mutex_##name\r
+#elif defined(WIN32)\r
+#define INIT_MUTEX(name) \\r
+ HANDLE _mm_mutex_##name\r
+#else\r
+#define INIT_MUTEX(name) \\r
+ void *_mm_mutex_##name = NULL\r
+#endif\r
+\r
+INIT_MUTEX(vars);\r
+INIT_MUTEX(lists);\r
+\r
+MIKMODAPI BOOL MikMod_InitThreads(void)\r
+{\r
+ static int firstcall=1;\r
+ static int result=0;\r
+ \r
+ if (firstcall) {\r
+ firstcall=0;\r
+#ifdef HAVE_PTHREAD\r
+ result=1;\r
+#elif defined(__OS2__)||defined(__EMX__)\r
+ if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) ||\r
+ DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) {\r
+ _mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL;\r
+ result=0;\r
+ } else\r
+ result=1;\r
+#elif defined(WIN32)\r
+ if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))||\r
+ (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)"))))\r
+ result=0;\r
+ else\r
+ result=1;\r
+#endif\r
+ }\r
+ return result;\r
+}\r
+\r
+MIKMODAPI void MikMod_Unlock(void)\r
+{\r
+ MUTEX_UNLOCK(lists);\r
+ MUTEX_UNLOCK(vars);\r
+}\r
+\r
+MIKMODAPI void MikMod_Lock(void)\r
+{\r
+ MUTEX_LOCK(vars);\r
+ MUTEX_LOCK(lists);\r
+}\r
+\r
+/*========== Parameter extraction helper */\r
+\r
+CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,BOOL implicit)\r
+{\r
+ CHAR *ret=NULL;\r
+\r
+ if(cmdline) {\r
+ CHAR *buf=strstr(cmdline,atomname);\r
+\r
+ if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {\r
+ CHAR *ptr=buf+strlen(atomname);\r
+\r
+ if(*ptr=='=') {\r
+ for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++);\r
+ ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));\r
+ if(ret)\r
+ strncpy(ret,buf,ptr-buf);\r
+ } else if((*ptr==',')||(!*ptr)) {\r
+ if(implicit) {\r
+ ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));\r
+ if(ret)\r
+ strncpy(ret,buf,ptr-buf);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return ret;\r
+}\r
+\r
+#if defined unix || (defined __APPLE__ && defined __MACH__)\r
+\r
+/*========== Posix helper functions */\r
+\r
+/* Check if the file is a regular or nonexistant file (or a link to a such a\r
+ file), and that, should the calling program be setuid, the access rights are\r
+ reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise.\r
+ The goal is to prevent a setuid root libmikmod application from overriding\r
+ files like /etc/passwd with digital sound... */\r
+BOOL MD_Access(CHAR *filename)\r
+{\r
+ struct stat buf;\r
+\r
+ if(!stat(filename,&buf)) {\r
+ /* not a regular file ? */\r
+ if(!S_ISREG(buf.st_mode)) return 0;\r
+ /* more than one hard link to the file ? */\r
+ if(buf.st_nlink>1) return 0;\r
+ /* check access rights with the real user and group id */\r
+ if(getuid()==buf.st_uid) {\r
+ if(!(buf.st_mode&S_IWUSR)) return 0;\r
+ } else if(getgid()==buf.st_gid) {\r
+ if(!(buf.st_mode&S_IWGRP)) return 0;\r
+ } else\r
+ if(!(buf.st_mode&S_IWOTH)) return 0;\r
+ }\r
+ \r
+ return 1;\r
+}\r
+\r
+/* Drop all root privileges we might have */\r
+BOOL MD_DropPrivileges(void)\r
+{\r
+ if(!geteuid()) {\r
+ if(getuid()) {\r
+ /* we are setuid root -> drop setuid to become the real user */\r
+ if(setuid(getuid())) return 1;\r
+ } else {\r
+ /* we are run as root -> drop all and become user 'nobody' */\r
+ struct passwd *nobody;\r
+ int uid;\r
+\r
+ if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */\r
+ uid=nobody->pw_uid;\r
+ if (!uid) /* user 'nobody' has root privileges ? weird... */\r
+ return 1;\r
+ if (setuid(uid)) return 1;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+#endif\r
+\r
+/* ex:set ts=4: */\r