1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-08-10 16:19:59 +00:00

Merge branch 'posaudio' of file:///Users/User/code/coding/Aquaria_fg_clean

This commit is contained in:
fgenesis 2013-07-24 04:36:43 +01:00
commit 965ec50228

View file

@ -52,6 +52,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef min #undef min
#undef max #undef max
// HACK: global because OpenAL has only one listener anyway
static FMOD_VECTOR s_listenerPos;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Decoder implementation for streamed Ogg Vorbis audio. // Decoder implementation for streamed Ogg Vorbis audio.
@ -88,7 +91,9 @@ public:
static void startDecoderThread(); static void startDecoderThread();
static void stopDecoderThread(); static void stopDecoderThread();
ALenum getFormat() const { return format; } int getNumChannels() const { return channels; }
void setForceMono(bool mono) { forcemono = mono; }
private: private:
@ -119,7 +124,9 @@ private:
OggVorbis_File vf; OggVorbis_File vf;
ALenum format; ALenum format;
int channels;
int freq; int freq;
bool forcemono;
bool thread; // true if played by background thread bool thread; // true if played by background thread
@ -277,6 +284,9 @@ OggDecoder::OggDecoder(VFILE *fp)
this->eof = false; this->eof = false;
this->samples_done = 0; this->samples_done = 0;
this->stopped = false; this->stopped = false;
this->format = 0;
this->channels = 0;
this->forcemono = false;
} }
OggDecoder::OggDecoder(const void *data, long data_size) OggDecoder::OggDecoder(const void *data, long data_size)
@ -296,6 +306,9 @@ OggDecoder::OggDecoder(const void *data, long data_size)
this->eof = false; this->eof = false;
this->samples_done = 0; this->samples_done = 0;
this->stopped = false; this->stopped = false;
this->format = 0;
this->channels = 0;
this->forcemono = false;
} }
OggDecoder::~OggDecoder() OggDecoder::~OggDecoder()
@ -338,6 +351,7 @@ bool OggDecoder::start(ALuint source, bool loop)
ov_clear(&vf); ov_clear(&vf);
return false; return false;
} }
channels = info->channels;
if (info->channels == 1) if (info->channels == 1)
format = AL_FORMAT_MONO16; format = AL_FORMAT_MONO16;
else if (info->channels == 2) else if (info->channels == 2)
@ -680,9 +694,9 @@ FMOD_RESULT OpenALSound::release()
ALBRIDGE(Sound,getFormat,(FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits),(type, format, channels, bits)) 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) FMOD_RESULT OpenALSound::getFormat(FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits)
{ {
if(channels) if(channels)
*channels = getNumChannels(); *channels = getNumChannels();
return FMOD_OK; return FMOD_OK;
} }
@ -710,7 +724,7 @@ public:
FMOD_RESULT getMode(FMOD_MODE *mode); FMOD_RESULT getMode(FMOD_MODE *mode);
void setGroupVolume(const float _volume); void setGroupVolume(const float _volume);
void setDistanceVolume(float _volume); void setDistanceVolume(float _volume);
void setSourceName(const ALuint _sid) { sid = _sid; } void setSourceName(const ALuint _sid) { sid = _sid; }
ALuint getSourceName() const { return sid; } ALuint getSourceName() const { return sid; }
bool start(OpenALSound *sound); bool start(OpenALSound *sound);
@ -737,6 +751,9 @@ private:
FMOD_CHANNEL_CALLBACK callback; FMOD_CHANNEL_CALLBACK callback;
void *userdata; void *userdata;
FMOD_MODE _mode; FMOD_MODE _mode;
float mindist;
float maxdist;
bool relative;
}; };
@ -779,6 +796,9 @@ OpenALChannel::OpenALChannel()
, inuse(false) , inuse(false)
, initial(true) , initial(true)
, _mode(FMOD_DEFAULT) , _mode(FMOD_DEFAULT)
, mindist(0.0f)
, maxdist(0.0f)
, relative(false)
{ {
} }
@ -793,6 +813,9 @@ void OpenALChannel::reacquire()
frequency = 1.0f; frequency = 1.0f;
sound = NULL; sound = NULL;
initial = true; initial = true;
mindist = 0.0f;
maxdist = 0.0f;
relative = false;
} }
void OpenALChannel::setGroupVolume(const float _volume) void OpenALChannel::setGroupVolume(const float _volume)
@ -822,7 +845,7 @@ bool OpenALChannel::start(OpenALSound *sound)
decoder = NULL; decoder = NULL;
return false; return false;
} }
sound->setNumChannels((decoder->getFormat() == AL_FORMAT_STEREO16) ? 2 : 1); sound->setNumChannels(decoder->getNumChannels());
} }
return true; return true;
} }
@ -952,134 +975,154 @@ FMOD_RESULT OpenALChannel::setPriority(int _priority)
ALBRIDGE(Channel,stop,(),()) ALBRIDGE(Channel,stop,(),())
FMOD_RESULT OpenALChannel::stop() FMOD_RESULT OpenALChannel::stop()
{ {
if (decoder) if (decoder)
{ {
decoder->stop(); decoder->stop();
decoder = NULL; decoder = NULL;
} }
alSourceStop(sid); alSourceStop(sid);
SANITY_CHECK_OPENAL_CALL(); SANITY_CHECK_OPENAL_CALL();
alSourcei(sid, AL_BUFFER, 0); alSourcei(sid, AL_BUFFER, 0);
SANITY_CHECK_OPENAL_CALL(); SANITY_CHECK_OPENAL_CALL();
if (sound) if (sound)
{ {
sound->release(); sound->release();
sound = NULL; sound = NULL;
} }
if (inuse && callback) if (inuse && callback)
callback(this, FMOD_CHANNEL_CALLBACKTYPE_END, NULL, NULL); // FIXME commanddata missing callback(this, FMOD_CHANNEL_CALLBACKTYPE_END, NULL, NULL); // HACK: commanddata missing (but they are not used by the callback)
paused = false; paused = false;
inuse = false; inuse = false;
initial = false; initial = false;
return FMOD_OK; return FMOD_OK;
} }
ALBRIDGE(Channel,setCallback,(FMOD_CHANNEL_CALLBACK callback),(callback)) ALBRIDGE(Channel,setCallback,(FMOD_CHANNEL_CALLBACK callback),(callback))
FMOD_RESULT OpenALChannel::setCallback(FMOD_CHANNEL_CALLBACK callback) FMOD_RESULT OpenALChannel::setCallback(FMOD_CHANNEL_CALLBACK callback)
{ {
this->callback = callback; this->callback = callback;
return FMOD_OK; return FMOD_OK;
} }
ALBRIDGE(Channel,getUserData,(void **userdata),(userdata)) ALBRIDGE(Channel,getUserData,(void **userdata),(userdata))
FMOD_RESULT OpenALChannel::getUserData(void **userdata) FMOD_RESULT OpenALChannel::getUserData(void **userdata)
{ {
*userdata = this->userdata; *userdata = this->userdata;
return FMOD_OK; return FMOD_OK;
} }
ALBRIDGE(Channel,setUserData,(void *userdata),(userdata)) ALBRIDGE(Channel,setUserData,(void *userdata),(userdata))
FMOD_RESULT OpenALChannel::setUserData(void *userdata) FMOD_RESULT OpenALChannel::setUserData(void *userdata)
{ {
this->userdata = userdata; this->userdata = userdata;
return FMOD_OK; return FMOD_OK;
} }
ALBRIDGE(Channel,set3DAttributes,(const FMOD_VECTOR *pos, const FMOD_VECTOR *vel),(pos, vel)) 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) FMOD_RESULT OpenALChannel::set3DAttributes(const FMOD_VECTOR *pos, const FMOD_VECTOR *vel)
{ {
if (pos) if (pos)
{ {
alSource3f(sid, AL_POSITION, pos->x, pos->y, pos->z); 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(maxdist == mindist)
if(vel) setDistanceVolume(1.0f);
alSource3f(sid, AL_VELOCITY, vel->x, vel->y, vel->z); 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;
}
SANITY_CHECK_OPENAL_CALL(); float d2 = dx*dx + dy*dy + dz*dz;
return FMOD_OK; 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)) ALBRIDGE(Channel,set3DMinMaxDistance,(float mindistance, float maxdistance),(mindistance, maxdistance))
FMOD_RESULT OpenALChannel::set3DMinMaxDistance(float mindistance, float maxdistance) FMOD_RESULT OpenALChannel::set3DMinMaxDistance(float mindistance, float maxdistance)
{ {
alSourcef(sid, AL_REFERENCE_DISTANCE, mindistance); alSourcef(sid, AL_REFERENCE_DISTANCE, mindistance);
alSourcef(sid, AL_MAX_DISTANCE, maxdistance); alSourcef(sid, AL_MAX_DISTANCE, maxdistance);
SANITY_CHECK_OPENAL_CALL(); SANITY_CHECK_OPENAL_CALL();
return FMOD_OK; mindist = mindistance;
maxdist = maxdistance;
return FMOD_OK;
} }
ALBRIDGE(Channel,setMode,(FMOD_MODE mode),(mode)) ALBRIDGE(Channel,setMode,(FMOD_MODE mode),(mode))
FMOD_RESULT OpenALChannel::setMode(FMOD_MODE mode) FMOD_RESULT OpenALChannel::setMode(FMOD_MODE mode)
{ {
_mode = mode; _mode = mode;
if(mode & FMOD_3D_HEADRELATIVE) if(mode & FMOD_3D_HEADRELATIVE)
alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE);
else // FMOD_3D_WORLDRELATIVE is the default according to FMOD docs else // FMOD_3D_WORLDRELATIVE is the default according to FMOD docs
alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE); alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE);
SANITY_CHECK_OPENAL_CALL(); SANITY_CHECK_OPENAL_CALL();
return FMOD_OK; return FMOD_OK;
} }
ALBRIDGE(Channel,getMode,(FMOD_MODE *mode),(mode)) ALBRIDGE(Channel,getMode,(FMOD_MODE *mode),(mode))
FMOD_RESULT OpenALChannel::getMode(FMOD_MODE *mode) FMOD_RESULT OpenALChannel::getMode(FMOD_MODE *mode)
{ {
*mode = _mode; *mode = _mode;
return FMOD_OK; return FMOD_OK;
} }
void OpenALChannel::setDistanceVolume(float _volume) void OpenALChannel::setDistanceVolume(float _volume)
{ {
distvolume = _volume; distvolume = _volume;
applyVolume(); applyVolume();
} }
void OpenALChannel::applyVolume() void OpenALChannel::applyVolume()
{ {
alSourcef(sid, AL_GAIN, volume * groupvolume * distvolume); alSourcef(sid, AL_GAIN, volume * groupvolume * distvolume);
SANITY_CHECK_OPENAL_CALL(); SANITY_CHECK_OPENAL_CALL();
} }
@ -1568,8 +1611,11 @@ FMOD_RESULT OpenALSystem::init(int maxchannels, const FMOD_INITFLAGS flags, cons
// HACK: FMOD doesn't do this. // HACK: FMOD doesn't do this.
// For completeness, we pass FMOD_3D_LINEARROLLOFF to createSound(). // For completeness, we pass FMOD_3D_LINEARROLLOFF to createSound().
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); // 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(); SANITY_CHECK_OPENAL_CALL();
s_listenerPos.x = s_listenerPos.y = s_listenerPos.z = 0.0f;
OggDecoder::startDecoderThread(); OggDecoder::startDecoderThread();
@ -1714,7 +1760,10 @@ FMOD_RESULT OpenALSystem::set3DListenerAttributes(int listener, const FMOD_VECTO
} }
if(pos) if(pos)
{
s_listenerPos = *pos;
alListener3f(AL_POSITION, pos->x, pos->y, pos->z); alListener3f(AL_POSITION, pos->x, pos->y, pos->z);
}
if(vel) if(vel)
alListener3f(AL_VELOCITY, vel->x, vel->y, vel->z); alListener3f(AL_VELOCITY, vel->x, vel->y, vel->z);