1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-11-15 14:09:06 +00:00

Merge branch 'posaudio'

This commit is contained in:
fgenesis 2013-07-26 23:34:02 +02:00
commit 9e1e4264ee
14 changed files with 601 additions and 199 deletions

View file

@ -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;

View file

@ -2293,58 +2293,23 @@ 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.positional = true;
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()

View file

@ -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();

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -2763,28 +2763,39 @@ 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);
if(sfx.vol <= 0)
sfx.vol = 1;
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);
float fadeOut = lua_tonumber(L, 6);
sfx.maxdist = lua_tonumber(L, 7);
sfx.relative = false;
sfx.positional = true;
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 +5938,24 @@ 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);
if(lua_isnumber(L, 6) && lua_isnumber(L, 7))
{
sfx.x = lua_tonumber(L, 5);
sfx.y = lua_tonumber(L, 6);
sfx.positional = true;
}
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;

View file

@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef BBGE_BUILD_WINDOWS
#define WIN32_LEAN_AND_MEAN
#define WIN32_NOMINMAX
#include <windows.h>
#ifdef _MSC_VER

View file

@ -3138,6 +3138,8 @@ void Core::main(float runTime)
}
}
sound->setListenerPos(screenCenter.x, screenCenter.y);
if (doScreenshot)
{
if (verbose) debugLog("screenshot");

View file

@ -49,6 +49,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//#define _DEBUG 1
#endif
#undef min
#undef max
// HACK: global because OpenAL has only one listener anyway
static FMOD_VECTOR s_listenerPos;
///////////////////////////////////////////////////////////////////////////
// Decoder implementation for streamed Ogg Vorbis audio.
@ -63,8 +69,12 @@ public:
~OggDecoder();
// Start playing on the given channel, with optional looping.
bool start(ALuint source, bool loop);
// Prepare playing on the given channel.
bool preStart(ALuint source);
// Decodes the first few buffers, starts the actual playback and detaches the decoder
// from the main thread, with optional looping.
void start(bool loop);
// Decode audio into any free buffers. Must be called periodically
// on systems without threads; may be called without harm on systems
@ -85,6 +95,10 @@ public:
static void startDecoderThread();
static void stopDecoderThread();
int getNumChannels() const { return channels; }
void setForceMono(bool mono) { forcemono = mono; }
private:
void _stop();
@ -114,7 +128,9 @@ private:
OggVorbis_File vf;
ALenum format;
int channels;
int freq;
bool forcemono;
bool thread; // true if played by background thread
@ -272,6 +288,9 @@ OggDecoder::OggDecoder(VFILE *fp)
this->eof = false;
this->samples_done = 0;
this->stopped = false;
this->format = 0;
this->channels = 0;
this->forcemono = false;
}
OggDecoder::OggDecoder(const void *data, long data_size)
@ -291,6 +310,9 @@ OggDecoder::OggDecoder(const void *data, long data_size)
this->eof = false;
this->samples_done = 0;
this->stopped = false;
this->format = 0;
this->channels = 0;
this->forcemono = false;
}
OggDecoder::~OggDecoder()
@ -304,10 +326,9 @@ OggDecoder::~OggDecoder()
}
}
bool OggDecoder::start(ALuint source, bool loop)
bool OggDecoder::preStart(ALuint source)
{
this->source = source;
this->loop = loop;
if (fp) {
if (ov_open_callbacks(fp, &vf, NULL, 0, local_OV_CALLBACKS_NOCLOSE) != 0)
@ -333,6 +354,7 @@ bool OggDecoder::start(ALuint source, bool loop)
ov_clear(&vf);
return false;
}
channels = info->channels;
if (info->channels == 1)
format = AL_FORMAT_MONO16;
else if (info->channels == 2)
@ -368,6 +390,13 @@ bool OggDecoder::start(ALuint source, bool loop)
return false;
}
return true;
}
void OggDecoder::start(bool loop)
{
this->loop = loop;
playing = true;
eof = false;
samples_done = 0;
@ -375,8 +404,6 @@ bool OggDecoder::start(ALuint source, bool loop)
queue(buffers[i]);
detachDecoder(this);
return true;
}
void OggDecoder::update()
@ -493,7 +520,22 @@ void OggDecoder::queue(ALuint buffer)
if (pcm_size > 0)
{
alBufferData(buffer, format, pcm_buffer, pcm_size, freq);
ALuint fmt = format;
if(channels == 2 && forcemono)
{
signed short *buf = (short*)&pcm_buffer[0];
int numSamples = pcm_size / 2; // 16 bit samples
int j = 0;
for (int i = 0; i < numSamples ; i += 2)
{
// This is in theory not quite correct, but it doesn't add any artifacts or clipping.
// FIXME: Seems that simple and stupid is the method of choice, then... -- FG
buf[j++] = (buf[i] + buf[i+1]) / 2;
}
pcm_size = numSamples;
fmt = AL_FORMAT_MONO16;
}
alBufferData(buffer, fmt, pcm_buffer, pcm_size, freq);
alSourceQueueBuffers(source, 1, &buffer);
}
}
@ -597,8 +639,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 +653,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 +664,7 @@ OpenALSound::OpenALSound(VFILE *_fp, const bool _looping)
, refcount(1)
, raw(false)
, bid(0)
, numChannels(0)
{
}
@ -629,6 +676,7 @@ OpenALSound::OpenALSound(void *_data, long _size, const bool _looping)
, refcount(1)
, raw(false)
, bid(0)
, numChannels(0)
{
}
@ -640,6 +688,7 @@ OpenALSound::OpenALSound(ALuint _bid, const bool _looping)
, refcount(1)
, raw(true)
, bid(_bid)
, numChannels(0)
{
}
@ -665,6 +714,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;
@ -672,7 +729,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);
@ -681,8 +738,16 @@ public:
FMOD_RESULT isPlaying(bool *isplaying);
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 setDistanceVolume(float _volume);
void setSourceName(const ALuint _sid) { sid = _sid; }
ALuint getSourceName() const { return sid; }
bool start(OpenALSound *sound);
@ -692,9 +757,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;
@ -703,6 +771,12 @@ private:
OggDecoder *decoder;
bool inuse;
bool initial;
FMOD_CHANNEL_CALLBACK callback;
void *userdata;
FMOD_MODE _mode;
float mindist;
float maxdist;
bool relative;
};
@ -735,6 +809,7 @@ OpenALChannel::OpenALChannel()
: sid(0)
, groupvolume(1.0f)
, volume(1.0f)
, distvolume(1.0f)
, paused(false)
, priority(0)
, frequency(1.0f)
@ -743,6 +818,10 @@ OpenALChannel::OpenALChannel()
, decoder(NULL)
, inuse(false)
, initial(true)
, _mode(FMOD_DEFAULT)
, mindist(0.0f)
, maxdist(0.0f)
, relative(false)
{
}
@ -751,18 +830,21 @@ void OpenALChannel::reacquire()
assert(!inuse);
inuse = true;
volume = 1.0f;
distvolume = 1.0f;
paused = true;
priority = 0;
frequency = 1.0f;
sound = NULL;
initial = true;
mindist = 0.0f;
maxdist = 0.0f;
relative = false;
}
void OpenALChannel::setGroupVolume(const float _volume)
{
groupvolume = _volume;
alSourcef(sid, AL_GAIN, volume * groupvolume);
SANITY_CHECK_OPENAL_CALL();
applyVolume();
}
bool OpenALChannel::start(OpenALSound *sound)
@ -780,12 +862,13 @@ bool OpenALChannel::start(OpenALSound *sound)
decoder = new OggDecoder(sound->getFile());
else
decoder = new OggDecoder(sound->getData(), sound->getSize());
if (!decoder->start(sid, sound->isLooping()))
if (!decoder->preStart(sid))
{
delete decoder;
decoder = NULL;
return false;
}
sound->setNumChannels(decoder->getNumChannels());
}
return true;
}
@ -805,12 +888,10 @@ 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;
alSourcef(sid, AL_GAIN, _volume * groupvolume);
SANITY_CHECK_OPENAL_CALL();
volume = _volume;
applyVolume();
return FMOD_OK;
}
@ -896,6 +977,11 @@ FMOD_RESULT OpenALChannel::setPaused(const bool _paused, const bool setstate)
}
else if ((!_paused) && (initial || ((state == AL_INITIAL) || (state == AL_PAUSED))))
{
if (initial && decoder)
{
decoder->setForceMono(mindist || maxdist); // HACK: this is set for positional sounds.
decoder->start(sound->isLooping());
}
alSourcePlay(sid);
initial = false;
SANITY_CHECK_OPENAL_CALL();
@ -914,15 +1000,161 @@ FMOD_RESULT OpenALChannel::setPriority(int _priority)
return FMOD_OK;
}
ALBRIDGE(Channel,setPan,(float volume),(volume))
FMOD_RESULT OpenALChannel::setPan(const float pan)
ALBRIDGE(Channel,stop,(),())
FMOD_RESULT OpenALChannel::stop()
{
alSource3f(sid, AL_POSITION, pan, 0, 0);
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); // HACK: commanddata missing (but they are not used by the callback)
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(maxdist == mindist)
setDistanceVolume(1.0f);
else
{
// This is where custom distance attenuation starts.
float dx, dy, dz;
if(relative)
{
dx = pos->x;
dy = pos->y;
dz = pos->z;
}
else
{
dx = s_listenerPos.x - pos->x;
dy = s_listenerPos.y - pos->y;
dz = s_listenerPos.z - pos->z;
}
float d2 = dx*dx + dy*dy + dz*dz;
if(d2 < mindist*mindist)
setDistanceVolume(1.0f);
else if(d2 > maxdist*maxdist)
setDistanceVolume(0.0f);
else
{
// Replacement method for AL_INVERSE_DISTANCE_CLAMPED.
// The problem with this distance model is that the volume never goes down
// to 0, no matter how far sound sources are away from the listener.
// This could be fixed by using AL_LINEAR_DISTANCE_CLAMPED, but this model does not sound
// natural (as the gain/volume/decibels is a logarithmic measure).
// As a remedy, use a simplified quadratic 1D-bezier curve to model
// a decay similar to AL_INVERSE_DISTANCE_CLAMPED, but that actually reaches 0.
// (The formula is simplified, as the control points (1, 0, 0) cause some math to vanish.) -- FG
const float t = ((sqrtf(d2) - mindist) / (maxdist - mindist)); // [0 .. 1]
const float t1 = 1.0f - t;
const float a = t1 * t1;
const float w = 2.0f; // weight; the higher this is, the steeper is the initial falloff, and the slower the final decay before reaching 0
const float gain = a / (a + (2.0f * w * t * t1) + (t * t));
setDistanceVolume(gain);
}
}
}
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();
mindist = mindistance;
maxdist = maxdistance;
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;
}
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...
OpenALChannelGroup::OpenALChannelGroup(const char *_name)
@ -1066,29 +1298,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 +1321,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);
@ -1247,8 +1457,11 @@ FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE
alGenBuffers(1, &bid);
if (bid != 0)
{
// FIXME: This needs to stored seperately and fed to the AL on demand,
// converting stereo to mono when it's known whether to do so or not.
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);
@ -1415,7 +1628,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 +1639,15 @@ 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().
// We do our own non-standard distance attenuation model, as the modes offered by OpenAL
// are not sufficient. See OpenALChannel::set3DMinMaxDistance() for the gain control code. -- FG
alDistanceModel(AL_NONE);
SANITY_CHECK_OPENAL_CALL();
s_listenerPos.x = s_listenerPos.y = s_listenerPos.z = 0.0f;
OggDecoder::startDecoderThread();
return FMOD_OK;
@ -1539,6 +1761,46 @@ 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)
{
s_listenerPos = *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...

View file

@ -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,15 @@ 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_SOUND_FORMAT;
typedef int FMOD_SOUND_TYPE;
typedef int FMOD_CREATESOUNDEXINFO;
#define FMOD_INIT_NORMAL 0
@ -92,6 +117,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
{
@ -112,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
@ -145,7 +173,13 @@ namespace FMOD
FMOD_RESULT setPriority(int priority);
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 +199,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);

View file

@ -1,10 +1,5 @@
#include "Localization.h"
#ifdef BBGE_BUILD_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#ifdef BBGE_BUILD_UNIX
#include <sys/types.h>
#include <sys/stat.h>

View file

@ -1055,8 +1055,12 @@ bool SoundManager::playVoice(const std::string &name, SoundVoiceType svt, float
checkError();
*/
voiceChannel->setPan(0);
voiceChannel->setFrequency(1);
voiceChannel->setCallback(NULL);
voiceChannel->setUserData(NULL);
voiceChannel->set3DMinMaxDistance(0.0f, 0.0f);
setSoundRelative(voiceChannel, true);
setSoundPos(voiceChannel, 0, 0);
result = voiceChannel->setPaused(false);
checkError();
@ -1143,13 +1147,30 @@ void *SoundManager::playSfx(const PlaySfx &play)
checkError();
}
channel->setPan(play.pan);
float freq = play.freq;
if (freq <= 0)
freq = 1;
channel->setFrequency(freq);
channel->setCallback(NULL);
channel->setUserData(NULL);
// distance gain attenuation: stereo separation + silence at further away than maxdist
float maxdist = play.maxdist;
if (!maxdist)
maxdist = 1800;
if(maxdist > 0 && play.positional)
channel->set3DMinMaxDistance(maxdist * 0.3, maxdist); // HACK: this works reasonably well
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);
checkError();
@ -1160,23 +1181,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 +1214,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);
@ -1372,7 +1338,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
setSoundRelative(musicChannel, true);
setSoundPos(musicChannel, 0, 0);
result = musicChannel->setPaused(false); // This is where the sound really starts.
checkError();
@ -1557,7 +1527,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 +1650,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());
}

View file

@ -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,27 @@ 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), positional(false) {}
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; // relative to listener?
bool positional; // if true, this indicates that we want positional sound (stereo will be downmixed to mono to make OpenAL happy)
};
class SoundHolder; // defined below
class SoundManager
{
public:
@ -140,16 +148,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 +258,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