/* position adjust channels ( watery-mario64 style music changes ) */ /*========================================================================= sound.cpp Author: PKG Created: Project: Spongebob Purpose: Copyright (c) 2000 Climax Development Ltd ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ #include "sound.h" #ifndef __SYSTEM_DBG_H__ #include "system\dbg.h" #endif #ifndef __UTILS_HEADER__ #include "utils\utils.h" #endif /* Std Lib ------- */ /* Data ---- */ /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ /*---------------------------------------------------------------------- Structure defintions -------------------- */ typedef struct XMSONGDATA { FileEquate m_vh,m_vb,m_pxm; int m_startPattern; }; typedef struct XMSFXFILEDATA { FileEquate m_vh,m_vb,m_pxm; }; typedef struct SFXDETAILS { int m_channelMask; int m_pattern; // ..or instrument number for loopers int m_looping; }; /*---------------------------------------------------------------------- Function Prototypes ------------------- */ /*---------------------------------------------------------------------- Vars ---- */ // Static stuff for CSoundMediator int CSoundMediator::s_initialised=false; int CSoundMediator::s_currentVolume[CSoundMediator::NUM_VOLUMETYPES]; int CSoundMediator::s_targetVolume[CSoundMediator::NUM_VOLUMETYPES]; int CSoundMediator::s_volumeDirty[CSoundMediator::NUM_VOLUMETYPES]; xmSampleId CSoundMediator::s_songSampleId=NO_SAMPLE; xmModId CSoundMediator::s_songModId=NO_SONG; xmPlayingId CSoundMediator::s_songPlayingId=NOT_PLAYING; int CSoundMediator::s_songStartPattern=0; xmSampleId CSoundMediator::s_sfxSampleId=NO_SAMPLE; xmModId CSoundMediator::s_sfxModId=NO_SONG; static CSpuSound *s_spuSound; static CXMPlaySound *s_xmplaySound; // Songs static XMSONGDATA s_xmSongData[CSoundMediator::NUM_SONGIDS]= { { MUSIC_INGAME_VH, MUSIC_INGAME_VB, MUSIC_INGAME_PXM, 0 }, // SONG_INGAME { MUSIC_SB_TITLE_VH, MUSIC_SB_TITLE_VB, MUSIC_SB_TITLE_PXM, 0 }, // SONG_TITLE { MUSIC_SB_TITLE_VH, MUSIC_SB_TITLE_VB, MUSIC_SB_TITLE_PXM, 0xa }, // SONG_OPTIONS { MUSIC_SB_TITLE_VH, MUSIC_SB_TITLE_VB, MUSIC_SB_TITLE_PXM, 0x13 }, // SONG_MEMORYCARD { MUSIC_SB_TITLE_VH, MUSIC_SB_TITLE_VB, MUSIC_SB_TITLE_PXM, 0x14 }, // SONG_GAMECOMPLETE { MUSIC_SB_TITLE_VH, MUSIC_SB_TITLE_VB, MUSIC_SB_TITLE_PXM, 0x23 }, // SONG_GAMEOVER }; // SFX banks static XMSFXFILEDATA s_xmSfxData[CSoundMediator::NUM_SFXBANKIDS]= { { SFX_INGAME_VH, SFX_INGAME_VB, SFX_INGAME_PXM }, // SFX_INGAME }; // Individual SFX details static SFXDETAILS s_sfxDetails[]= { { 1, 6, 1 }, { 1, 4, 0 }, { 1, 5, 0 }, { 1, 0, 1 }, }; // Reverb details static ReverbDetails s_reverbDetails[CSoundMediator::NUM_REVERBTYPES]= { { SPU_REV_MODE_OFF, 0, 0, 0 }, // REV_NONE { SPU_REV_MODE_ECHO, 75, 0x3000, 100 }, // REV_ECHOTEST }; /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::initialise() { int i; ASSERT(!s_initialised); s_spuSound=new ("SPUSound") CSpuSound(); s_spuSound->initialise(); s_xmplaySound=new ("XMPlaySound") CXMPlaySound(); s_xmplaySound->initialise(); CXAStream::Init(); for(i=0;ishutdown(); delete s_xmplaySound; s_spuSound->shutdown(); delete s_spuSound; SOUND_DBGMSG("Sound mediator shutdown"); s_initialised=false; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::think(int _frames) { int i; int diff,speed; int *current,*target,*dirty; ASSERT(s_initialised); // Fade to target volume ASSERT(_frames!=0); if(_frames==0)_frames=1; speed=_frames*VOLUME_CHANGE_SPEED; current=s_currentVolume; target=s_targetVolume; dirty=s_volumeDirty; for(i=0;i0) { *current+=speed; if(*current>*target)*current=*target; *dirty=true; } current++; target++; dirty++; } // Update of anything that needs it CXAStream::ControlXA(); s_xmplaySound->think(); // Push through any changes in volume if(s_volumeDirty[VOL_FADE]) { s_volumeDirty[VOL_SONG]=true; s_volumeDirty[VOL_SFX]=true; s_volumeDirty[VOL_SPEECH]=true; s_volumeDirty[VOL_FADE]=false; } if(s_volumeDirty[VOL_SONG]) { s_xmplaySound->setMasterSongVolume((s_currentVolume[VOL_SONG]*s_currentVolume[VOL_FADE])>>8); s_volumeDirty[VOL_SONG]=false; } if(s_volumeDirty[VOL_SFX]) { s_xmplaySound->setMasterSfxVolume((s_currentVolume[VOL_SFX]*s_currentVolume[VOL_FADE])>>8); s_volumeDirty[VOL_SFX]=false; } if(s_volumeDirty[VOL_SPEECH]) { int vol=((s_currentVolume[VOL_SPEECH]*s_currentVolume[VOL_FADE])>>8)<<7; CXAStream::setMasterVolume(vol,vol); s_volumeDirty[VOL_SPEECH]=false; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::setReverbType(REVERBTYPE _type) { s_spuSound->setReverbDetails(&s_reverbDetails[_type]); s_spuSound->setReverbActive(true); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::setSong(SONGID _songId) { XMSONGDATA *song; ASSERT(s_songSampleId==NO_SAMPLE); ASSERT(s_songModId==NO_SONG); song=&s_xmSongData[_songId]; s_songModId=s_xmplaySound->loadModData(song->m_pxm); s_songSampleId=s_xmplaySound->loadSampleData(song->m_vh,song->m_vb); s_songStartPattern=song->m_startPattern; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::playSong() { ASSERT(s_songSampleId!=NO_SAMPLE); ASSERT(s_songModId!=NO_SONG); ASSERT(s_songPlayingId==NOT_PLAYING); s_songPlayingId=s_xmplaySound->playSong(s_songSampleId,s_songModId,s_songStartPattern); // s_volumeDirty[SONG]=true; // Force a volume update } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::dumpSong() { ASSERT(s_songSampleId!=NO_SAMPLE); ASSERT(s_songModId!=NO_SONG); if(s_songPlayingId!=NOT_PLAYING) { s_xmplaySound->stopPlayingId(s_songPlayingId); s_xmplaySound->unlockPlayingId(s_songPlayingId); } s_xmplaySound->dumpSampleData(s_songSampleId); s_xmplaySound->dumpModData(s_songModId); s_songSampleId=NO_SAMPLE; s_songModId=NO_SONG; s_songPlayingId=NOT_PLAYING; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::setSfxBank(SFXBANKID _bankId) { XMSFXFILEDATA *sfx; ASSERT(s_sfxSampleId==NO_SAMPLE); ASSERT(s_sfxModId==NO_SONG); sfx=&s_xmSfxData[_bankId]; s_sfxModId=s_xmplaySound->loadModData(sfx->m_pxm); s_sfxSampleId=s_xmplaySound->loadSampleData(sfx->m_vh,sfx->m_vb); } /*---------------------------------------------------------------------- Function: Purpose: Params: Pass _lock as true if you wanna keep hold of one-shot sfx. This'll be necessary if you have a *long* one-shot at the same time as *lots* of other sfx. Returns: ---------------------------------------------------------------------- */ xmPlayingId CSoundMediator::playSfx(int _sfxId,int _lock=false) { int sfxChannelMask; xmPlayingId playId; SFXDETAILS *sfx; ASSERT(s_sfxSampleId!=NO_SAMPLE); ASSERT(s_sfxModId!=NO_SONG); // Play! sfx=&s_sfxDetails[_sfxId]; if(sfx->m_looping) { playId=s_xmplaySound->playLoopingSfx(s_sfxSampleId,s_sfxModId,sfx->m_pattern,10); } else { playId=s_xmplaySound->playSfx(s_sfxSampleId,s_sfxModId,sfx->m_pattern,sfx->m_channelMask,20); if(!_lock&&playId!=NOT_PLAYING) { s_xmplaySound->unlockPlayingId(playId); // We really don't care about one-shot sfx.. playId=NOT_PLAYING; } } // s_volumeDirty[SFX]=true; // Force a volume update return playId; } /*---------------------------------------------------------------------- Function: Purpose: Calculate volume and panning for a sound base upon its position in space. Takes a position in space which describes the sound position relative to the camera/microphone. Volume comes from distance from origin and panning comes from the position along the x axis. Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::setposition(xmPlayingId _playingId,VECTOR *pos) { int volume,pan; volume=CXMPlaySound::MAX_VOLUME-(CalcLengthV(pos)); if(volumevx/2)+CXMPlaySound::PAN_CENTRE; if(panCXMPlaySound::PAN_RIGHT)pan=CXMPlaySound::PAN_RIGHT; s_xmplaySound->setVolume(_playingId,volume); s_xmplaySound->setPanning(_playingId,pan); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::stopSfx(xmPlayingId _playingId) { s_xmplaySound->stopPlayingId(_playingId); s_xmplaySound->unlockPlayingId(_playingId); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::playSpeech(SpeechEquate _speech) { stopSpeech(); CXAStream::PlaySpeech(_speech); // s_volumeDirty[SPEECH]=true; // Force a volume update } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::stopSpeech() { if(CXAStream::IsPlaying()) CXAStream::Stop(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::setVolume(VOLUMETYPE _type,int _val) { ASSERT(_val>=MIN_VOLUME&&_val<=MAX_VOLUME); s_targetVolume[_type]=_val; s_volumeDirty[_type]=true; // Otherwise we could miss volume changes under rare conditions } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CSoundMediator::getVolume(VOLUMETYPE _type) { return s_targetVolume[_type]; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CSoundMediator::stopAllSound() { s_xmplaySound->stopAndUnlockAllSound(); CXAStream::Stop(); } /*=========================================================================== end */