diff --git a/Aquaria/ScriptInterface.cpp b/Aquaria/ScriptInterface.cpp index b795311..8749efa 100644 --- a/Aquaria/ScriptInterface.cpp +++ b/Aquaria/ScriptInterface.cpp @@ -2767,6 +2767,8 @@ luaFunc(entity_playSfx) sfx.name = getString(L, 2); sfx.freq = lua_tonumber(L, 3); sfx.vol = lua_tonumber(L, 4); + if(sfx.vol <= 0) + sfx.vol = 1; sfx.loops = lua_tonumber(L, 5); float fadeOut = lua_tonumber(L, 6); diff --git a/BBGE/FmodOpenALBridge.cpp b/BBGE/FmodOpenALBridge.cpp index 47f480e..57e5d4b 100644 --- a/BBGE/FmodOpenALBridge.cpp +++ b/BBGE/FmodOpenALBridge.cpp @@ -49,6 +49,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //#define _DEBUG 1 #endif +#undef min +#undef max + /////////////////////////////////////////////////////////////////////////// // Decoder implementation for streamed Ogg Vorbis audio. @@ -85,6 +88,8 @@ public: static void startDecoderThread(); static void stopDecoderThread(); + ALenum getFormat() const { return format; } + private: void _stop(); @@ -597,8 +602,11 @@ public: bool isLooping() const { return looping; } bool isRaw() const { return raw; } FMOD_RESULT release(); + FMOD_RESULT getFormat(FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); void reference() { refcount++; } ALuint getBufferName() const { return bid; } + int getNumChannels() const { return numChannels; } + void setNumChannels(int c) { numChannels = c; } private: VFILE * const fp; @@ -608,6 +616,7 @@ private: int refcount; const bool raw; // true if buffer holds raw PCM data ALuint bid; // only used if raw == true + int numChannels; }; OpenALSound::OpenALSound(VFILE *_fp, const bool _looping) @@ -618,6 +627,7 @@ OpenALSound::OpenALSound(VFILE *_fp, const bool _looping) , refcount(1) , raw(false) , bid(0) + , numChannels(0) { } @@ -629,6 +639,7 @@ OpenALSound::OpenALSound(void *_data, long _size, const bool _looping) , refcount(1) , raw(false) , bid(0) + , numChannels(0) { } @@ -640,6 +651,7 @@ OpenALSound::OpenALSound(ALuint _bid, const bool _looping) , refcount(1) , raw(true) , bid(_bid) + , numChannels(0) { } @@ -665,6 +677,14 @@ FMOD_RESULT OpenALSound::release() return FMOD_OK; } +ALBRIDGE(Sound,getFormat,(FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits),(type, format, channels, bits)) +FMOD_RESULT OpenALSound::getFormat(FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits) +{ + if(channels) + *channels = getNumChannels(); + return FMOD_OK; +} + class OpenALChannelGroup; @@ -691,6 +711,7 @@ public: FMOD_RESULT getMode(FMOD_MODE *mode); void setGroupVolume(const float _volume); + void setDistanceVolume(float _volume); void setSourceName(const ALuint _sid) { sid = _sid; } ALuint getSourceName() const { return sid; } bool start(OpenALSound *sound); @@ -700,9 +721,12 @@ public: void setSound(OpenALSound *sound); private: + void applyVolume(); + ALuint sid; // source id. float groupvolume; float volume; + float distvolume; bool paused; int priority; float frequency; @@ -746,6 +770,7 @@ OpenALChannel::OpenALChannel() : sid(0) , groupvolume(1.0f) , volume(1.0f) + , distvolume(1.0f) , paused(false) , priority(0) , frequency(1.0f) @@ -763,6 +788,7 @@ void OpenALChannel::reacquire() assert(!inuse); inuse = true; volume = 1.0f; + distvolume = 1.0f; paused = true; priority = 0; frequency = 1.0f; @@ -773,8 +799,7 @@ void OpenALChannel::reacquire() void OpenALChannel::setGroupVolume(const float _volume) { groupvolume = _volume; - alSourcef(sid, AL_GAIN, volume * groupvolume); - SANITY_CHECK_OPENAL_CALL(); + applyVolume(); } bool OpenALChannel::start(OpenALSound *sound) @@ -798,6 +823,7 @@ bool OpenALChannel::start(OpenALSound *sound) decoder = NULL; return false; } + sound->setNumChannels((decoder->getFormat() == AL_FORMAT_STEREO16) ? 2 : 1); } return true; } @@ -820,8 +846,7 @@ ALBRIDGE(Channel,setVolume,(float volume),(volume)) FMOD_RESULT OpenALChannel::setVolume(const float _volume) { volume = _volume; - alSourcef(sid, AL_GAIN, _volume * groupvolume); - SANITY_CHECK_OPENAL_CALL(); + applyVolume(); return FMOD_OK; } @@ -984,7 +1009,37 @@ ALBRIDGE(Channel,set3DAttributes,(const FMOD_VECTOR *pos, const FMOD_VECTOR *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); + int chans = sound->getNumChannels(); + if(sound->getNumChannels() == 1) + setDistanceVolume(1); // nothing to do + else + { + // HACK: reduce volume if far away (OpanAL does not do this for stereo sounds) + // HACK: assume linear distance model + ALfloat listenerPos[3]; + ALint relative = 0; + alGetSourcei(sid, AL_SOURCE_RELATIVE, &relative); + if(relative) + listenerPos[0] = listenerPos[1] = listenerPos[2] = 0; + else + alGetListenerfv(AL_POSITION, &listenerPos[0]); + float dx = listenerPos[0] - pos->x; + float dy = listenerPos[1] - pos->y; + float dz = listenerPos[2] - pos->z; + float distance = sqrtf(dx*dx + dy*dy + dz*dz); + float rolloff = 1, refdist = 0, maxdist = 0; + alGetSourcef(sid, AL_ROLLOFF_FACTOR, &rolloff); + alGetSourcef(sid, AL_REFERENCE_DISTANCE, &refdist); + alGetSourcef(sid, AL_MAX_DISTANCE, &maxdist); + distance = std::max(distance, refdist); + distance = std::min(distance, maxdist); + float gain = (maxdist == refdist) ? 1 : (1 - rolloff * (distance - refdist) / (maxdist - refdist)); + setDistanceVolume(gain); + } + + } if(vel) alSource3f(sid, AL_VELOCITY, vel->x, vel->y, vel->z); @@ -1024,6 +1079,18 @@ FMOD_RESULT OpenALChannel::getMode(FMOD_MODE *mode) return FMOD_OK; } +void OpenALChannel::setDistanceVolume(float _volume) +{ + distvolume = _volume; + applyVolume(); +} + +void OpenALChannel::applyVolume() +{ + alSourcef(sid, AL_GAIN, volume * groupvolume * distvolume); + SANITY_CHECK_OPENAL_CALL(); +} + // FMOD::ChannelGroup implementation... @@ -1330,6 +1397,7 @@ FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE { alBufferData(bid, format, data, size, freq); *sound = (Sound *) new OpenALSound(bid, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL))); + ((OpenALSound*)*sound)->setNumChannels(format == AL_FORMAT_STEREO16 ? 2 : 1); retval = FMOD_OK; } free(data); diff --git a/BBGE/FmodOpenALBridge.h b/BBGE/FmodOpenALBridge.h index 6de856b..0b1f28e 100644 --- a/BBGE/FmodOpenALBridge.h +++ b/BBGE/FmodOpenALBridge.h @@ -101,6 +101,8 @@ typedef int FMOD_MODE; #define FMOD_3D_LINEARROLLOFF (1<<10) #define FMOD_DEFAULT (FMOD_2D | FMOD_HARDWARE) +typedef int FMOD_SOUND_FORMAT; +typedef int FMOD_SOUND_TYPE; typedef int FMOD_CREATESOUNDEXINFO; @@ -137,6 +139,7 @@ namespace FMOD { public: FMOD_RESULT release(); + FMOD_RESULT getFormat(FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); // only *channels implemented }; class DSP diff --git a/BBGE/SoundManager.cpp b/BBGE/SoundManager.cpp index 621c83b..a3de5a2 100644 --- a/BBGE/SoundManager.cpp +++ b/BBGE/SoundManager.cpp @@ -1060,8 +1060,8 @@ bool SoundManager::playVoice(const std::string &name, SoundVoiceType svt, float voiceChannel->setCallback(NULL); voiceChannel->setUserData(NULL); voiceChannel->set3DMinMaxDistance(0.0f, 0.0f); - setSoundPos(voiceChannel, 0, 0); setSoundRelative(voiceChannel, true); + setSoundPos(voiceChannel, 0, 0); result = voiceChannel->setPaused(false); checkError(); @@ -1158,10 +1158,6 @@ void *SoundManager::playSfx(const PlaySfx &play) 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) @@ -1172,6 +1168,10 @@ void *SoundManager::playSfx(const PlaySfx &play) else channel->set3DMinMaxDistance(0, 0); // no attenuation + // position in space + setSoundRelative(channel, play.relative); + setSoundPos(channel, play.x, play.y); // must be set after everything else (See hack in OpenALChannel::set3DAttributes()) + result = channel->setPaused(false); @@ -1344,9 +1344,9 @@ bool SoundManager::playMusic(const std::string &name, SoundLoopType slt, SoundFa 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); + musicChannel->set3DMinMaxDistance(0.0f, 0.0f); // disable attenuation setSoundRelative(musicChannel, true); + setSoundPos(musicChannel, 0, 0); result = musicChannel->setPaused(false); // This is where the sound really starts. checkError();