#include "FMODStudioModule.h"
#include "IPixelStreamingStreamer.h"
#include "IPixelStreamingAudioInput.h"
#include "fmod_studio.hpp"
#include "fmod.hpp"
#include "fmod_errors.h"
#include <cstring>
class PixelDSP
{
private:
FMOD::Studio::System* studioSystem;
FMOD::System* system;
FMOD::DSP* dspInstance;
FMOD::Studio::Bank* bank;
FMOD::Studio::EventInstance* event;
TSharedPtr<IPixelStreamingAudioInput> input;
public:
PixelDSP(FMOD::Studio::System* studioSystem, TSharedPtr<IPixelStreamingAudioInput> input);
static FMOD_RESULT DSPCallback(FMOD_DSP_STATE* dsp_state, float* inbuffer, float* outbuffer, unsigned int length, int inchannels, int* outchannels);
void UpdateListenerPosition(FMOD_VECTOR position, FMOD_VECTOR velocity, FMOD_VECTOR forward, FMOD_VECTOR up);
static PixelDSP* GetInstance(FMOD_DSP_STATE* dsp_state);
void LoadBank(const char* relativeBankPath);
void LoadEvent(const char* eventPath);
void PlayEvent();
void UpdateEventLocation(FMOD_VECTOR position, FMOD_VECTOR velocity, FMOD_VECTOR forward, FMOD_VECTOR up);
void UpdateEventParameter(const char* parameterName, float value);
void Update();
};
// Implementation
FMOD_RESULT F_CALLBACK PixelDSP::DSPCallback(FMOD_DSP_STATE* dsp_state, float* inbuffer, float* outbuffer, unsigned int length, int inchannels, int* outchannels)
{
PixelDSP* instance = GetInstance(dsp_state);
if (instance)
{
// Push audio data to pixel stream here
if (instance->input.IsValid())
{
for (int i = 0; i < length * inchannels; i++)
{
if (outbuffer[i] != 0) {
UE_LOG(LogTemp, Warning, TEXT("Audio: %f"), outbuffer[i]);
}
}
instance->input->PushAudio(outbuffer, length * inchannels, inchannels, 48000);
}
}
return FMOD_OK;
}
PixelDSP::PixelDSP(FMOD::Studio::System* studioSystem, TSharedPtr<IPixelStreamingAudioInput> input) : studioSystem(studioSystem), system(nullptr), dspInstance(nullptr), input(input)
{
FMOD_DSP_DESCRIPTION dspDesc;
memset(&dspDesc, 0, sizeof(FMOD_DSP_DESCRIPTION));
strcpy(dspDesc.name, "PixelDSP");
dspDesc.version = 0x00010000;
dspDesc.numinputbuffers = 1;
dspDesc.numoutputbuffers = 1;
dspDesc.read = PixelDSP::DSPCallback;
dspDesc.userdata = this;
studioSystem->initialize(32, FMOD_STUDIO_INIT_LIVEUPDATE, FMOD_INIT_NORMAL, nullptr);
studioSystem->getCoreSystem(&system);
FMOD_RESULT result;
system->createDSP(&dspDesc, &dspInstance);
// Add the DSP to the master channel group to ensure it's processed
FMOD::ChannelGroup* masterGroup = nullptr;
result = system->getMasterChannelGroup(&masterGroup);
if (result != FMOD_OK)
{
UE_LOG(LogTemp, Error, TEXT("Failed to get master channel group: %s"), FMOD_ErrorString(result));
return;
}
result = masterGroup->addDSP(0, dspInstance);
if (result != FMOD_OK)
{
UE_LOG(LogTemp, Error, TEXT("Failed to add DSP to master group: %s"), FMOD_ErrorString(result));
}
// Set the number of 3D listeners
result = system->set3DNumListeners(1);
if (result != FMOD_OK)
{
UE_LOG(LogTemp, Error, TEXT("Failed to set number of listeners: %s"), FMOD_ErrorString(result));
}
UE_LOG(LogTemp, Warning, TEXT("DSP initialized successfully"));
}
PixelDSP* PixelDSP::GetInstance(FMOD_DSP_STATE* dsp_state)
{
FMOD::DSP* dsp;
dsp = static_cast<FMOD::DSP*>(dsp_state->instance);
if (dsp)
{
void *userData;
dsp->getUserData(&userData);
return static_cast<PixelDSP*>(userData);
}
UE_LOG(LogTemp, Error, TEXT("Failed to get DSP instance"));
return nullptr;
}
void PixelDSP::UpdateListenerPosition(FMOD_VECTOR position, FMOD_VECTOR velocity, FMOD_VECTOR forward, FMOD_VECTOR up)
{
system->set3DListenerAttributes(0, &position, &velocity, &forward, &up);
}
void PixelDSP::LoadBank(const char* filename)
{
FMOD_RESULT result = studioSystem->loadBankFile(filename, FMOD_STUDIO_LOAD_BANK_NORMAL, &bank);
if (result != FMOD_OK)
{
FString WideFilename = FString(UTF8_TO_TCHAR(FMOD_ErrorString(result)));
UE_LOG(LogTemp, Error, TEXT("Failed to load bank: %s"), *WideFilename);
}
result = bank->loadSampleData();
if (result != FMOD_OK)
{
FString ErrorString = FString(UTF8_TO_TCHAR(FMOD_ErrorString(result)));
UE_LOG(LogTemp, Error, TEXT("Failed to load sample data: %s"), *ErrorString);
}
}
void PixelDSP::LoadEvent(const char* eventPath)
{
FMOD::Studio::EventDescription* eventDescription;
FMOD_RESULT result = studioSystem->getEvent(eventPath, &eventDescription);
if (result != FMOD_OK)
{
FString WideFilename = FString(UTF8_TO_TCHAR(FMOD_ErrorString(result)));
UE_LOG(LogTemp, Error, TEXT("Failed to get event: %s"), *WideFilename);
}
eventDescription->createInstance(&event);
}
void PixelDSP::PlayEvent()
{
FMOD_RESULT result = event->start();
if (result != FMOD_OK)
{
FString WideFilename = FString(UTF8_TO_TCHAR(FMOD_ErrorString(result)));
UE_LOG(LogTemp, Error, TEXT("Failed to start event: %s"), *WideFilename);
}
}
void PixelDSP::UpdateEventLocation(FMOD_VECTOR position, FMOD_VECTOR velocity, FMOD_VECTOR forward, FMOD_VECTOR up)
{
FMOD_3D_ATTRIBUTES attributes;
attributes.position = position;
attributes.velocity = velocity;
attributes.forward = forward;
attributes.up = up;
event->set3DAttributes(&attributes);
}
void PixelDSP::UpdateEventParameter(const char* parameterName, float value)
{
FMOD_RESULT result = event->setParameterByName(parameterName, value);
if (result != FMOD_OK)
{
FString WideFilename = FString(UTF8_TO_TCHAR(FMOD_ErrorString(result)));
UE_LOG(LogTemp, Error, TEXT("Failed to set parameter: %s"), *WideFilename);
}
}
void PixelDSP::Update()
{
studioSystem->update();
}
Thanks, that seemed to get me some more progress! The part that I struggle with now is it complains about buses and I never get any audio data?