I spent more time on this issue than should have been necessary because there’s a lot of mixed messages on here and udn about the issue. So to save people time in future I figured I’d detail the solution I arrived at.
Based on various reports on here and udn I initially thought it was pointless to try and use unreal’s native haptics support. I spent time trying to cleanly punch through WinDualShock to get the pad handles and writing xaudio2 code to talk to them. This all turned out to be a waste of time as the Unreal Audio code already exists and though it’s poorly documented the code needed to get it to work turned out to be fairly small.
The first thing you need is a dsp connected to the channel group that your haptics signal is on the code to do this is really simple and there are good examples in the fmod samples & on here -
The other part was what wasted most of my time how to get the audio into the pad, the libscepad defers it to windows xaudio2, there’s a bunch of problems with getting the pad handles.
Only the module that opens the pad has access to the context so trying to call the pad api outside of WinDualShock will fail.
Modifying WinDualShock does work but it’s not clean and will cause merge issues in future so I opted for using Unreal Audio alongside fmod (which should be fine on windows but make sure it’s only enabled on windows and not other platforms).
It took a while to understand the mess that is Unreal Audio but it’s quite simple once you know -
HapticsSource = NewObject<UFloatSoundWaveProcedural>();
HapticsSource->SetSampleRate(48000);
HapticsSource->NumChannels = 2;
HapticsSource->SampleByteSize = 4;
HapticsSource->Duration = INDEFINITELY_LOOPING_DURATION;
HapticsSource->SoundSubmixObject = HapticsEndpoint;
FSoundSubmixSendInfo SubmixSendInfo;
SubmixSendInfo.SendStage = ESubmixSendStage::PreDistanceAttenuation;
SubmixSendInfo.SendLevelControlMethod = ESendLevelControlMethod::Manual;
SubmixSendInfo.SoundSubmix = HapticsEndpoint;
SubmixSendInfo.SendLevel = 1;
HapticsSource->SoundSubmixSends.Add(SubmixSendInfo);
UGameplayStatics::PlaySound2D(this, HapticsSource);
I wrote the UFloatSoundWaveProcedural class but it’s just a regular USoundWaveProcedural with the float type, and from there you can feed in the audio coming out of your dsp with
HapticsSource->QueueAudio
you’ll need some sort of buffering and sync between the dsp on the mixer thread and a queueaudio on the gamethread but beyond that the above code is all that’s needed to get a haptics signal from an fmod channel group to the dualsense (you can also use similar code for the gamepad speaker).