mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-02-25 15:33:57 +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
|
@ -3466,7 +3466,7 @@ void Avatar::lockToWallCommon()
|
|||
dsq->spawnParticleEffect("LockToWall", position);
|
||||
stopBurst();
|
||||
stopRoll();
|
||||
core->sound->playSfx("LockToWall", 1.0, 0);//, (1000+rand()%100)/1000.0f);
|
||||
core->sound->playSfx("LockToWall", 1.0);
|
||||
//bursting = false;
|
||||
this->burst = 1;
|
||||
//lastLockToWallPos = position;
|
||||
|
|
|
@ -2293,58 +2293,22 @@ void DSQ::playMenuSelectSfx()
|
|||
core->sound->playSfx("MenuSelect");
|
||||
}
|
||||
|
||||
PlaySfx DSQ::calcPositionalSfx(const Vector &position, float maxdist)
|
||||
void DSQ::playPositionalSfx(const std::string &name, const Vector &position, float f, float fadeOut, SoundHolder *holder)
|
||||
{
|
||||
PlaySfx sfx;
|
||||
sfx.vol = 0;
|
||||
if (dsq->game && dsq->game->avatar)
|
||||
{
|
||||
Vector diff = position - dsq->game->avatar->position;
|
||||
|
||||
// Aspect-ratio-adjustment:
|
||||
// Just multiplying the cut-off distance with aspect increases it too much on widescreen,
|
||||
// so only a part of it is aspect-corrected to make it sound better.
|
||||
// Aspect is most likely >= 5/4 here, which results in a higher value than
|
||||
// the default of 1024; this is intended. -- FG
|
||||
if (maxdist <= 0)
|
||||
maxdist = 724 + (300 * aspect);
|
||||
|
||||
float dist = diff.getLength2D();
|
||||
if (dist < maxdist)
|
||||
{
|
||||
sfx.vol = 1.0f - (dist / maxdist);
|
||||
sfx.pan = (diff.x / maxdist) * 2.0f;
|
||||
if (sfx.pan < -1)
|
||||
sfx.pan = -1;
|
||||
if (sfx.pan > 1)
|
||||
sfx.pan = 1;
|
||||
}
|
||||
}
|
||||
return sfx;
|
||||
}
|
||||
|
||||
void DSQ::playPositionalSfx(const std::string &name, const Vector &position, float f, float fadeOut)
|
||||
{
|
||||
PlaySfx sfx = calcPositionalSfx(position);
|
||||
|
||||
// FIXME: Right now, positional sound effects never update their relative position to the
|
||||
// listener, which means that if they are spawned too far away to be audible, it is not possible
|
||||
// that they ever get audible at all. Additionally, the current scripting API only provides
|
||||
// functions to fade sounds OUT, not to set their volume arbitrarily.
|
||||
// Because audio thread creation is costly, drop sounds that can not be heard.
|
||||
// This needs to be removed once proper audio source/listener positioning is implemented,
|
||||
// or the scripting interface gets additional functions to mess with sound. -- FG
|
||||
if (sfx.vol <= 0)
|
||||
return;
|
||||
|
||||
sfx.freq = f;
|
||||
sfx.name = name;
|
||||
sfx.relative = false;
|
||||
sfx.x = position.x;
|
||||
sfx.y = position.y;
|
||||
|
||||
void *c = sound->playSfx(sfx);
|
||||
|
||||
if (fadeOut != 0)
|
||||
{
|
||||
sound->fadeSfx(c, SFT_OUT, fadeOut);
|
||||
}
|
||||
|
||||
if (holder)
|
||||
holder->linkSound(c);
|
||||
}
|
||||
|
||||
void DSQ::shutdown()
|
||||
|
|
|
@ -1426,8 +1426,7 @@ public:
|
|||
bool voiceOversEnabled;
|
||||
int recentSaveSlot;
|
||||
|
||||
PlaySfx calcPositionalSfx(const Vector &position, float maxdist = 0);
|
||||
void playPositionalSfx(const std::string &name, const Vector &position, float freq=1.0f, float fadeOut=0);
|
||||
void playPositionalSfx(const std::string &name, const Vector &position, float freq=1.0f, float fadeOut=0, SoundHolder *holder = 0);
|
||||
|
||||
void playMenuSelectSfx();
|
||||
|
||||
|
|
|
@ -284,6 +284,8 @@ Entity::Entity()
|
|||
setDamageTarget(DT_AVATAR_BUBBLE, false);
|
||||
setDamageTarget(DT_AVATAR_SEED, false);
|
||||
|
||||
stopSoundsOnDeath = false;
|
||||
|
||||
|
||||
//debugLog("End Entity::Entity()");
|
||||
}
|
||||
|
@ -573,6 +575,10 @@ void Entity::watchEntity(Entity *e)
|
|||
|
||||
void Entity::destroy()
|
||||
{
|
||||
if (stopSoundsOnDeath)
|
||||
this->stopAllSounds();
|
||||
this->unlinkAllSounds();
|
||||
|
||||
/*
|
||||
if (hair)
|
||||
{
|
||||
|
@ -1231,6 +1237,8 @@ void Entity::update(float dt)
|
|||
position = backupPos;
|
||||
if (vel.isNan())
|
||||
vel = backupVel;
|
||||
|
||||
updateSoundPosition();
|
||||
}
|
||||
|
||||
void Entity::postUpdate(float dt)
|
||||
|
@ -2239,7 +2247,8 @@ void Entity::songNoteDone(int note, float len)
|
|||
|
||||
void Entity::sound(const std::string &sound, float freq, float fadeOut)
|
||||
{
|
||||
dsq->playPositionalSfx(sound, position, freq, fadeOut);
|
||||
dsq->playPositionalSfx(sound, position, freq, fadeOut, this);
|
||||
updateSoundPosition();
|
||||
}
|
||||
|
||||
Vector Entity::getEnergyShotTargetPosition()
|
||||
|
@ -3139,3 +3148,8 @@ bool Entity::isEntityInside()
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Entity::updateSoundPosition()
|
||||
{
|
||||
SoundHolder::updateSoundPosition(position.x + offset.x, position.y + offset.y);
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ enum BounceType
|
|||
BOUNCE_REAL = 1
|
||||
};
|
||||
|
||||
class Entity : public Quad, public StateMachine
|
||||
class Entity : public Quad, public StateMachine, public SoundHolder
|
||||
{
|
||||
public:
|
||||
Entity();
|
||||
|
@ -276,6 +276,7 @@ public:
|
|||
|
||||
void popBubble();
|
||||
void sound(const std::string &sound, float freq=1, float fadeOut=0);
|
||||
void setStopSoundsOnDeath(bool stop) { stopSoundsOnDeath = stop; }
|
||||
|
||||
void freeze(float time);
|
||||
|
||||
|
@ -492,6 +493,8 @@ public:
|
|||
|
||||
bool isEntityInside();
|
||||
|
||||
void updateSoundPosition();
|
||||
|
||||
protected:
|
||||
bool calledEntityDied;
|
||||
Path *waterBubble;
|
||||
|
@ -602,6 +605,8 @@ private:
|
|||
int maxSpeed;
|
||||
int oldMaxSpeed;
|
||||
|
||||
bool stopSoundsOnDeath;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8134,13 +8134,13 @@ void Game::playBurstSound(bool wallJump)
|
|||
int freqBase = 950;
|
||||
if (wallJump)
|
||||
freqBase += 100;
|
||||
sound->playSfx("Burst", 1, 0);//, (freqBase+rand()%25)/1000.0f);
|
||||
sound->playSfx("Burst", 1);
|
||||
if (chance(50))
|
||||
{
|
||||
switch (dsq->continuity.form)
|
||||
{
|
||||
case FORM_BEAST:
|
||||
sound->playSfx("BeastBurst", (128+rand()%64)/256.0f, 0);//, (freqBase+rand()%25)/1000.0f);
|
||||
sound->playSfx("BeastBurst", (128+rand()%64)/256.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2763,28 +2763,36 @@ luaFunc(entity_playSfx)
|
|||
void *h = NULL;
|
||||
if (e && !dsq->isSkippingCutscene())
|
||||
{
|
||||
PlaySfx sfx = dsq->calcPositionalSfx(e->position, lua_tonumber(L, 7));
|
||||
PlaySfx sfx;
|
||||
sfx.name = getString(L, 2);
|
||||
sfx.freq = lua_tonumber(L, 3);
|
||||
float vol = lua_tonumber(L, 4);
|
||||
sfx.vol = lua_tonumber(L, 4);
|
||||
sfx.loops = lua_tonumber(L, 5);
|
||||
|
||||
float fadeOut = lua_tonumber(L, 6);
|
||||
if(vol > 0)
|
||||
sfx.vol *= vol;
|
||||
|
||||
// FIXME: See comment in DSQ::playPositionalSfx() -- FG
|
||||
if (sfx.vol <= 0)
|
||||
luaReturnPtr(NULL);
|
||||
sfx.maxdist = lua_tonumber(L, 7);
|
||||
sfx.relative = false;
|
||||
|
||||
h = core->sound->playSfx(sfx);
|
||||
if (fadeOut != 0)
|
||||
{
|
||||
sound->fadeSfx(h, SFT_OUT, fadeOut);
|
||||
}
|
||||
|
||||
e->linkSound(h);
|
||||
e->updateSoundPosition();
|
||||
}
|
||||
luaReturnPtr(h);
|
||||
}
|
||||
|
||||
luaFunc(entity_setStopSoundsOnDeath)
|
||||
{
|
||||
Entity *e = entity(L);
|
||||
if (e)
|
||||
e->setStopSoundsOnDeath(getBool(L, 2));
|
||||
luaReturnNil();
|
||||
}
|
||||
|
||||
luaFunc(entity_setSpiritFreeze)
|
||||
{
|
||||
Entity *e = entity(L);
|
||||
|
@ -5927,32 +5935,20 @@ luaFunc(emote)
|
|||
|
||||
luaFunc(playSfx)
|
||||
{
|
||||
float freq = lua_tonumber(L, 2);
|
||||
float vol = lua_tonumber(L, 3);
|
||||
int loops = lua_tointeger(L, 4);
|
||||
if (vol <= 0)
|
||||
vol = 1;
|
||||
|
||||
PlaySfx sfx;
|
||||
|
||||
if (lua_isnumber(L, 5) && lua_isnumber(L, 6))
|
||||
{
|
||||
const Vector pos(lua_tonumber(L, 5), lua_tonumber(L, 6));
|
||||
sfx = dsq->calcPositionalSfx(pos, lua_tonumber(L, 7));
|
||||
sfx.vol *= vol;
|
||||
}
|
||||
else
|
||||
{
|
||||
sfx.vol = vol;
|
||||
}
|
||||
|
||||
// FIXME: See comment in DSQ::playPositionalSfx() -- FG
|
||||
if (sfx.vol <= 0)
|
||||
luaReturnPtr(NULL);
|
||||
|
||||
sfx.name = getString(L, 1);
|
||||
sfx.freq = freq;
|
||||
sfx.loops = loops;
|
||||
sfx.freq = lua_tonumber(L, 2);
|
||||
sfx.vol = lua_tonumber(L, 3);
|
||||
if (sfx.vol <= 0)
|
||||
sfx.vol = 1;
|
||||
sfx.loops = lua_tointeger(L, 4);
|
||||
sfx.x = lua_tonumber(L, 5);
|
||||
sfx.y = lua_tonumber(L, 6);
|
||||
sfx.maxdist = lua_tonumber(L, 7);
|
||||
if(lua_isnoneornil(L, 8))
|
||||
sfx.relative = (sfx.x == 0 && sfx.y == 0);
|
||||
else
|
||||
sfx.relative = getBool(L, 8);
|
||||
|
||||
void *handle = NULL;
|
||||
|
||||
|
|
|
@ -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
Reference in a new issue