-
Notifications
You must be signed in to change notification settings - Fork 220
Seg Fault when trying to use Reflection Sim with IPL_REFLECTIONEFFECTTYPE_CONVOLUTION #546
Description
System Information
Please provide the following information about your system:
- Steam Audio version: 4.8.1
- Operating System and version: Linux Mint 22 Cinnamon Linux Kernel: 6.14.0-29-generic
- (Optional) CPU architecture (e.g. x86-64, armv7): AMD Ryzen 9 7950X 16-Core Processor × 16
Issue Description
When trying to use iplReflectionEffectApply() when reflectionEffectParams.ir is not null (reflections simulation has been ran) I keep running into a segmentation fault when i = 1 for this code:
for (auto i = 0; i < params.numChannels; ++i) { for (auto j = 0; j < numBlocks; ++j) { auto index = static_cast<int>((mDryBlockIndex + j) % mFFTDryBlocks.size(0)); ArrayMath::multiplyAccumulate(static_cast<int>(mFFTDryBlocks.size(1)), mFFTDryBlocks[index], (*mPrevFFTIR)[i][j], mFFTWet[i]); } }
2026-03-29_17-18-05.mp4
I suspect it has something to do with my channels? But its strange that IPL_REFLECTIONEFFECTTYPE_PARAMETRIC works (sort of... I get audio artifacts when using parametric)
Steps To Reproduce
This is how I have set up my configuration:
- Creating the Simulation
ReflectionsSimulator::ReflectionsSimulator(const std::shared_ptr<SteamAudioContext>& steamAudioContext)
{
IPLSimulationSettings simulationSettings{};
simulationSettings.flags = IPL_SIMULATIONFLAGS_REFLECTIONS; // this enables reflection simulation
simulationSettings.sceneType = IPL_SCENETYPE_DEFAULT;
simulationSettings.reflectionType = IPL_REFLECTIONEFFECTTYPE_CONVOLUTION;
simulationSettings.maxNumRays = 4096;
simulationSettings.numDiffuseSamples = 32;
simulationSettings.maxDuration = 2.0f;
simulationSettings.maxOrder = 1;
simulationSettings.maxNumSources = 100;
const auto threads = static_cast<int>(std::thread::hardware_concurrency()) - 1;
simulationSettings.numThreads = threads;
auto [samplingRate, frameSize] = steamAudioContext->GetAudioSettings();
simulationSettings.samplingRate = samplingRate;
simulationSettings.frameSize = frameSize;
if (const IPLerror errorCode = iplSimulatorCreate(steamAudioContext->GetContext(),
&simulationSettings,
&simulator);
errorCode != IPL_STATUS_SUCCESS)
{
throw std::runtime_error("Failed to Create IPL Reflections Simulator.");
}
}
- This is how I am creating my Sources
void SimulatorOrchestrator::CreateIplReflectionSimSource(IPLSource& iplReflectionsSimSource) const
{
IPLSourceSettings sourceSettings{};
sourceSettings.flags = IPL_SIMULATIONFLAGS_REFLECTIONS;
if (const IPLerror errorCode = iplSourceCreate(reflectionsSimulator->GetSimulator(),
&sourceSettings,
&iplReflectionsSimSource);
errorCode != IPL_STATUS_SUCCESS)
{
throw std::runtime_error("Failed to create iplReflectionsSimSource.");
}
}
where later they are added to to Reflections simulator
void ReflectionsSimulator::AddSource(const IPLSource iplSource) const
{
iplSourceAdd(iplSource, simulator);
iplSimulatorCommit(simulator);
}
- This is how I am creating my IPLReflectionEffects
// Create IPLReflectionEffect
IPLReflectionEffectSettings reflectionEffectSettings = {};
reflectionEffectSettings.type =IPL_REFLECTIONEFFECTTYPE_CONVOLUTION;
reflectionEffectSettings.irSize = 2 * SoundConstants::SAMPLE_RATE;
// 88200; // 2.0f (IR duration) * 44100 (sampling rate)
reflectionEffectSettings.numChannels = 4; // 1st order Ambisonics !!!
if (const IPLerror errorCode = iplReflectionEffectCreate(inSteamAudioContext->GetContext(),
&audioSettings,
&reflectionEffectSettings,
&reflectionEffect);
errorCode != IPL_STATUS_SUCCESS)
{
throw std::runtime_error("Failed to Create IPL ReflectionEffect.");
}
if (const IPLerror errorCode = iplAudioBufferAllocate(inSteamAudioContext->GetContext(),
4,
SoundConstants::FRAME_SIZE,
&outReflectionBuffer);
errorCode != IPL_STATUS_SUCCESS)
{
throw std::runtime_error("Failed to Allocate Buffer for outReflectionBuffer.");
}
// Create IPLAmbisonicsDecodeEffect
IPLAmbisonicsDecodeEffectSettings ambisonicsDecodeEffectSettings{};
/*Order 0 has 1 channel, order 1 has 4 channels, order 2 has 9 channels, and so on*/
ambisonicsDecodeEffectSettings.maxOrder = 1; // 1st order Ambisonics (4 channels)
ambisonicsDecodeEffectSettings.hrtf = hrtf;
ambisonicsDecodeEffectSettings.speakerLayout.type = IPL_SPEAKERLAYOUTTYPE_STEREO; //?
if (const IPLerror errorCode = iplAmbisonicsDecodeEffectCreate(inSteamAudioContext->GetContext(),
&audioSettings,
&ambisonicsDecodeEffectSettings,
&ambisonicsDecodeEffect);
errorCode != IPL_STATUS_SUCCESS)
{
throw std::runtime_error("Failed to Create IPL ambisonicsDecodeEffect.");
}
if (const IPLerror errorCode = iplAudioBufferAllocate(inSteamAudioContext->GetContext(),
2,
SoundConstants::FRAME_SIZE,
&outAmbisonicsDecodeBuffer);
errorCode != IPL_STATUS_SUCCESS)
{
throw std::runtime_error("Failed to Allocate Buffer for outAmbisonicsDecodeBuffer.");
}
- this is how i am updating my sources (ignore the flags they are always true in this scenario), this is run on the main game thread
void SteamSpatialisedAudio::UpdateSource(
const Math::Vector3D sourceForward,
const Math::Vector3D sourceUp,
Math::Point3D sourcePosition,
SoundObject3DSettings::InputSimulationSettings inputSimulationSettings)
{
const auto sourceRight = Math::Normalize(Math::Cross(sourceForward, sourceUp));
IPLCoordinateSpace3 sourceCoordinates;
sourceCoordinates.right = SteamAudioContext::ToIplVector(sourceRight);
sourceCoordinates.ahead = SteamAudioContext::ToIplVector(sourceForward);
sourceCoordinates.up = SteamAudioContext::ToIplVector(sourceUp);
sourceCoordinates.origin = SteamAudioContext::ToIplVector(sourcePosition);
IPLSimulationInputs inputs{};
inputs.source = sourceCoordinates;
int iplSimulationFlags = 0;
if (inputSimulationSettings.HasFlag(SoundEngineSettings::SimulationFlags::DIRECT))
{
inputs.directFlags = GetIplDirectSimulationFlags(inputSimulationSettings.inputDirectSimulationSettings);
}
if (inputSimulationSettings.HasFlag(SoundEngineSettings::SimulationFlags::REFLECTIONS))
{
iplSimulationFlags |= IPL_SIMULATIONFLAGS_REFLECTIONS;
}
if (inputSimulationSettings.HasFlag(SoundEngineSettings::SimulationFlags::PATHING))
{
iplSimulationFlags |= IPL_SIMULATIONFLAGS_PATHING;
}
inputs.flags = *reinterpret_cast<IPLSimulationFlags*>(&iplSimulationFlags);;
inputs.occlusionType = inputSimulationSettings.occlusionType ==
SoundObject3DSettings::InputOcclusionType::RAYCAST
? IPL_OCCLUSIONTYPE_RAYCAST
: IPL_OCCLUSIONTYPE_VOLUMETRIC;
inputs.numOcclusionSamples = inputSimulationSettings.numberOfOcclusionSamples;
inputs.numTransmissionRays = inputSimulationSettings.numberOfTransmissionRays;
if (inputSimulationSettings.HasFlag(SoundEngineSettings::SimulationFlags::DIRECT))
{
iplSourceSetInputs(iplDirectSimSource, IPL_SIMULATIONFLAGS_DIRECT, &inputs);
}
if (inputSimulationSettings.HasFlag(SoundEngineSettings::SimulationFlags::REFLECTIONS))
{
inputs.reverbScale[0] = 1.0f;
inputs.reverbScale[1] = 1.0f;
inputs.reverbScale[2] = 1.0f;
iplSourceSetInputs(iplReflectionsSimSource, IPL_SIMULATIONFLAGS_REFLECTIONS, &inputs);
}
}
- I am also running the reflections simulator on a separate thread
void ReflectionsSimulator::Run()
{
if (!reflectionsSimulatorIsRunning.exchange(true))
{
// runs on background thread
Core::JobSystem::Execute([this]
{
iplSimulatorRunReflections(simulator);
reflectionsSimulatorIsRunning.store(false);
});
}
}
- I retrieve the Outputs on the main game thread
void SteamSpatialisedAudio::RetrieveSimulationOutput(
const SoundObject3DSettings::OutputSimulationSettings outputSimulationSettings
)
{
IPLSimulationOutputs outputs{};
if (outputSimulationSettings.HasFlag(SoundEngineSettings::SimulationFlags::DIRECT))
{
const IPLDirectEffectFlags iplDirectFlags = GetIplDirectEffectFlags(
outputSimulationSettings.outputDirectSimulationSettings);
iplSourceGetOutputs(iplDirectSimSource, IPL_SIMULATIONFLAGS_DIRECT, &outputs);
directEffectParams = outputs.direct;
directEffectParams.flags = iplDirectFlags;
}
useReflections = outputSimulationSettings.HasFlag(SoundEngineSettings::SimulationFlags::REFLECTIONS);
if (useReflections)
{
iplSourceGetOutputs(iplReflectionsSimSource, IPL_SIMULATIONFLAGS_REFLECTIONS, &outputs);
reflectionEffectParams = outputs.reflections;
}
}
- And then finally this is my audio thread that tries to apply the effects, I've had no issues with DirectEffect and Binaural only issue has come when I've tried to add Reflections
const auto inFrame = const_cast<float*>(&inputData[currentFrameIndex * SoundConstants::FRAME_SIZE]);
float* inData[] = {inFrame};
IPLAudioBuffer inBuffer{1, SoundConstants::FRAME_SIZE, inData};
// Main Loop
//The main processing loop applies 3D audio effects to the input audio one frame at a time,
//accumulating the results in an output buffer
iplDirectEffectApply(directEffect, &directEffectParams, &inBuffer, &outDirectBuffer);
binauralEffectParams.direction = direction;
iplBinauralEffectApply(binauralEffect, &binauralEffectParams, &outDirectBuffer, &outBinauralBuffer);
if (reflectionEffectParams.ir != NULL)
{
LOG_DEBUG("Gonna crash");
}
iplReflectionEffectApply(reflectionEffect, &reflectionEffectParams, &inBuffer, &outReflectionBuffer, nullptr);
ambisonicsDecodeEffectParams.orientation = orientation;
ambisonicsDecodeEffectParams.order = 1;
ambisonicsDecodeEffectParams.hrtf = hrtf;
ambisonicsDecodeEffectParams.binaural = IPL_TRUE;
iplAmbisonicsDecodeEffectApply(ambisonicsDecodeEffect, &ambisonicsDecodeEffectParams, &outReflectionBuffer,
&outAmbisonicsDecodeBuffer);
std::vector<float> outputAudioFrame(2 * SoundConstants::FRAME_SIZE);
//iplAudioBufferInterleave(steamContext->GetContext(), &outBinauralBuffer, outputAudioFrame.data());
//iplAudioBufferInterleave(steamContext->GetContext(), &outAmbisonicsDecodeBuffer, outputAudioFrame.data());
//At this point, outputAudioFrame contains a single frame of interleaved stereo audio
for (int i = 0; i < SoundConstants::FRAME_SIZE; ++i)
{
for (int ch = 0; ch < 2; ++ch)
{
float sampleBinaural = outBinauralBuffer.data[ch][i];
float sampleAmbisonics = outAmbisonicsDecodeBuffer.data[ch][i];
// Simple linear mix
// float mixedSample = sampleBinaural + sampleAmbisonics;
float mixedSample = sampleAmbisonics;
// Clamp to [-1, 1] to be safe
outputAudioFrame[i * 2 + ch] = std::clamp(mixedSample, -1.0f, 1.0f);
}
}
reflectionEffectParams.ir is null up until the point the reflections simulator has run, once the first run is done thats when the seg fault is gonna happen.
For completeness this is what it sounds like when I use reflectionType = IPL_REFLECTIONEFFECTTYPE_PARAMETRIC
(my sound comes from the point lights just for reference)