Fix playing mono audio sounds with panning

Tested on OpenAL and XAudio backkend on Windows.

#3206
This commit is contained in:
Wojtek Figat
2025-02-11 23:35:08 +01:00
parent dccb43702e
commit 84843f8cbb
2 changed files with 53 additions and 24 deletions

View File

@@ -161,7 +161,10 @@ public:
case 2:
default: // TODO: implement multi-channel support (eg. 5.1, 7.1)
outputMatrix[0] = channels[FrontLeft];
outputMatrix[sourceChannels + 1] = channels[FrontRight];
if (sourceChannels == 1)
outputMatrix[1] = channels[FrontRight];
else
outputMatrix[sourceChannels + 1] = channels[FrontRight];
break;
}
}

View File

@@ -40,11 +40,17 @@
namespace ALC
{
struct SourceData
{
AudioDataInfo Format;
bool Spatial;
};
ALCdevice* Device = nullptr;
ALCcontext* Context = nullptr;
AudioBackend::FeatureFlags Features = AudioBackend::FeatureFlags::None;
CriticalSection Locker;
Dictionary<uint32, AudioDataInfo> SourceIDtoFormat;
Dictionary<uint32, SourceData> SourcesData;
bool IsExtensionSupported(const char* extension)
{
@@ -88,32 +94,32 @@ namespace ALC
alSourcef(sourceID, AL_PITCH, pitch);
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
alSourcei(sourceID, AL_LOOPING, loop);
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial);
alSourcei(sourceID, AL_SOURCE_RELATIVE, AL_TRUE); // Non-spatial sounds use AL_POSITION for panning
alSourcei(sourceID, AL_BUFFER, 0);
#ifdef AL_SOFT_source_spatialize
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE); // Always spatialize, fixes multi-channel played as spatial
#endif
if (spatial)
{
#ifdef AL_SOFT_source_spatialize
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
#endif
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(Vector3::Zero));
#ifdef AL_EXT_STEREO_ANGLES
const float panAngle = pan * PI_HALF;
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
#endif
}
else
{
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
alSource3f(sourceID, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
}
#ifdef AL_EXT_STEREO_ANGLES
const float panAngle = pan * PI_HALF;
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
#endif
}
}
@@ -303,7 +309,9 @@ uint32 AudioBackendOAL::Source_Add(const AudioDataInfo& format, const Vector3& p
// Cache audio data format assigned on source (used in Source_GetCurrentBufferTime)
ALC::Locker.Lock();
ALC::SourceIDtoFormat[sourceID] = format;
auto& data = ALC::SourcesData[sourceID];
data.Format = format;
data.Spatial = spatial;
ALC::Locker.Unlock();
return sourceID;
@@ -317,18 +325,30 @@ void AudioBackendOAL::Source_Remove(uint32 sourceID)
ALC_CHECK_ERROR(alDeleteSources);
ALC::Locker.Lock();
ALC::SourceIDtoFormat.Remove(sourceID);
ALC::SourcesData.Remove(sourceID);
ALC::Locker.Unlock();
}
void AudioBackendOAL::Source_VelocityChanged(uint32 sourceID, const Vector3& velocity)
{
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
ALC::Locker.Lock();
const bool spatial = ALC::SourcesData[sourceID].Spatial;
ALC::Locker.Unlock();
if (spatial)
{
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
}
}
void AudioBackendOAL::Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
{
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
ALC::Locker.Lock();
const bool spatial = ALC::SourcesData[sourceID].Spatial;
ALC::Locker.Unlock();
if (spatial)
{
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
}
}
void AudioBackendOAL::Source_VolumeChanged(uint32 sourceID, float volume)
@@ -343,11 +363,21 @@ void AudioBackendOAL::Source_PitchChanged(uint32 sourceID, float pitch)
void AudioBackendOAL::Source_PanChanged(uint32 sourceID, float pan)
{
ALC::Locker.Lock();
const bool spatial = ALC::SourcesData[sourceID].Spatial;
ALC::Locker.Unlock();
if (spatial)
{
#ifdef AL_EXT_STEREO_ANGLES
const float panAngle = pan * PI_HALF;
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
const float panAngle = pan * PI_HALF;
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
#endif
}
else
{
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
}
}
void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
@@ -357,12 +387,8 @@ void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
void AudioBackendOAL::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
{
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial);
if (spatial)
{
#ifdef AL_SOFT_source_spatialize
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
#endif
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
@@ -411,7 +437,7 @@ float AudioBackendOAL::Source_GetCurrentBufferTime(uint32 sourceID)
alGetSourcef(sourceID, AL_SEC_OFFSET, &time);
#else
ALC::Locker.Lock();
AudioDataInfo clipInfo = ALC::SourceIDtoFormat[sourceID];
AudioDataInfo clipInfo = ALC::SourcesData[sourceID].Format;
ALC::Locker.Unlock();
ALint samplesPlayed;
alGetSourcei(sourceID, AL_SAMPLE_OFFSET, &samplesPlayed);