Mercurial > ~darius > hgwebdir.cgi > mikmod
view playercode/mdriver.c @ 21:eb5b14d0e054
Makefile
unneeded rule
mikmodux.h
Fix MODULE
author | darius |
---|---|
date | Fri, 24 Apr 1998 08:04:39 +0000 |
parents | 80fa6dd10e14 |
children |
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; /* * 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); } 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; }