Fix various issues with OpenAL buffers playback (do proper bit convertion)
This commit is contained in:
@@ -454,14 +454,12 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||
}
|
||||
break;
|
||||
case AudioFormat::Raw:
|
||||
{
|
||||
data = Span<byte>(chunk->Get(), chunk->Size());
|
||||
}
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
info.NumSamples = data.Length() / bytesPerSample;
|
||||
info.NumSamples = Math::AlignDown(data.Length() / bytesPerSample, info.NumChannels * bytesPerSample);
|
||||
|
||||
// Convert to Mono if used as 3D source and backend doesn't support it
|
||||
if (Is3D() && info.NumChannels > 1 && EnumHasNoneFlags(AudioBackend::Features(), AudioBackend::FeatureFlags::SpatialMultiChannel))
|
||||
|
||||
@@ -228,11 +228,9 @@ namespace ALC
|
||||
ALenum GetOpenALBufferFormat(uint32 numChannels, uint32 bitDepth)
|
||||
{
|
||||
// TODO: cache enum values in Init()??
|
||||
|
||||
switch (bitDepth)
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
switch (numChannels)
|
||||
{
|
||||
case 1:
|
||||
@@ -247,13 +245,8 @@ ALenum GetOpenALBufferFormat(uint32 numChannels, uint32 bitDepth)
|
||||
return alGetEnumValue("AL_FORMAT_61CHN8");
|
||||
case 8:
|
||||
return alGetEnumValue("AL_FORMAT_71CHN8");
|
||||
default:
|
||||
CRASH;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
switch (numChannels)
|
||||
{
|
||||
case 1:
|
||||
@@ -268,19 +261,22 @@ ALenum GetOpenALBufferFormat(uint32 numChannels, uint32 bitDepth)
|
||||
return alGetEnumValue("AL_FORMAT_61CHN16");
|
||||
case 8:
|
||||
return alGetEnumValue("AL_FORMAT_71CHN16");
|
||||
default:
|
||||
CRASH;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
switch (numChannels)
|
||||
{
|
||||
case 1:
|
||||
#ifdef AL_FORMAT_MONO_FLOAT32
|
||||
return AL_FORMAT_MONO_FLOAT32;
|
||||
#else
|
||||
return alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
|
||||
#endif
|
||||
case 2:
|
||||
#ifdef AL_FORMAT_STEREO_FLOAT32
|
||||
return AL_FORMAT_STEREO_FLOAT32;
|
||||
#else
|
||||
return alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
|
||||
#endif
|
||||
case 4:
|
||||
return alGetEnumValue("AL_FORMAT_QUAD32");
|
||||
case 6:
|
||||
@@ -289,15 +285,9 @@ ALenum GetOpenALBufferFormat(uint32 numChannels, uint32 bitDepth)
|
||||
return alGetEnumValue("AL_FORMAT_61CHN32");
|
||||
case 8:
|
||||
return alGetEnumValue("AL_FORMAT_71CHN32");
|
||||
default:
|
||||
CRASH;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
default:
|
||||
CRASH;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AudioBackendOAL::Listener_OnAdd(AudioListener* listener)
|
||||
@@ -607,7 +597,8 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
// TODO: maybe use temporary buffers per thread to reduce dynamic allocations when uploading data to OpenAL?
|
||||
// Pick the format for the audio data (it might not be supported natively)
|
||||
ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
|
||||
|
||||
// Mono or stereo
|
||||
if (info.NumChannels <= 2)
|
||||
@@ -618,28 +609,23 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
{
|
||||
const uint32 bufferSize = info.NumSamples * sizeof(float);
|
||||
float* sampleBufferFloat = (float*)Allocator::Allocate(bufferSize);
|
||||
|
||||
AudioTool::ConvertToFloat(samples, info.BitDepth, sampleBufferFloat, info.NumSamples);
|
||||
|
||||
const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 32);
|
||||
alBufferData(bufferId, format, sampleBufferFloat, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
|
||||
Allocator::Free(sampleBufferFloat);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warning, "OpenAL doesn't support bit depth larger than 16. Your audio data will be truncated.");
|
||||
|
||||
const uint32 bufferSize = info.NumSamples * 2;
|
||||
byte* sampleBuffer16 = (byte*)Allocator::Allocate(bufferSize);
|
||||
|
||||
AudioTool::ConvertBitDepth(samples, info.BitDepth, sampleBuffer16, 16, info.NumSamples);
|
||||
|
||||
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16);
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 16);
|
||||
alBufferData(bufferId, format, sampleBuffer16, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
|
||||
Allocator::Free(sampleBuffer16);
|
||||
}
|
||||
}
|
||||
@@ -648,19 +634,15 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
// OpenAL expects unsigned 8-bit data, but engine stores it as signed, so convert
|
||||
const uint32 bufferSize = info.NumSamples * (info.BitDepth / 8);
|
||||
byte* sampleBuffer = (byte*)Allocator::Allocate(bufferSize);
|
||||
|
||||
for (uint32 i = 0; i < info.NumSamples; i++)
|
||||
sampleBuffer[i] = ((int8*)samples)[i] + 128;
|
||||
|
||||
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16);
|
||||
alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
|
||||
Allocator::Free(sampleBuffer);
|
||||
}
|
||||
else
|
||||
else if (format)
|
||||
{
|
||||
const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
|
||||
alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
}
|
||||
@@ -675,10 +657,9 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
{
|
||||
const uint32 bufferSize = info.NumChannels * sizeof(int32);
|
||||
byte* sampleBuffer32 = (byte*)Allocator::Allocate(bufferSize);
|
||||
|
||||
AudioTool::ConvertBitDepth(samples, info.BitDepth, sampleBuffer32, 32, info.NumSamples);
|
||||
|
||||
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 32);
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 32);
|
||||
alBufferData(bufferId, format, sampleBuffer32, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
|
||||
@@ -693,19 +674,23 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
|
||||
for (uint32 i = 0; i < info.NumSamples; i++)
|
||||
sampleBuffer[i] = ((int8*)samples)[i] + 128;
|
||||
|
||||
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16);
|
||||
format = GetOpenALBufferFormat(info.NumChannels, 16);
|
||||
alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
|
||||
Allocator::Free(sampleBuffer);
|
||||
}
|
||||
else
|
||||
else if (format)
|
||||
{
|
||||
const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
|
||||
alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
|
||||
ALC_CHECK_ERROR(alBufferData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!format)
|
||||
{
|
||||
LOG(Error, "Not suppported audio data format for OpenAL device: BitDepth={}, NumChannels={}", info.BitDepth, info.NumChannels);
|
||||
}
|
||||
}
|
||||
|
||||
const Char* AudioBackendOAL::Base_Name()
|
||||
|
||||
@@ -231,8 +231,7 @@ void AudioTool::ConvertToFloat(const byte* input, uint32 inBitDepth, float* outp
|
||||
for (uint32 i = 0; i < numSamples; i++)
|
||||
{
|
||||
const int8 sample = *(int8*)input;
|
||||
output[i] = sample / 127.0f;
|
||||
|
||||
output[i] = sample * (1.0f / 127.0f);
|
||||
input++;
|
||||
}
|
||||
}
|
||||
@@ -241,8 +240,7 @@ void AudioTool::ConvertToFloat(const byte* input, uint32 inBitDepth, float* outp
|
||||
for (uint32 i = 0; i < numSamples; i++)
|
||||
{
|
||||
const int16 sample = *(int16*)input;
|
||||
output[i] = sample / 32767.0f;
|
||||
|
||||
output[i] = sample * (1.0f / 32767.0f);
|
||||
input += 2;
|
||||
}
|
||||
}
|
||||
@@ -251,8 +249,7 @@ void AudioTool::ConvertToFloat(const byte* input, uint32 inBitDepth, float* outp
|
||||
for (uint32 i = 0; i < numSamples; i++)
|
||||
{
|
||||
const int32 sample = Convert24To32Bits(input);
|
||||
output[i] = sample / 2147483647.0f;
|
||||
|
||||
output[i] = sample * (1.0f / 2147483647.0f);
|
||||
input += 3;
|
||||
}
|
||||
}
|
||||
@@ -261,8 +258,7 @@ void AudioTool::ConvertToFloat(const byte* input, uint32 inBitDepth, float* outp
|
||||
for (uint32 i = 0; i < numSamples; i++)
|
||||
{
|
||||
const int32 sample = *(int32*)input;
|
||||
output[i] = sample / 2147483647.0f;
|
||||
|
||||
output[i] = sample * (1.0f / 2147483647.0f);
|
||||
input += 4;
|
||||
}
|
||||
}
|
||||
@@ -278,7 +274,6 @@ void AudioTool::ConvertFromFloat(const float* input, int32* output, uint32 numSa
|
||||
{
|
||||
const float sample = *(float*)input;
|
||||
output[i] = static_cast<int32>(sample * 2147483647.0f);
|
||||
|
||||
input++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user