diff playercode/mdriver.c @ 5:42e11dc15457

Initial revision
author darius
date Fri, 23 Jan 1998 16:05:08 +0000
parents
children 437e8455d862
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/playercode/mdriver.c	Fri Jan 23 16:05:08 1998 +0000
@@ -0,0 +1,556 @@
+/*
+
+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;
+}
+