Mercurial > ~darius > hgwebdir.cgi > mikmod
view playercode/mdriver.c @ 11:d5cb2cfc8eca
Initial revision
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:11 +0000 |
parents | 42e11dc15457 |
children | 437e8455d862 |
line wrap: on
line source
/* 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; }