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: case 2:
default: // TODO: implement multi-channel support (eg. 5.1, 7.1) default: // TODO: implement multi-channel support (eg. 5.1, 7.1)
outputMatrix[0] = channels[FrontLeft]; outputMatrix[0] = channels[FrontLeft];
outputMatrix[sourceChannels + 1] = channels[FrontRight]; if (sourceChannels == 1)
outputMatrix[1] = channels[FrontRight];
else
outputMatrix[sourceChannels + 1] = channels[FrontRight];
break; break;
} }
} }

View File

@@ -40,11 +40,17 @@
namespace ALC namespace ALC
{ {
struct SourceData
{
AudioDataInfo Format;
bool Spatial;
};
ALCdevice* Device = nullptr; ALCdevice* Device = nullptr;
ALCcontext* Context = nullptr; ALCcontext* Context = nullptr;
AudioBackend::FeatureFlags Features = AudioBackend::FeatureFlags::None; AudioBackend::FeatureFlags Features = AudioBackend::FeatureFlags::None;
CriticalSection Locker; CriticalSection Locker;
Dictionary<uint32, AudioDataInfo> SourceIDtoFormat; Dictionary<uint32, SourceData> SourcesData;
bool IsExtensionSupported(const char* extension) bool IsExtensionSupported(const char* extension)
{ {
@@ -88,32 +94,32 @@ namespace ALC
alSourcef(sourceID, AL_PITCH, pitch); alSourcef(sourceID, AL_PITCH, pitch);
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f); alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
alSourcei(sourceID, AL_LOOPING, loop); 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); 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) 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_ROLLOFF_FACTOR, attenuation);
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler); alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance)); alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position)); alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(Vector3::Zero)); 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 else
{ {
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f); alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f); alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.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); 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) // Cache audio data format assigned on source (used in Source_GetCurrentBufferTime)
ALC::Locker.Lock(); ALC::Locker.Lock();
ALC::SourceIDtoFormat[sourceID] = format; auto& data = ALC::SourcesData[sourceID];
data.Format = format;
data.Spatial = spatial;
ALC::Locker.Unlock(); ALC::Locker.Unlock();
return sourceID; return sourceID;
@@ -317,18 +325,30 @@ void AudioBackendOAL::Source_Remove(uint32 sourceID)
ALC_CHECK_ERROR(alDeleteSources); ALC_CHECK_ERROR(alDeleteSources);
ALC::Locker.Lock(); ALC::Locker.Lock();
ALC::SourceIDtoFormat.Remove(sourceID); ALC::SourcesData.Remove(sourceID);
ALC::Locker.Unlock(); ALC::Locker.Unlock();
} }
void AudioBackendOAL::Source_VelocityChanged(uint32 sourceID, const Vector3& velocity) 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) 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) 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) 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 #ifdef AL_EXT_STEREO_ANGLES
const float panAngle = pan * PI_HALF; 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 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); alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
#endif #endif
}
else
{
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
}
} }
void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop) 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) void AudioBackendOAL::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
{ {
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial);
if (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_ROLLOFF_FACTOR, attenuation);
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler); alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance)); 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); alGetSourcef(sourceID, AL_SEC_OFFSET, &time);
#else #else
ALC::Locker.Lock(); ALC::Locker.Lock();
AudioDataInfo clipInfo = ALC::SourceIDtoFormat[sourceID]; AudioDataInfo clipInfo = ALC::SourcesData[sourceID].Format;
ALC::Locker.Unlock(); ALC::Locker.Unlock();
ALint samplesPlayed; ALint samplesPlayed;
alGetSourcei(sourceID, AL_SAMPLE_OFFSET, &samplesPlayed); alGetSourcei(sourceID, AL_SAMPLE_OFFSET, &samplesPlayed);