mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-10-04 05:13:19 +00:00
Implemenet proper positional audio, one issue still.
With this patch, entities can serve as a sound source whose position updates relative to the listener. This implements the last missing feature of my previous positional audio patch, which is moving sound sources. Previously, all sounds were relative to the listener with the listener centered at (0, 0, 0), and once a sound started playing, the position could not be changed. Volume was set as an estimation of the distance to the listener. These restrictions are now gone; OpenAL will handle the volume & panning based on the distance. The remaining problem is that stereo sounds are not attenuated, at all. Lua additions: - playSfx() takes an additional parameter now. - entity_setStopSoundsOnDeath()
This commit is contained in:
parent
49b6234ac8
commit
e6680da428
12 changed files with 435 additions and 174 deletions
|
@ -3138,6 +3138,8 @@ void Core::main(float runTime)
|
|||
}
|
||||
}
|
||||
|
||||
sound->setListenerPos(screenCenter.x, screenCenter.y);
|
||||
|
||||
if (doScreenshot)
|
||||
{
|
||||
if (verbose) debugLog("screenshot");
|
||||
|
|
|
@ -672,7 +672,7 @@ class OpenALChannel
|
|||
{
|
||||
public:
|
||||
OpenALChannel();
|
||||
FMOD_RESULT setVolume(const float _volume, const bool setstate=true);
|
||||
FMOD_RESULT setVolume(const float _volume);
|
||||
FMOD_RESULT setPaused(const bool _paused, const bool setstate=true);
|
||||
FMOD_RESULT setFrequency(const float _frequency);
|
||||
FMOD_RESULT setPriority(int _priority);
|
||||
|
@ -682,6 +682,14 @@ public:
|
|||
FMOD_RESULT setChannelGroup(ChannelGroup *channelgroup);
|
||||
FMOD_RESULT stop();
|
||||
FMOD_RESULT setPan(const float pan);
|
||||
FMOD_RESULT setCallback(FMOD_CHANNEL_CALLBACK callback);
|
||||
FMOD_RESULT getUserData(void **userdata);
|
||||
FMOD_RESULT setUserData(void *userdata);
|
||||
FMOD_RESULT set3DAttributes(const FMOD_VECTOR *pos, const FMOD_VECTOR *vel);
|
||||
FMOD_RESULT set3DMinMaxDistance(float mindistance, float maxdistance);
|
||||
FMOD_RESULT setMode(FMOD_MODE mode);
|
||||
FMOD_RESULT getMode(FMOD_MODE *mode);
|
||||
|
||||
void setGroupVolume(const float _volume);
|
||||
void setSourceName(const ALuint _sid) { sid = _sid; }
|
||||
ALuint getSourceName() const { return sid; }
|
||||
|
@ -703,6 +711,9 @@ private:
|
|||
OggDecoder *decoder;
|
||||
bool inuse;
|
||||
bool initial;
|
||||
FMOD_CHANNEL_CALLBACK callback;
|
||||
void *userdata;
|
||||
FMOD_MODE _mode;
|
||||
};
|
||||
|
||||
|
||||
|
@ -743,6 +754,7 @@ OpenALChannel::OpenALChannel()
|
|||
, decoder(NULL)
|
||||
, inuse(false)
|
||||
, initial(true)
|
||||
, _mode(FMOD_DEFAULT)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -805,10 +817,9 @@ void OpenALChannel::update()
|
|||
}
|
||||
|
||||
ALBRIDGE(Channel,setVolume,(float volume),(volume))
|
||||
FMOD_RESULT OpenALChannel::setVolume(const float _volume, const bool setstate)
|
||||
FMOD_RESULT OpenALChannel::setVolume(const float _volume)
|
||||
{
|
||||
if (setstate)
|
||||
volume = _volume;
|
||||
volume = _volume;
|
||||
alSourcef(sid, AL_GAIN, _volume * groupvolume);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
return FMOD_OK;
|
||||
|
@ -922,6 +933,98 @@ FMOD_RESULT OpenALChannel::setPan(const float pan)
|
|||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(Channel,stop,(),())
|
||||
FMOD_RESULT OpenALChannel::stop()
|
||||
{
|
||||
if (decoder)
|
||||
{
|
||||
decoder->stop();
|
||||
decoder = NULL;
|
||||
}
|
||||
alSourceStop(sid);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
alSourcei(sid, AL_BUFFER, 0);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
if (sound)
|
||||
{
|
||||
sound->release();
|
||||
sound = NULL;
|
||||
}
|
||||
if (inuse && callback)
|
||||
callback(this, FMOD_CHANNEL_CALLBACKTYPE_END, NULL, NULL); // FIXME commanddata missing
|
||||
paused = false;
|
||||
inuse = false;
|
||||
initial = false;
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
ALBRIDGE(Channel,setCallback,(FMOD_CHANNEL_CALLBACK callback),(callback))
|
||||
FMOD_RESULT OpenALChannel::setCallback(FMOD_CHANNEL_CALLBACK callback)
|
||||
{
|
||||
this->callback = callback;
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(Channel,getUserData,(void **userdata),(userdata))
|
||||
FMOD_RESULT OpenALChannel::getUserData(void **userdata)
|
||||
{
|
||||
*userdata = this->userdata;
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(Channel,setUserData,(void *userdata),(userdata))
|
||||
FMOD_RESULT OpenALChannel::setUserData(void *userdata)
|
||||
{
|
||||
this->userdata = userdata;
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(Channel,set3DAttributes,(const FMOD_VECTOR *pos, const FMOD_VECTOR *vel),(pos, vel))
|
||||
FMOD_RESULT OpenALChannel::set3DAttributes(const FMOD_VECTOR *pos, const FMOD_VECTOR *vel)
|
||||
{
|
||||
if (pos)
|
||||
alSource3f(sid, AL_POSITION, pos->x, pos->y, pos->z);
|
||||
if(vel)
|
||||
alSource3f(sid, AL_VELOCITY, vel->x, vel->y, vel->z);
|
||||
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(Channel,set3DMinMaxDistance,(float mindistance, float maxdistance),(mindistance, maxdistance))
|
||||
FMOD_RESULT OpenALChannel::set3DMinMaxDistance(float mindistance, float maxdistance)
|
||||
{
|
||||
alSourcef(sid, AL_REFERENCE_DISTANCE, mindistance);
|
||||
alSourcef(sid, AL_MAX_DISTANCE, maxdistance);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(Channel,setMode,(FMOD_MODE mode),(mode))
|
||||
FMOD_RESULT OpenALChannel::setMode(FMOD_MODE mode)
|
||||
{
|
||||
_mode = mode;
|
||||
|
||||
if(mode & FMOD_3D_HEADRELATIVE)
|
||||
alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
else // FMOD_3D_WORLDRELATIVE is the default according to FMOD docs
|
||||
alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(Channel,getMode,(FMOD_MODE *mode),(mode))
|
||||
FMOD_RESULT OpenALChannel::getMode(FMOD_MODE *mode)
|
||||
{
|
||||
*mode = _mode;
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FMOD::ChannelGroup implementation...
|
||||
|
||||
|
@ -1066,29 +1169,6 @@ void OpenALChannel::setSound(OpenALSound *_sound)
|
|||
}
|
||||
|
||||
|
||||
ALBRIDGE(Channel,stop,(),())
|
||||
FMOD_RESULT OpenALChannel::stop()
|
||||
{
|
||||
if (decoder)
|
||||
{
|
||||
decoder->stop();
|
||||
decoder = NULL;
|
||||
}
|
||||
alSourceStop(sid);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
alSourcei(sid, AL_BUFFER, 0);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
if (sound)
|
||||
{
|
||||
sound->release();
|
||||
sound = NULL;
|
||||
}
|
||||
paused = false;
|
||||
inuse = false;
|
||||
initial = false;
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FMOD::System implementation ...
|
||||
|
@ -1112,6 +1192,7 @@ public:
|
|||
FMOD_RESULT getDriverCaps(const int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency, FMOD_SPEAKERMODE *controlpanelspeakermode);
|
||||
FMOD_RESULT getMasterChannelGroup(ChannelGroup **channelgroup);
|
||||
FMOD_RESULT playSound(FMOD_CHANNELINDEX channelid, Sound *sound, bool paused, Channel **channel);
|
||||
FMOD_RESULT set3DListenerAttributes(int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up);
|
||||
|
||||
FMOD_RESULT getNumChannels(int *maxchannels_ret);
|
||||
|
||||
|
@ -1415,7 +1496,7 @@ FMOD_RESULT OpenALSystem::init(int maxchannels, const FMOD_INITFLAGS flags, cons
|
|||
break;
|
||||
}
|
||||
|
||||
alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
alSource3f(sid, AL_POSITION, 0.0f, 0.0f, 0.0f); // no panning or spatialization in Aquaria.
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
|
@ -1426,6 +1507,12 @@ FMOD_RESULT OpenALSystem::init(int maxchannels, const FMOD_INITFLAGS flags, cons
|
|||
ss << "Using " << num_channels << " sound channels.";
|
||||
debugLog(ss.str());
|
||||
|
||||
// HACK: FMOD doesn't do this.
|
||||
// For completeness, we pass FMOD_3D_LINEARROLLOFF to createSound().
|
||||
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
|
||||
SANITY_CHECK_OPENAL_CALL();
|
||||
|
||||
|
||||
OggDecoder::startDecoderThread();
|
||||
|
||||
return FMOD_OK;
|
||||
|
@ -1539,6 +1626,43 @@ FMOD_RESULT OpenALSystem::update()
|
|||
return FMOD_OK;
|
||||
}
|
||||
|
||||
ALBRIDGE(System, set3DListenerAttributes, (int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up),
|
||||
(listener, pos, vel, forward, up));
|
||||
FMOD_RESULT OpenALSystem::set3DListenerAttributes(int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up)
|
||||
{
|
||||
// ignore listener parameter; there is only one listener in OpenAL.
|
||||
|
||||
if(up || forward)
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, &orientation[0]);
|
||||
|
||||
if(forward)
|
||||
{
|
||||
orientation[0] = forward->x;
|
||||
orientation[1] = forward->y;
|
||||
orientation[2] = forward->z;
|
||||
}
|
||||
|
||||
if(up)
|
||||
{
|
||||
orientation[3] = up->x;
|
||||
orientation[4] = up->y;
|
||||
orientation[5] = up->z;
|
||||
}
|
||||
|
||||
alListenerfv(AL_ORIENTATION, &orientation[0]);
|
||||
}
|
||||
|
||||
if(pos)
|
||||
alListener3f(AL_POSITION, pos->x, pos->y, pos->z);
|
||||
|
||||
if(vel)
|
||||
alListener3f(AL_VELOCITY, vel->x, vel->y, vel->z);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
// misc FMOD bits...
|
||||
|
||||
|
|
|
@ -60,6 +60,24 @@ typedef enum
|
|||
FMOD_DSP_TYPE_REVERB,
|
||||
} FMOD_DSP_TYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FMOD_CHANNEL_CALLBACKTYPE_END, /* Called when a sound ends. */
|
||||
FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE, /* Called when a voice is swapped out or swapped in. */
|
||||
FMOD_CHANNEL_CALLBACKTYPE_SYNCPOINT, /* Called when a syncpoint is encountered. Can be from wav file markers. */
|
||||
FMOD_CHANNEL_CALLBACKTYPE_OCCLUSION, /* Called when the channel has its geometry occlusion value calculated. Can be used to clamp or change the value. */
|
||||
|
||||
FMOD_CHANNEL_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */
|
||||
FMOD_CHANNEL_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */
|
||||
} FMOD_CHANNEL_CALLBACKTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x; /* X co-ordinate in 3D space. */
|
||||
float y; /* Y co-ordinate in 3D space. */
|
||||
float z; /* Z co-ordinate in 3D space. */
|
||||
} FMOD_VECTOR;
|
||||
|
||||
#define F_CALLBACK
|
||||
|
||||
typedef int FMOD_CAPS;
|
||||
|
@ -77,8 +95,13 @@ typedef int FMOD_MODE;
|
|||
#define FMOD_LOOP_OFF (1<<4)
|
||||
#define FMOD_LOOP_NORMAL (1<<5)
|
||||
#define FMOD_LOWMEM (1<<6)
|
||||
#define FMOD_3D (1<<7)
|
||||
#define FMOD_3D_HEADRELATIVE (1<<8)
|
||||
#define FMOD_3D_WORLDRELATIVE (1<<9)
|
||||
#define FMOD_3D_LINEARROLLOFF (1<<10)
|
||||
#define FMOD_DEFAULT (FMOD_2D | FMOD_HARDWARE)
|
||||
|
||||
|
||||
typedef int FMOD_CREATESOUNDEXINFO;
|
||||
|
||||
#define FMOD_INIT_NORMAL 0
|
||||
|
@ -92,6 +115,8 @@ typedef FMOD_RESULT (*FMOD_FILE_CLOSECALLBACK)(void *,void *);
|
|||
typedef FMOD_RESULT (*FMOD_FILE_READCALLBACK)(void *,void *,unsigned int,unsigned int *,void *);
|
||||
typedef FMOD_RESULT (*FMOD_FILE_SEEKCALLBACK)(void *,unsigned int,void *);
|
||||
|
||||
typedef FMOD_RESULT (*FMOD_CHANNEL_CALLBACK)(void *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2);
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -146,6 +171,13 @@ namespace FMOD
|
|||
FMOD_RESULT stop();
|
||||
FMOD_RESULT setPaused(bool paused);
|
||||
FMOD_RESULT setPan(float pan);
|
||||
FMOD_RESULT setCallback(FMOD_CHANNEL_CALLBACK callback);
|
||||
FMOD_RESULT getUserData(void **userdata);
|
||||
FMOD_RESULT setUserData(void *userdata);
|
||||
FMOD_RESULT set3DAttributes(const FMOD_VECTOR *pos, const FMOD_VECTOR *vel);
|
||||
FMOD_RESULT set3DMinMaxDistance(float mindistance, float maxdistance);
|
||||
FMOD_RESULT setMode(FMOD_MODE mode);
|
||||
FMOD_RESULT getMode(FMOD_MODE *mode);
|
||||
};
|
||||
|
||||
class System
|
||||
|
@ -165,6 +197,7 @@ namespace FMOD
|
|||
FMOD_RESULT setFileSystem(FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, int blockalign);
|
||||
FMOD_RESULT setSpeakerMode(FMOD_SPEAKERMODE speakermode);
|
||||
FMOD_RESULT update();
|
||||
FMOD_RESULT set3DListenerAttributes(int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up);
|
||||
|
||||
// BBGE-specific...
|
||||
FMOD_RESULT getNumChannels(int *maxchannels_ret);
|
||||
|
|
|
@ -1057,6 +1057,11 @@ bool SoundManager::playVoice(const std::string &name, SoundVoiceType svt, float
|
|||
|
||||
voiceChannel->setPan(0);
|
||||
voiceChannel->setFrequency(1);
|
||||
voiceChannel->setCallback(NULL);
|
||||
voiceChannel->setUserData(NULL);
|
||||
voiceChannel->set3DMinMaxDistance(0.0f, 0.0f);
|
||||
setSoundPos(voiceChannel, 0, 0);
|
||||
setSoundRelative(voiceChannel, true);
|
||||
|
||||
result = voiceChannel->setPaused(false);
|
||||
checkError();
|
||||
|
@ -1143,13 +1148,32 @@ void *SoundManager::playSfx(const PlaySfx &play)
|
|||
checkError();
|
||||
}
|
||||
|
||||
channel->setPan(play.pan);
|
||||
//channel->setPan(play.pan);
|
||||
|
||||
float freq = play.freq;
|
||||
if (freq <= 0)
|
||||
freq = 1;
|
||||
channel->setFrequency(freq);
|
||||
|
||||
channel->setCallback(NULL);
|
||||
channel->setUserData(NULL);
|
||||
|
||||
// position in space
|
||||
setSoundPos(channel, play.x, play.y);
|
||||
setSoundRelative(channel, play.relative);
|
||||
|
||||
// distance gain attenuation: stereo separation + silence at further away than maxdist
|
||||
float maxdist = play.maxdist;
|
||||
if (!maxdist)
|
||||
maxdist = 1300;
|
||||
|
||||
if(maxdist > 0)
|
||||
channel->set3DMinMaxDistance(maxdist * 0.3, maxdist); // HACK: this works reasonably well
|
||||
else
|
||||
channel->set3DMinMaxDistance(0, 0); // no attenuation
|
||||
|
||||
|
||||
|
||||
result = channel->setPaused(false);
|
||||
checkError();
|
||||
|
||||
|
@ -1160,23 +1184,11 @@ void *SoundManager::playSfx(const PlaySfx &play)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *SoundManager::playSfx(const std::string &name, float vol, float pan, float freq)
|
||||
void *SoundManager::playSfx(const std::string &name, float vol)
|
||||
{
|
||||
PlaySfx play;
|
||||
play.name = name;
|
||||
play.vol = vol;
|
||||
play.pan = pan;
|
||||
play.freq = freq;
|
||||
return playSfx(play);
|
||||
}
|
||||
|
||||
void *SoundManager::playSfx(int handle, float vol, float pan, float freq)
|
||||
{
|
||||
PlaySfx play;
|
||||
play.handle = handle;
|
||||
play.vol = vol;
|
||||
play.pan = pan;
|
||||
play.freq = freq;
|
||||
return playSfx(play);
|
||||
}
|
||||
|
||||
|
@ -1205,49 +1217,6 @@ bool SoundManager::isPlayingMusic(const std::string &name)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SoundManager::playMod(const std::string &name)
|
||||
{
|
||||
std::string fn;
|
||||
|
||||
fn = musicPath + name;
|
||||
stringToLower(fn);
|
||||
|
||||
FMOD_MODE mode=0;
|
||||
|
||||
//FMOD_CREATESOUNDEXINFO exinfo;
|
||||
|
||||
//mode = FMOD_2D | FMOD_SOFTWARE | FMOD_CREATESAMPLE;//FMOD_CREATESTREAM;
|
||||
mode = FMOD_HARDWARE | FMOD_2D | FMOD_CREATESTREAM;
|
||||
|
||||
debugLog("createSound: " + fn);
|
||||
result = SoundCore::system->createSound(fn.c_str(), mode, 0, &modSound);
|
||||
if (checkError())
|
||||
{
|
||||
debugLog("createSound failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
debugLog("playSound");
|
||||
result = SoundCore::system->playSound(FMOD_CHANNEL_FREE, modSound, false, &modChannel);
|
||||
checkError();
|
||||
|
||||
debugLog("setChannelGroup");
|
||||
result = modChannel->setChannelGroup(group_mus);
|
||||
checkError();
|
||||
|
||||
debugLog("setPriority");
|
||||
result = modChannel->setPriority(0); // should be highest priority (according to the docs)
|
||||
checkError();
|
||||
|
||||
debugLog("setPaused");
|
||||
result = modChannel->setPaused(false);
|
||||
checkError();
|
||||
|
||||
debugLog("returning");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundManager::playMusic(const std::string &name, SoundLoopType slt, SoundFadeType sft, float trans, SoundConditionType sct)
|
||||
{
|
||||
debugLog("playMusic: " + name);
|
||||
|
@ -1373,6 +1342,11 @@ bool SoundManager::playMusic(const std::string &name, SoundLoopType slt, SoundFa
|
|||
|
||||
musicChannel->setFrequency(1); // in case the channel was used by a pitch-shifted sound before
|
||||
musicChannel->setPan(0);
|
||||
musicChannel->setCallback(NULL);
|
||||
musicChannel->setUserData(NULL);
|
||||
musicChannel->set3DMinMaxDistance(0.0f, 0.0f); // disable attenuation // FIXME: is that right?
|
||||
setSoundPos(musicChannel, 0, 0);
|
||||
setSoundRelative(musicChannel, true);
|
||||
|
||||
result = musicChannel->setPaused(false); // This is where the sound really starts.
|
||||
checkError();
|
||||
|
@ -1557,7 +1531,7 @@ Buffer SoundManager::loadSoundIntoBank(const std::string &filename, const std::s
|
|||
if (sound)
|
||||
return sound;
|
||||
|
||||
FMOD_MODE mode = FMOD_DEFAULT | FMOD_LOWMEM;
|
||||
FMOD_MODE mode = FMOD_DEFAULT | FMOD_LOWMEM | FMOD_3D | FMOD_3D_LINEARROLLOFF;
|
||||
if (loop)
|
||||
mode |= FMOD_LOOP_NORMAL;
|
||||
|
||||
|
@ -1680,3 +1654,122 @@ bool SoundManager::checkError()
|
|||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoundManager::setListenerPos(float x, float y)
|
||||
{
|
||||
FMOD_VECTOR pos;
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = 0.0f;
|
||||
|
||||
FMOD_VECTOR forward;
|
||||
forward.x = 0.0f;
|
||||
forward.y = 0.0f;
|
||||
forward.z = -1.0f;
|
||||
|
||||
FMOD_VECTOR up;
|
||||
up.x = 0.0f;
|
||||
up.y = 1.0f;
|
||||
up.z = 0.0f;
|
||||
|
||||
SoundCore::system->set3DListenerAttributes(0, &pos, NULL, &forward, &up);
|
||||
}
|
||||
|
||||
void SoundManager::setSoundPos(void *channel, float x, float y)
|
||||
{
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
FMOD::Channel *pChannel = (FMOD::Channel*)channel;
|
||||
FMOD_VECTOR pos;
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = 0.0f;
|
||||
|
||||
pChannel->set3DAttributes(&pos, NULL);
|
||||
}
|
||||
|
||||
void SoundManager::setSoundRelative(void *channel, bool relative)
|
||||
{
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
FMOD::Channel *pChannel = (FMOD::Channel*)channel;
|
||||
|
||||
FMOD_MODE mode = 0;
|
||||
pChannel->getMode(&mode);
|
||||
FMOD_MODE newmode = mode & ~(FMOD_3D_WORLDRELATIVE | FMOD_3D_HEADRELATIVE);
|
||||
if(relative)
|
||||
newmode |= (FMOD_3D_HEADRELATIVE | FMOD_3D);
|
||||
else
|
||||
newmode |= (FMOD_3D_WORLDRELATIVE | FMOD_3D);
|
||||
|
||||
if (mode != newmode)
|
||||
pChannel->setMode(newmode);
|
||||
}
|
||||
|
||||
static FMOD_RESULT s_soundHolderCallback(void *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2)
|
||||
{
|
||||
if (!channel)
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
|
||||
SoundHolder *holder = NULL;
|
||||
FMOD::Channel *pChannel = (FMOD::Channel*)channel;
|
||||
pChannel->getUserData((void**)&holder);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case FMOD_CHANNEL_CALLBACKTYPE_END:
|
||||
holder->unlinkSound(channel);
|
||||
break;
|
||||
default:
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
SoundHolder::~SoundHolder()
|
||||
{
|
||||
unlinkAllSounds();
|
||||
}
|
||||
|
||||
void SoundHolder::updateSoundPosition(float x, float y)
|
||||
{
|
||||
if (activeSounds.size())
|
||||
for(std::set<void*>::iterator it = activeSounds.begin(); it != activeSounds.end(); ++it)
|
||||
sound->setSoundPos(*it, x, y);
|
||||
}
|
||||
|
||||
void SoundHolder::stopAllSounds()
|
||||
{
|
||||
// activeSounds is modified by SoundManager::stopSfx(), which calls unkinkSound(), can't use iterator here
|
||||
while(activeSounds.size())
|
||||
sound->stopSfx(*activeSounds.begin());
|
||||
}
|
||||
|
||||
void SoundHolder::unlinkSound(void *channel)
|
||||
{
|
||||
FMOD::Channel *pChannel = (FMOD::Channel*)channel;
|
||||
pChannel->setUserData(NULL);
|
||||
pChannel->setCallback(NULL);
|
||||
activeSounds.erase(channel);
|
||||
}
|
||||
|
||||
void SoundHolder::linkSound(void *channel)
|
||||
{
|
||||
if (!channel)
|
||||
return;
|
||||
FMOD::Channel *pChannel = (FMOD::Channel*)channel;
|
||||
pChannel->setUserData(this);
|
||||
pChannel->setCallback(s_soundHolderCallback);
|
||||
activeSounds.insert(channel);
|
||||
}
|
||||
|
||||
void SoundHolder::unlinkAllSounds()
|
||||
{
|
||||
while(activeSounds.size())
|
||||
unlinkSound(*activeSounds.begin());
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include <string>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include "Vector.h"
|
||||
|
||||
// if using SDL_MIXER
|
||||
|
@ -103,20 +104,26 @@ enum SoundLoadType
|
|||
|
||||
struct PlaySfx
|
||||
{
|
||||
PlaySfx() : priority(0.5), handle(0), pan(0), vol(1), fade(SFT_NONE), time(0), freq(1), loops(0), channel(BBGE_AUDIO_NOCHANNEL) {}
|
||||
PlaySfx() : priority(0.5), handle(0), vol(1), fade(SFT_NONE),
|
||||
time(0), freq(1), loops(0), channel(BBGE_AUDIO_NOCHANNEL),
|
||||
maxdist(0), x(0), y(0), relative(true) {}
|
||||
|
||||
std::string name;
|
||||
intptr_t handle;
|
||||
float pan;
|
||||
float vol;
|
||||
float time;
|
||||
float freq;
|
||||
int loops;
|
||||
int channel;
|
||||
float priority;
|
||||
float maxdist; // distance gain attenuation. if 0: use default value, -1: don't attenuate at all
|
||||
SoundFadeType fade;
|
||||
float x, y;
|
||||
bool relative;
|
||||
};
|
||||
|
||||
class SoundHolder; // defined below
|
||||
|
||||
class SoundManager
|
||||
{
|
||||
public:
|
||||
|
@ -140,16 +147,18 @@ public:
|
|||
SoundCore::Buffer getBuffer(const std::string &name);
|
||||
|
||||
void *playSfx(const PlaySfx &play);
|
||||
void *playSfx(const std::string &name, float vol=1, float pan=0, float freq=1);
|
||||
void *playSfx(int handle, float vol=1, float pan=0, float freq=1);
|
||||
void *playSfx(const std::string &name, float vol=1);
|
||||
|
||||
bool playMod(const std::string &name);
|
||||
bool playMusic(const std::string &name, SoundLoopType=SLT_NORMAL, SoundFadeType sft=SFT_NONE, float trans=0, SoundConditionType sct=SCT_NORMAL);
|
||||
bool playVoice(const std::string &name, SoundVoiceType=SVT_QUEUE, float vmod=-1);
|
||||
|
||||
float getMusicFader();
|
||||
float getVoxFader();
|
||||
|
||||
void setListenerPos(float x, float y);
|
||||
void setSoundPos(void *channel, float x, float y);
|
||||
void setSoundRelative(void *channel, bool relative);
|
||||
|
||||
std::string getVolumeString();
|
||||
|
||||
void toggleEffectMusic(SoundEffectType effect, bool on);
|
||||
|
@ -248,6 +257,28 @@ private:
|
|||
void (*loadProgressCallback)();
|
||||
};
|
||||
|
||||
class SoundHolder
|
||||
{
|
||||
friend class SoundManager;
|
||||
public:
|
||||
void updateSoundPosition(float x, float y);
|
||||
void stopAllSounds();
|
||||
void unlinkSound(void *channel);
|
||||
void linkSound(void *channel);
|
||||
void unlinkAllSounds();
|
||||
|
||||
protected:
|
||||
virtual ~SoundHolder();
|
||||
|
||||
private:
|
||||
std::set<void*> activeSounds;
|
||||
};
|
||||
|
||||
|
||||
extern SoundManager *sound;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue