1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-08-09 15:49:52 +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.freq = f;
sfx.name = name; sfx.name = name;
sfx.relative = false; sfx.relative = false;
sfx.positional = true;
sfx.x = position.x; sfx.x = position.x;
sfx.y = position.y; sfx.y = position.y;

View file

@ -2774,6 +2774,7 @@ luaFunc(entity_playSfx)
float fadeOut = lua_tonumber(L, 6); float fadeOut = lua_tonumber(L, 6);
sfx.maxdist = lua_tonumber(L, 7); sfx.maxdist = lua_tonumber(L, 7);
sfx.relative = false; sfx.relative = false;
sfx.positional = true;
h = core->sound->playSfx(sfx); h = core->sound->playSfx(sfx);
if (fadeOut != 0) if (fadeOut != 0)
@ -5944,8 +5945,12 @@ luaFunc(playSfx)
if (sfx.vol <= 0) if (sfx.vol <= 0)
sfx.vol = 1; sfx.vol = 1;
sfx.loops = lua_tointeger(L, 4); sfx.loops = lua_tointeger(L, 4);
if(lua_isnumber(L, 6) && lua_isnumber(L, 7))
{
sfx.x = lua_tonumber(L, 5); sfx.x = lua_tonumber(L, 5);
sfx.y = lua_tonumber(L, 6); sfx.y = lua_tonumber(L, 6);
sfx.positional = true;
}
sfx.maxdist = lua_tonumber(L, 7); sfx.maxdist = lua_tonumber(L, 7);
if(lua_isnoneornil(L, 8)) if(lua_isnoneornil(L, 8))
sfx.relative = (sfx.x == 0 && sfx.y == 0); sfx.relative = (sfx.x == 0 && sfx.y == 0);

View file

@ -69,8 +69,12 @@ public:
~OggDecoder(); ~OggDecoder();
// Start playing on the given channel, with optional looping. // Prepare playing on the given channel.
bool start(ALuint source, bool loop); 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 // Decode audio into any free buffers. Must be called periodically
// on systems without threads; may be called without harm on systems // 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->source = source;
this->loop = loop;
if (fp) { if (fp) {
if (ov_open_callbacks(fp, &vf, NULL, 0, local_OV_CALLBACKS_NOCLOSE) != 0) 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 false;
} }
return true;
}
void OggDecoder::start(bool loop)
{
this->loop = loop;
playing = true; playing = true;
eof = false; eof = false;
samples_done = 0; samples_done = 0;
@ -394,8 +404,6 @@ bool OggDecoder::start(ALuint source, bool loop)
queue(buffers[i]); queue(buffers[i]);
detachDecoder(this); detachDecoder(this);
return true;
} }
void OggDecoder::update() void OggDecoder::update()
@ -512,7 +520,22 @@ void OggDecoder::queue(ALuint buffer)
if (pcm_size > 0) 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); alSourceQueueBuffers(source, 1, &buffer);
} }
} }
@ -839,7 +862,7 @@ bool OpenALChannel::start(OpenALSound *sound)
decoder = new OggDecoder(sound->getFile()); decoder = new OggDecoder(sound->getFile());
else else
decoder = new OggDecoder(sound->getData(), sound->getSize()); decoder = new OggDecoder(sound->getData(), sound->getSize());
if (!decoder->start(sid, sound->isLooping())) if (!decoder->preStart(sid))
{ {
delete decoder; delete decoder;
decoder = NULL; 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)))) 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); alSourcePlay(sid);
initial = false; initial = false;
SANITY_CHECK_OPENAL_CALL(); SANITY_CHECK_OPENAL_CALL();
@ -1429,6 +1457,8 @@ FMOD_RESULT OpenALSystem::createSound(const char *name_or_data, const FMOD_MODE
alGenBuffers(1, &bid); alGenBuffers(1, &bid);
if (bid != 0) 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); alBufferData(bid, format, data, size, freq);
*sound = (Sound *) new OpenALSound(bid, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL))); *sound = (Sound *) new OpenALSound(bid, (((mode & FMOD_LOOP_OFF) == 0) && (mode & FMOD_LOOP_NORMAL)));
((OpenALSound*)*sound)->setNumChannels(format == AL_FORMAT_STEREO16 ? 2 : 1); ((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 // distance gain attenuation: stereo separation + silence at further away than maxdist
float maxdist = play.maxdist; float maxdist = play.maxdist;
if (!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 channel->set3DMinMaxDistance(maxdist * 0.3, maxdist); // HACK: this works reasonably well
else else
channel->set3DMinMaxDistance(0, 0); // no attenuation 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), PlaySfx() : priority(0.5), handle(0), vol(1), fade(SFT_NONE),
time(0), freq(1), loops(0), channel(BBGE_AUDIO_NOCHANNEL), 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; std::string name;
intptr_t handle; 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 float maxdist; // distance gain attenuation. if 0: use default value, -1: don't attenuate at all
SoundFadeType fade; SoundFadeType fade;
float x, y; 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 class SoundHolder; // defined below