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

Implement stereo to mono mixing for proper L/R separation even for stereo samples.

This mixes only those sounds that are supposed to be played positional.
All centered (default) sounds are played in stereo, as usual.
This commit is contained in:
fgenesis 2013-07-24 19:57:13 +02:00
parent 66802e1935
commit cf6556b94d
5 changed files with 51 additions and 14 deletions

View file

@ -2299,6 +2299,7 @@ void DSQ::playPositionalSfx(const std::string &name, const Vector &position, flo
sfx.freq = f;
sfx.name = name;
sfx.relative = false;
sfx.positional = true;
sfx.x = position.x;
sfx.y = position.y;

View file

@ -2774,6 +2774,7 @@ luaFunc(entity_playSfx)
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)
@ -5944,8 +5945,12 @@ luaFunc(playSfx)
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);
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);

View file

@ -69,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
@ -322,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)
@ -387,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;
@ -394,8 +404,6 @@ bool OggDecoder::start(ALuint source, bool loop)
queue(buffers[i]);
detachDecoder(this);
return true;
}
void OggDecoder::update()
@ -512,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);
}
}
@ -839,7 +862,7 @@ 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;
@ -954,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->setForceMono(mindist || maxdist); // HACK: this is set for positional sounds.
decoder->start(sound->isLooping());
}
alSourcePlay(sid);
initial = false;
SANITY_CHECK_OPENAL_CALL();
@ -1429,6 +1457,8 @@ 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);

View file

@ -1158,9 +1158,9 @@ void *SoundManager::playSfx(const PlaySfx &play)
// distance gain attenuation: stereo separation + silence at further away than maxdist
float maxdist = play.maxdist;
if (!maxdist)
maxdist = 1300;
maxdist = 1800;
if(maxdist > 0)
if(maxdist > 0 && play.positional)
channel->set3DMinMaxDistance(maxdist * 0.3, maxdist); // HACK: this works reasonably well
else
channel->set3DMinMaxDistance(0, 0); // no attenuation

View file

@ -106,7 +106,7 @@ struct PlaySfx
{
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) {}
maxdist(0), x(0), y(0), relative(true), positional(false) {}
std::string name;
intptr_t handle;
@ -119,7 +119,8 @@ struct PlaySfx
float maxdist; // distance gain attenuation. if 0: use default value, -1: don't attenuate at all
SoundFadeType fade;
float x, y;
bool relative;
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