diff playercode/mdriver.c @ 12:437e8455d862

General tidy up.. Rename makefile.gcc to Makefile
author darius
date Thu, 23 Apr 1998 07:20:13 +0000
parents 42e11dc15457
children 80fa6dd10e14
line wrap: on
line diff
--- a/playercode/mdriver.c	Fri Jan 23 16:05:11 1998 +0000
+++ b/playercode/mdriver.c	Thu Apr 23 07:20:13 1998 +0000
@@ -1,556 +1,626 @@
-/*
-
-Name:  MDRIVER.C
-
-Description:
-These routines are used to access the available soundcard drivers.
-
-Portability:
-All systems - all compilers
-
-*/
-
-#include "mikmod.h"
-
-MDRIVER *firstdriver = NULL, *md_driver = &drv_nos;
-
-UWORD md_device         = 0;
-UWORD md_mixfreq        = 44100;
-UWORD md_mode           = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND;
-UWORD md_dmabufsize     = 50;
-UBYTE md_pansep         = 128;      // 128 == 100% (full left/right)
-
-UBYTE md_reverb         = 6;       // Reverb
-
-UBYTE md_volume         = 96;       // Global sound volume (0-128)
-UBYTE md_musicvolume    = 128;      // volume of song
-UBYTE md_sndfxvolume    = 128;      // volume of sound effects
-
-UBYTE md_bpm            = 125;
-
-
-// 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;
-
-// Backup variables.  This way, the end programmer can fiddle with the
-// main globals without mikmod blowing up.
-
-static UWORD idevice, imixfreq, imode, idmabufsize;
-
-
-static void LimitHardVoices(int limit)
-
-// Limits the number of hardware voices to the specified amount.
-// This function should only be used by the low-level drivers.
-
-{
-    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;
-}
-
-
-static void LimitSoftVoices(int limit)
-
-// Limits the number of hardware voices to the specified amount.
-// This function should only be used by the low-level drivers.
-
-{
-    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);
-}
-
-
-UWORD MD_SetDMA(int secs)
-
-// Converts the given number of 1/10th seconds into the number of bytes of
-// audio that a sample # 1/10th seconds long would require at the current md_*
-// settings.
-
-{
-    ULONG result;
-
-    result = (md_mixfreq * ((md_mode & DMODE_STEREO) ? 2 : 1) *
-             ((md_mode & DMODE_16BITS) ? 2 : 1) * secs) * 10;
-
-    if(result > 32000) result = 32000;
-    return(md_dmabufsize = (result & ~3));  // round it off to an 8 byte boundry
-}
-
-
-void MD_InfoDriver(void)
-{
-    int t;
-    MDRIVER *l;
-
-    // list all registered devicedrivers:
-    for(t=1,l=firstdriver; l!=NULL; l=l->next, t++)
-        printf("%d. %s\n",t,l->Version);
-}
-
-
-void MD_RegisterDriver(MDRIVER *drv)
-{
-    MDRIVER *cruise = firstdriver;
-
-    if(cruise!=NULL)
-    {   while(cruise->next!=NULL)  cruise = cruise->next;
-        cruise->next = drv;
-    } else
-        firstdriver = drv; 
-}
-
-
-SWORD MD_SampleLoad(SAMPLOAD *s, int type, FILE *fp)
-//  type - sample type .. MD_MUSIC or MD_SNDFX
-{
-    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, fp);
-    SL_Exit(s);
-
-    return result;
-}
-
-
-void MD_SampleUnLoad(SWORD handle)
-{
-    md_driver->SampleUnLoad(handle);
-}
-
-
-void MD_SetBPM(UBYTE bpm)
-{
-    md_bpm = bpm;
-}
-
-
-void MikMod_RegisterPlayer(void (*player)(void))
-{
-    md_player = player;
-}
-
-
-void MikMod_Update(void)
-{
-    if(isplaying) md_driver->Update();
-}
-
-
-void Voice_SetVolume(int voice, UWORD vol)
-{
-    ULONG  tmp;
-
-    if((voice<0) || (voice>=md_numchn)) return;
-    tmp = (ULONG)vol * (ULONG)md_volume * ((voice < md_sngchn) ? (ULONG)md_musicvolume : (ULONG)md_sndfxvolume);
-    md_driver->VoiceSetVolume(voice,tmp/16384UL);
-}
-
-
-void Voice_SetFrequency(int voice, ULONG frq)
-{
-    if((voice < 0) || (voice >= md_numchn)) return;
-    if(md_sample[voice]!=NULL && md_sample[voice]->divfactor!=0) frq/=md_sample[voice]->divfactor;
-    md_driver->VoiceSetFrequency(voice, frq);
-}
-
-
-void Voice_SetPanning(int voice, ULONG pan)
-{
-    if((voice < 0) || (voice >= md_numchn)) return;
-    if(pan!=PAN_SURROUND)
-    {   if(md_mode & DMODE_REVERSE) pan = 255-pan;
-        pan = (((SWORD)(pan-128)*md_pansep) / 128)+128;
-    }
-    md_driver->VoiceSetPanning(voice, pan);
-}
-
-
-void Voice_Play(int voice, SAMPLE *s, ULONG start)
-{
-    ULONG  repend;
-    
-    if((voice < 0) || (voice >= md_numchn) || (start >= s->length)) return;
-
-    md_sample[voice] = s;
-    repend = s->loopend;
-
-    if(s->flags&SF_LOOP)
-       if(repend > s->length) repend = s->length;    // repend can't be bigger than size
-
-    md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
-}
-
-
-void Voice_Stop(int 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);
-}
-
- 
-BOOL Voice_Stopped(int voice)
-{
-    if((voice < 0) || (voice >= md_numchn)) return 0;
-    return(md_driver->VoiceStopped(voice));
-}
-
-
-SLONG Voice_GetPosition(int voice)
-{
-    if((voice < 0) || (voice >= md_numchn)) return 0;
-    return(md_driver->VoiceGetPosition(voice));
-}
-
-
-ULONG Voice_RealVolume(int voice)
-{
-    if((voice < 0) || (voice >= md_numchn)) return 0;
-    return(md_driver->VoiceRealVolume(voice));
-}
-
-
-// ================================
-//  Functions prefixed with MikMod
-// ================================
-
-BOOL MikMod_Init(void)
-{
-    UWORD t;
-
-    _mm_critical = 1;
-
-    // if md_device==0, try to find a device number
-
-    if(md_device==0)
-    {   for(t=1,md_driver=firstdriver; md_driver!=NULL; md_driver=md_driver->next, t++)
-        {   if(md_driver->IsPresent()) break;
-        }
-
-        if(md_driver==NULL)
-        {   _mm_errno = MMERR_DETECTING_DEVICE;
-            if(_mm_errorhandler!=NULL) _mm_errorhandler();
-            md_driver = &drv_nos;
-            return 1;
-        }
-
-        md_device = t;
-    } else
-    {   // if n>0 use that driver
-        for(t=1,md_driver=firstdriver; (md_driver!=NULL) && (t!=md_device); md_driver=md_driver->next, t++);
-
-        if(md_driver==NULL)
-        {   _mm_errno = MMERR_INVALID_DEVICE;
-            if(_mm_errorhandler!=NULL) _mm_errorhandler();
-            md_driver = &drv_nos;
-            return 1;
-        }
-    
-        if(!md_driver->IsPresent())
-        {   _mm_errno = MMERR_DETECTING_DEVICE;
-            if(_mm_errorhandler!=NULL) _mm_errorhandler();
-            md_driver = &drv_nos;
-            return 1;
-        }
-    }
-
-    if(md_driver->Init())
-    {   MikMod_Exit();
-        if(_mm_errorhandler!=NULL) _mm_errorhandler();
-        return 1;
-    }
-
-    idevice  = md_device;   imode       = md_mode;
-    imixfreq = md_mixfreq;  idmabufsize = md_dmabufsize;
-    initialized = 1;
-    _mm_critical = 0;
-
-    return 0;
-}
-
-
-void MikMod_Exit(void)
-{
-    MikMod_DisableOutput();
-    md_driver->Exit();
-    md_numchn = md_sfxchn = md_sngchn = 0;
-    md_driver = &drv_nos;
-    initialized = 0;
-}
-
-
-BOOL MikMod_Reset(void)
-
-// Reset the driver using the new global variable settings.
-// If the driver has not been initialized, it will be now.
-
-{
-    if(!initialized) return MikMod_Init();
-    if((md_driver->Reset == NULL) || (md_device != idevice))
-    {   // md_driver->Reset was NULL, or md_device was changed,
-        // so do a full reset of the driver.
-
-        if(isplaying) md_driver->PlayStop();
-        md_driver->Exit();
-        if(MikMod_Init())
-        {   MikMod_Exit();
-            if(_mm_errorhandler!=NULL) _mm_errorhandler();
-            return 1;
-        }
-        if(isplaying) md_driver->PlayStart();
-    } else
-    {   if(md_driver->Reset())
-        {   MikMod_Exit();
-            if(_mm_errorhandler!=NULL) _mm_errorhandler();
-            return 1;
-        }
-    }
-    
-    return 0;
-}
-
-
-BOOL MikMod_SetNumVoices(int music, int sfx)
-
-// If either parameter is -1, the current set value will be retained.
-
-{
-    BOOL resume = 0;
-    int  t, oldchn = 0;
-
-    if((music==0) && (sfx==0)) return 0;
-
-    _mm_critical = 1;
-
-    if(isplaying)
-    {   MikMod_DisableOutput();
-        oldchn = md_numchn;
-        resume = 1;
-    }
-
-    if(sfxinfo!=NULL)   free(sfxinfo);
-    if(md_sample!=NULL) free(md_sample);
-    md_sample  = NULL;
-    sfxinfo    = NULL;
-
-    /*md_softchn = md_hardchn = 0;
-
-    if(md_mode & DMODE_SOFT_SNDFX)
-       md_softchn = sfx; else md_hardchn = sfx;
-
-    if(md_mode & DMODE_SOFT_MUSIC)
-       md_softchn += music; else md_hardchn += music;
-    */
-
-    if(music != -1) md_sngchn = music;
-    if(sfx != -1)   md_sfxchn = sfx;
-
-    md_numchn = md_sngchn + md_sfxchn;
-
-    LimitHardVoices(md_driver->HardVoiceLimit);
-    LimitSoftVoices(md_driver->SoftVoiceLimit);
-
-    if(md_driver->SetNumVoices())
-    {   MikMod_Exit();
-        md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
-        if(_mm_errorhandler!=NULL) _mm_errorhandler();
-        return 1;
-    }
-
-    if(md_sngchn || md_sfxchn)
-        md_sample = (SAMPLE **)_mm_calloc(md_sngchn+md_sfxchn, sizeof(SAMPLE *));
-    if(md_sfxchn)
-        sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn, sizeof(UBYTE));
-
-    // make sure the player doesn't start with garbage
-    for(t=oldchn; t<md_numchn; t++)  Voice_Stop(t);
-
-    sfxpool = 0;
-
-    if(resume) MikMod_EnableOutput();
-    _mm_critical = 0;
-
-    return 0;
-}
-
-
-BOOL MikMod_EnableOutput(void)
-{
-    // safety valve, prevents entering
-    // playstart twice:
-
-    _mm_critical = 1;
-    if(!isplaying)
-    {   if(md_driver->PlayStart()) return 1;
-        isplaying = 1;
-    }
-    _mm_critical = 0;
-    return 0;
-}
-
-
-void MikMod_DisableOutput(void)
-{
-    // safety valve, prevents calling playStop when playstart
-    // hasn't been called:
-
-    if(isplaying && md_driver!=NULL)
-    {   isplaying = 0;
-        md_driver->PlayStop();
-    }
-}
-
-
-BOOL MikMod_Active(void)
-{
-    return isplaying;
-}
-
-
-int MikMod_PlaySample(SAMPLE *s, ULONG start, UBYTE flags)
-
-// Plays a sound effects sample.  Picks a voice from the number of voices
-// allocated for use as sound effects (loops through voices, skipping all
-// active criticals).
-//
-// Returns the voice that the sound is being played on.
-
-{
-    int orig = sfxpool;    // for cases where all channels are critical
-    int c;
-
-    if(md_sfxchn==0) return -1;
-    if(s->volume > 64) s->volume = 64;
-    
-    // check the first location after sfxpool
-    do
-    {   if(sfxinfo[sfxpool] & SFX_CRITICAL)
-        {   if(md_driver->VoiceStopped(c=sfxpool+md_sngchn))
-            {   sfxinfo[sfxpool] = flags;
-                Voice_Play(c, s, start);
-                md_driver->VoiceSetVolume(c,s->volume<<2);
-                md_driver->VoiceSetPanning(c,s->panning);
-                md_driver->VoiceSetFrequency(c,s->speed);
-                sfxpool++;
-                if(sfxpool >= md_sfxchn) sfxpool = 0;
-                return c;
-            }
-        } else
-        {   sfxinfo[sfxpool] = flags;
-            Voice_Play(c=sfxpool+md_sngchn, s, start);
-            md_driver->VoiceSetVolume(c,s->volume<<2);
-            md_driver->VoiceSetPanning(c,s->panning);
-            md_driver->VoiceSetFrequency(c,s->speed);
-            sfxpool++;
-            if(sfxpool >= md_sfxchn) sfxpool = 0;
-            return c;
-        }
-
-        sfxpool++;
-        if(sfxpool >= md_sfxchn) sfxpool = 0;
-    } while(sfxpool!=orig);
-
-    return -1;
-}
-
+/*
+ * Name:  MDRIVER.C
+ * 
+ * Description: These routines are used to access the available soundcard
+ * drivers.
+ * 
+ * Portability: All systems - all compilers
+ * 
+ */
+
+#include "mikmod.h"
+
+MDRIVER        *firstdriver = NULL, *md_driver = &drv_nos;
+
+UWORD           md_device = 0;
+UWORD           md_mixfreq = 44100;
+UWORD           md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND;
+UWORD           md_dmabufsize = 50;
+UBYTE           md_pansep = 128;		/* 128 == 100% (full left/right) */
+
+UBYTE           md_reverb = 6;			/* Reverb */
+
+UBYTE           md_volume = 96;			/* Global sound volume (0-128) */
+UBYTE           md_musicvolume = 128;	/* volume of song */
+UBYTE           md_sndfxvolume = 128;	/* volume of sound effects */
+
+UBYTE           md_bpm = 125;
+
+
+/* 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;
+
+/*
+ * Backup variables.  This way, the end programmer can fiddle with the main
+ * globals without mikmod blowing up.
+ */
+
+static UWORD    idevice, imixfreq, imode, idmabufsize;
+
+/*
+ * 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);
+}
+
+
+/*
+ * Converts the given number of 1/10th seconds into the number of bytes of
+ * audio that a sample # 1/10th seconds long would require at the current md_*
+ * settings.
+ */
+UWORD 
+MD_SetDMA(int secs)
+{
+    ULONG           result;
+
+    result = (md_mixfreq * ((md_mode & DMODE_STEREO) ? 2 : 1) *
+			  ((md_mode & DMODE_16BITS) ? 2 : 1) * secs) * 10;
+
+    if (result > 32000)
+		result = 32000;
+    return (md_dmabufsize = (result & ~3));	/* round it off to an 8 byte
+											 * boundry */
+}
+
+
+void 
+MD_InfoDriver(void)
+{
+    int             t;
+    MDRIVER        *l;
+
+    /* list all registered devicedrivers: */
+    for (t = 1, l = firstdriver; l != NULL; l = l->next, t++)
+		printf("%d. %s\n", t, l->Version);
+}
+
+
+void 
+MD_RegisterDriver(MDRIVER * drv)
+{
+    MDRIVER        *cruise = firstdriver;
+
+    if (cruise != NULL) {
+		while (cruise->next != NULL)
+			cruise = cruise->next;
+		cruise->next = drv;
+    } else
+		firstdriver = drv;
+}
+
+
+/* type - sample type .. MD_MUSIC or MD_SNDFX */
+SWORD 
+MD_SampleLoad(SAMPLOAD * s, int type, FILE * fp)
+{
+    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, fp);
+    SL_Exit(s);
+
+    return result;
+}
+
+
+void 
+MD_SampleUnLoad(SWORD handle)
+{
+    md_driver->SampleUnLoad(handle);
+}
+
+
+void 
+MD_SetBPM(UBYTE bpm)
+{
+    md_bpm = bpm;
+}
+
+
+void 
+MikMod_RegisterPlayer(void (*player) (void))
+{
+    md_player = player;
+}
+
+
+void 
+MikMod_Update(void)
+{
+    if (isplaying)
+		md_driver->Update();
+}
+
+
+void 
+Voice_SetVolume(int voice, UWORD vol)
+{
+    ULONG           tmp;
+
+    if ((voice < 0) || (voice >= md_numchn))
+		return;
+    tmp = (ULONG) vol *(ULONG) md_volume *
+		((voice < md_sngchn) ? (ULONG) md_musicvolume : (ULONG) md_sndfxvolume);
+    md_driver->VoiceSetVolume(voice, tmp / 16384 UL);
+}
+
+
+void 
+Voice_SetFrequency(int voice, ULONG frq)
+{
+    if ((voice < 0) || (voice >= md_numchn))
+		return;
+    if (md_sample[voice] != NULL && md_sample[voice]->divfactor != 0)
+		frq /= md_sample[voice]->divfactor;
+    md_driver->VoiceSetFrequency(voice, frq);
+}
+
+
+void 
+Voice_SetPanning(int voice, ULONG pan)
+{
+    if ((voice < 0) || (voice >= md_numchn))
+		return;
+    if (pan != PAN_SURROUND) {
+		if (md_mode & DMODE_REVERSE)
+			pan = 255 - pan;
+		pan = (((SWORD) (pan - 128) * md_pansep) / 128) + 128;
+    }
+    md_driver->VoiceSetPanning(voice, pan);
+}
+
+
+void 
+Voice_Play(int voice, SAMPLE * s, ULONG start)
+{
+    ULONG           repend;
+
+    if ((voice < 0) || (voice >= md_numchn) || (start >= s->length))
+		return;
+
+    md_sample[voice] = s;
+    repend = s->loopend;
+
+    if (s->flags & SF_LOOP)
+		if (repend > s->length)
+			repend = s->length;	/* repend can't be bigger than size */
+
+    md_driver->VoicePlay(voice, s->handle, start, s->length, s->loopstart, repend, s->flags);
+}
+
+
+void 
+Voice_Stop(int 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);
+}
+
+
+BOOL 
+Voice_Stopped(int voice)
+{
+    if ((voice < 0) || (voice >= md_numchn))
+		return 0;
+    return (md_driver->VoiceStopped(voice));
+}
+
+
+SLONG 
+Voice_GetPosition(int voice)
+{
+    if ((voice < 0) || (voice >= md_numchn))
+		return 0;
+    return (md_driver->VoiceGetPosition(voice));
+}
+
+
+ULONG 
+Voice_RealVolume(int voice)
+{
+    if ((voice < 0) || (voice >= md_numchn))
+		return 0;
+    return (md_driver->VoiceRealVolume(voice));
+}
+
+
+/*
+ * Functions prefixed with MikMod
+ */
+BOOL 
+MikMod_Init(void)
+{
+    UWORD           t;
+
+    _mm_critical = 1;
+
+    /* if md_device==0, try to find a device number */
+
+    if (md_device == 0) {
+		for (t = 1, md_driver = firstdriver; md_driver != NULL; md_driver = md_driver->next, t++) {
+			if (md_driver->IsPresent())
+				break;
+		}
+
+		if (md_driver == NULL) {
+			_mm_errno = MMERR_DETECTING_DEVICE;
+			if (_mm_errorhandler != NULL)
+				_mm_errorhandler();
+			md_driver = &drv_nos;
+			return 1;
+		}
+		md_device = t;
+    } else {			/* if n>0 use that driver */
+		for (t = 1, md_driver = firstdriver; 
+			 (md_driver != NULL) && (t != md_device);
+			 md_driver = md_driver->next, t++)
+			; 	/* Nothing */
+
+		if (md_driver == NULL) {
+			_mm_errno = MMERR_INVALID_DEVICE;
+			if (_mm_errorhandler != NULL)
+				_mm_errorhandler();
+			md_driver = &drv_nos;
+			return 1;
+		}
+		if (!md_driver->IsPresent()) {
+			_mm_errno = MMERR_DETECTING_DEVICE;
+			if (_mm_errorhandler != NULL)
+				_mm_errorhandler();
+			md_driver = &drv_nos;
+			return 1;
+		}
+    }
+
+    if (md_driver->Init()) {
+		MikMod_Exit();
+		if (_mm_errorhandler != NULL)
+			_mm_errorhandler();
+		return 1;
+    }
+    idevice = md_device;
+    imode = md_mode;
+    imixfreq = md_mixfreq;
+    idmabufsize = md_dmabufsize;
+    initialized = 1;
+    _mm_critical = 0;
+
+    return 0;
+}
+
+
+void 
+MikMod_Exit(void)
+{
+    MikMod_DisableOutput();
+    md_driver->Exit();
+    md_numchn = md_sfxchn = md_sngchn = 0;
+    md_driver = &drv_nos;
+    initialized = 0;
+}
+
+
+/*
+ * Reset the driver using the new global variable settings. If the driver has
+ * not been initialized, it will be now.
+ */
+BOOL 
+MikMod_Reset(void)
+{
+    if (!initialized)
+		return MikMod_Init();
+    if ((md_driver->Reset == NULL) || 
+		(md_device != idevice)) {	/* md_driver->Reset was
+									 * NULL, or md_device
+									 * was changed, so do a
+									 * full reset of the
+									 * driver. */
+		if (isplaying)
+			md_driver->PlayStop();
+		md_driver->Exit();
+		if (MikMod_Init()) {
+			MikMod_Exit();
+			if (_mm_errorhandler != NULL)
+				_mm_errorhandler();
+			return 1;
+		}
+		if (isplaying)
+			md_driver->PlayStart();
+    } else {
+		if (md_driver->Reset()) {
+			MikMod_Exit();
+			if (_mm_errorhandler != NULL)
+				_mm_errorhandler();
+			return 1;
+		}
+    }
+
+    return 0;
+}
+
+
+/* If either parameter is -1, the current set value will be retained. */
+BOOL 
+MikMod_SetNumVoices(int music, int sfx)
+{
+    BOOL            resume = 0;
+    int             t, oldchn = 0;
+
+    if ((music == 0) && (sfx == 0))
+		return 0;
+
+    _mm_critical = 1;
+
+    if (isplaying) {
+		MikMod_DisableOutput();
+		oldchn = md_numchn;
+		resume = 1;
+    }
+    if (sfxinfo != NULL)
+		free(sfxinfo);
+    if (md_sample != NULL)
+		free(md_sample);
+    md_sample = NULL;
+    sfxinfo = NULL;
+
+    /*
+     * md_softchn = md_hardchn = 0;
+     * 
+     * if(md_mode & DMODE_SOFT_SNDFX) md_softchn = sfx; else md_hardchn = sfx;
+     * 
+     * if(md_mode & DMODE_SOFT_MUSIC) md_softchn += music; else md_hardchn +=
+     * music;
+     */
+
+    if (music != -1)
+		md_sngchn = music;
+    if (sfx != -1)
+		md_sfxchn = sfx;
+
+    md_numchn = md_sngchn + md_sfxchn;
+
+    LimitHardVoices(md_driver->HardVoiceLimit);
+    LimitSoftVoices(md_driver->SoftVoiceLimit);
+
+    if (md_driver->SetNumVoices()) {
+		MikMod_Exit();
+		md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
+		if (_mm_errorhandler != NULL)
+			_mm_errorhandler();
+		return 1;
+    }
+    if (md_sngchn || md_sfxchn)
+		md_sample = (SAMPLE **) _mm_calloc(md_sngchn + md_sfxchn, sizeof(SAMPLE *));
+    if (md_sfxchn)
+		sfxinfo = (UBYTE *) _mm_calloc(md_sfxchn, sizeof(UBYTE));
+
+    /* make sure the player doesn't start with garbage */
+    for (t = oldchn; t < md_numchn; t++)
+		Voice_Stop(t);
+
+    sfxpool = 0;
+
+    if (resume)
+		MikMod_EnableOutput();
+    _mm_critical = 0;
+
+    return 0;
+}
+
+
+BOOL 
+MikMod_EnableOutput(void)
+{
+    /*
+     * safety valve, prevents entering playstart twice:
+     */
+    _mm_critical = 1;
+    if (!isplaying) {
+		if (md_driver->PlayStart())
+			return 1;
+		isplaying = 1;
+    }
+    _mm_critical = 0;
+    return 0;
+}
+
+
+void 
+MikMod_DisableOutput(void)
+{
+    /*
+     * safety valve, prevents calling playStop when playstart hasn't been
+     * called:
+     */
+
+    if (isplaying && md_driver != NULL) {
+		isplaying = 0;
+		md_driver->PlayStop();
+    }
+}
+
+
+BOOL 
+MikMod_Active(void)
+{
+    return isplaying;
+}
+
+
+/*
+ * Plays a sound effects sample.  Picks a voice from the number of voices
+ * allocated for use as sound effects (loops through voices, skipping all
+ * active criticals).
+ * 
+ * Returns the voice that the sound is being played on.
+ */
+int 
+MikMod_PlaySample(SAMPLE * s, ULONG start, UBYTE flags)
+{
+    int             orig = sfxpool;	/* for cases where all channels are
+									 * critical */
+    int             c;
+
+    if (md_sfxchn == 0)
+		return -1;
+    if (s->volume > 64)
+		s->volume = 64;
+
+    /* check the first location after sfxpool */
+    do {
+		if (sfxinfo[sfxpool] & SFX_CRITICAL) {
+			if (md_driver->VoiceStopped(c = sfxpool + md_sngchn)) {
+				sfxinfo[sfxpool] = flags;
+				Voice_Play(c, s, start);
+				md_driver->VoiceSetVolume(c, s->volume << 2);
+				md_driver->VoiceSetPanning(c, s->panning);
+				md_driver->VoiceSetFrequency(c, s->speed);
+				sfxpool++;
+				if (sfxpool >= md_sfxchn)
+					sfxpool = 0;
+				return c;
+			}
+		} else {
+			sfxinfo[sfxpool] = flags;
+			Voice_Play(c = sfxpool + md_sngchn, s, start);
+			md_driver->VoiceSetVolume(c, s->volume << 2);
+			md_driver->VoiceSetPanning(c, s->panning);
+			md_driver->VoiceSetFrequency(c, s->speed);
+			sfxpool++;
+			if (sfxpool >= md_sfxchn)
+				sfxpool = 0;
+			return c;
+		}
+
+		sfxpool++;
+		if (sfxpool >= md_sfxchn)
+			sfxpool = 0;
+    } while (sfxpool != orig);
+
+    return -1;
+}