How to build early reflection?

Transceiver only has 32 channels, so it seems like transceiver won’t be enough. What would be a good alternative way to position the reflected signals?

Hi,

Could you elaborate on what you are trying to achieve?

@Connor_FMOD Something similar to wwise reflect, say

  1. Calculate some reflection points for active events.
  2. Create “virtual emitters” at the reflection points that plays the same signal as the source event.
  3. Apply the delay, attenuation change, filters to the virtual emitters. (Either defined by curve or calculate based on physics )

I’m open to other ways to achieve similar effect though!

Also interested in learning this

Hi,

Unfortunately, FMOD does not natively support reflections. However, the Resonance Audio (Fundamental Concepts - Early Reflections and Reverb) plugin does have early reflections which we do support (FMOD Studio | Advanced Topics - Resonance Audio) and is included with FMOD Studio.
image
I would suggest giving the resonance audio documentation a read to see if it supports the functionality you are looking for.

What engine are you looking at developing on?

Hope this helps!

Thanks for the pointers! We are developing using Unreal. I’m completely open to write our own DSP, or calculate the reflection points ourselves.

The part I’m not sure how to do is duplicating and repositioning signals(beyond the 32 channels limit). Is there any way you would recommend doing this? If the Resonance guys can do it, feel like there should be a way somehow, unless they have access to proprietary FMOD features?

Thank you!

1 Like

The Resonance Audio simulates reflections using Raycasts to all the room surfaces (or simply in 6 directions). Then for each surface found use the distance to the collision to calculate the delay which will be added to a buffer. Playing the sound back panned towards the collision with the delay and finally adding a Low pass to all the reflected audio.

They avoid the need to create new sounds for each reflection by locating the collision point of the echo and panning the original sound toward the collision. This will avoid the need for greater than 32 channels and just require creating your own DSP to create the delay buffer and replaying the sound panned. Hope this helps!

Values can be passed to the DSP using User Data, (FMOD API | Glossary - User Data) DSP::setUserData(). Hope this helps, if you have any more questions please do not hesitate to ask.

1 Like

Connor you are the champion, gonna do some experiment this weekend!

1 Like

I’m doing some quick’n dirty prototyping ine UE, got some sounds playing on the fly following the user_created_sound example. I was testing if I can pipe those sounds to an FMOD panner, but for some reason, I don’t hear any panning changes:

Code below:

// Called when the game starts or when spawned
void AMultiSoundActor::BeginPlay()
{
	Super::BeginPlay();
...
	FMOD_CREATESOUNDEXINFO  exinfo;

	memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
	exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);  /* Required. */
	exinfo.numchannels = 2;                               /* Number of channels in the sound. */
	exinfo.defaultfrequency = 44100;                           /* Default playback rate of sound. */
	exinfo.decodebuffersize = 44100;                           /* Chunk size of stream update in samples. This will be the amount of data passed to the user callback. */
	exinfo.length = exinfo.defaultfrequency * exinfo.numchannels * sizeof(signed short) * 5; /* Length of PCM data in bytes of whole song (for Sound::getLength) */
	exinfo.format = FMOD_SOUND_FORMAT_PCM16;         /* Data format of sound. */
	exinfo.pcmreadcallback = pcmreadcallback;                 /* User callback for reading. */

	verifyfmod(system->createSound(0, mode, &exinfo, &sound));

	verifyfmod(system->playSound(sound, 0, 0, &channel));

	system->createDSPByType(FMOD_DSP_TYPE_PAN, &panner);
	channel->addDSP(FMOD_CHANNELCONTROL_DSP_HEAD, panner);
	

}

// Called every frame
void AMultiSoundActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	FMOD_VECTOR fmodVec = { {0} };
	FMOD_VECTOR fmodVel = { {0} };

	FVector soundLoc = this->GetActorLocation();
	FMODUtils::Assign(fmodVec, soundLoc);
	
	channel->set3DAttributes(&fmodVec, &fmodVel);

	DrawDebugSphere(GetWorld(), soundLoc, 100, 32, FColor::Blue, false, 0.0f, 0.0f, 2.0f);

	FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI multi = {};

	{
		//Calculate positioning values
		FMOD_3D_ATTRIBUTES absolute = {};
		FVector soundFwd = this->GetActorForwardVector();
		FMODUtils::Assign(absolute.forward, soundFwd);

		absolute.position = { 0,1,0 };
		FMODUtils::Assign(absolute.position, soundLoc);

		FVector soundUp = this->GetActorUpVector();

		absolute.up = { 0,1,0 };
		FMODUtils::Assign(absolute.position, soundUp);

		absolute.velocity = { 0,0,0 };

		FMOD_3D_ATTRIBUTES relative = {};

		APlayerCameraManager* camManager = GetWorld()->GetFirstPlayerController()->PlayerCameraManager;
		FVector camLoc = camManager->GetCameraLocation();
		FVector camFwd = camManager->GetCameraRotation().Vector();
		FVector camUp = camManager->GetActorUpVector();
		FTransform xCam = camManager->GetActorTransform();

		FVector rLoc = xCam.TransformPosition(soundLoc);
		FVector rFwd = xCam.TransformPosition(soundFwd);
		FVector rUp = xCam.TransformPosition(soundUp);

		FMODUtils::Assign(relative.forward, rFwd);
		FMODUtils::Assign(relative.position, rLoc);
		FMODUtils::Assign(relative.up, rUp);

		//Assign values
		multi.numlisteners = 1;
		multi.weight[0] = 1;
		multi.absolute = absolute;
		multi.relative[0] = relative;
	}
	panner->setParameterInt(FMOD_DSP_PAN_3D_ROLLOFF, FMOD_DSP_PAN_3D_ROLLOFF_INVERSE);
	panner->setParameterData(FMOD_DSP_PAN_3D_POSITION, (void*)(&multi), sizeof(multi));
	panner->setParameterFloat(FMOD_DSP_PAN_3D_MIN_DISTANCE, 20.0f);
	panner->setParameterFloat(FMOD_DSP_PAN_3D_MAX_DISTANCE, 200.0f);
	panner->setMeteringEnabled(true, true);
	panner->setChannelFormat(0, FMOD_MAX_CHANNEL_WIDTH, FMOD_SPEAKERMODE_STEREO);
	channel->set3DLevel(1.0f);
	sound->set3DMinMaxDistance(20.0f, 200.0f);
	
}
1 Like

Bump see if I can get some help debugging the code above :eyes:

I’m not sure why generating sound buffer-> pipe into a panner approach wouldn’t work, feel like there’s a bug in the code.

Hi,

You were super close, try changing these values:

absolute.position = { 0,1,0 };
// to 
absolute.position = { 50,50,0 };

Hope that helps!

1 Like


Hmmm still doesn’t seem to be attenuating the signal, profiler graph + short video are attached.

*Full code of the file: *
(I did switch FMODUtils::Assign to FMODUtils::ConvertWorldVector to get the Y-axis and Z-axis conversion between FMOD and UE, but doesn’t seem to affect the result)

// Fill out your copyright notice in the Description page of Project Settings.


#include "MultiSoundActor.h"
#include "FMODUtils.h"
#include "DrawDebugHelpers.h"	

// Sets default values
AMultiSoundActor::AMultiSoundActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

FMOD_RESULT F_CALLBACK pcmreadcallback(FMOD_SOUND* /*sound*/, void* data, unsigned int datalen)
{
	static float  t1 = 0, t2 = 0;        // time
	static float  v1 = 0, v2 = 0;        // velocity
	signed short* stereo16bitbuffer = (signed short*)data;

	for (unsigned int count = 0; count < (datalen >> 2); count++)     // >>2 = 16bit stereo (4 bytes per sample)
	{
		*stereo16bitbuffer++ = (signed short)(FMath::Sin(t1) * 32767.0f) * 0.1f;    // left channel
		*stereo16bitbuffer++ = (signed short)(FMath::Sin(t2) * 32767.0f) * 0.1f;    // right channel

		t1 += 0.01f + v1;
		t2 += 0.0142f + v2;
		v1 += (float)(FMath::Sin(t1) * 0.002f);
		v2 += (float)(FMath::Sin(t2) * 0.002f);
	}

	return FMOD_OK;
}

// Called when the game starts or when spawned
void AMultiSoundActor::BeginPlay()
{
	Super::BeginPlay();
	// Only play events in PIE/game, not when placing them in the editor
	auto StudioSystem = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime);
	if (StudioInstance) 
	{
		StudioInstance->start();
		StudioInstance->release();
	}
	

	FMOD::System* system = nullptr;
	StudioSystem->getCoreSystem(&system);
	FMOD_MODE               mode = FMOD_OPENUSER | FMOD_LOOP_NORMAL;
	FMOD_CREATESOUNDEXINFO  exinfo;
	void* extradriverdata = 0;

	memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
	exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);  /* Required. */
	exinfo.numchannels = 2;                               /* Number of channels in the sound. */
	exinfo.defaultfrequency = 44100;                           /* Default playback rate of sound. */
	exinfo.decodebuffersize = 44100;                           /* Chunk size of stream update in samples. This will be the amount of data passed to the user callback. */
	exinfo.length = exinfo.defaultfrequency * exinfo.numchannels * sizeof(signed short) * 5; /* Length of PCM data in bytes of whole song (for Sound::getLength) */
	exinfo.format = FMOD_SOUND_FORMAT_PCM16;         /* Data format of sound. */
	exinfo.pcmreadcallback = pcmreadcallback;                 /* User callback for reading. */

	verifyfmod(system->createSound(0, mode, &exinfo, &sound));

	verifyfmod(system->playSound(sound, 0, 0, &channel));

	system->createDSPByType(FMOD_DSP_TYPE_PAN, &panner);
	channel->addDSP(FMOD_CHANNELCONTROL_DSP_HEAD, panner);
	

}

// Called every frame
void AMultiSoundActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	FMOD_VECTOR fmodVec = { {0} };
	FMOD_VECTOR fmodVel = { {0} };

	FVector soundLoc = this->GetActorLocation();
	fmodVec = FMODUtils::ConvertWorldVector(soundLoc);

	channel->set3DAttributes(&fmodVec, &fmodVel);

	DrawDebugSphere(GetWorld(), soundLoc, 100, 32, FColor::Blue, false, 0.0f, 0.0f, 2.0f);

	FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI multi = {};

	{
		//Calculate positioning values
		FMOD_3D_ATTRIBUTES absolute = {};
		FVector soundFwd = this->GetActorForwardVector();
		absolute.forward = FMODUtils::ConvertWorldVector(soundFwd);

		absolute.position = { 50,50,0 };
		absolute.position = FMODUtils::ConvertWorldVector(soundLoc);

		FVector soundUp = this->GetActorUpVector();

		absolute.up = { 0,1,0 };
		absolute.up = FMODUtils::ConvertWorldVector(soundUp);

		absolute.velocity = { 0,0,0 };

		FMOD_3D_ATTRIBUTES relative = {};

		APlayerCameraManager* camManager = GetWorld()->GetFirstPlayerController()->PlayerCameraManager;
		FVector camLoc = camManager->GetCameraLocation();
		FVector camFwd = camManager->GetCameraRotation().Vector();
		FVector camUp = camManager->GetActorUpVector();
		FTransform xCam = camManager->GetActorTransform();

		FVector rLoc = xCam.TransformPosition(soundLoc);
		FVector rFwd = xCam.TransformPosition(soundFwd);
		FVector rUp = xCam.TransformPosition(soundUp);

		relative.forward = FMODUtils::ConvertWorldVector(rFwd);
		relative.position = FMODUtils::ConvertWorldVector(rLoc);
		relative.up = FMODUtils::ConvertWorldVector(rUp);

		//Assign values
		multi.numlisteners = 1;
		multi.weight[0] = 1;
		multi.absolute = absolute;
		multi.relative[0] = relative;
	}
	panner->setParameterInt(FMOD_DSP_PAN_3D_ROLLOFF, FMOD_DSP_PAN_3D_ROLLOFF_INVERSE);
	panner->setParameterData(FMOD_DSP_PAN_3D_POSITION, (void*)(&multi), sizeof(multi));
	panner->setParameterFloat(FMOD_DSP_PAN_3D_MIN_DISTANCE, 20.0f);
	panner->setParameterFloat(FMOD_DSP_PAN_3D_MAX_DISTANCE, 200.0f);
	panner->setMeteringEnabled(false, true);
	panner->setChannelFormat(0, FMOD_MAX_CHANNEL_WIDTH, FMOD_SPEAKERMODE_STEREO);
	channel->set3DLevel(1.0f);
	sound->set3DMinMaxDistance(0.0f, 200.0f);
	
}

void AMultiSoundActor::EndPlay(EEndPlayReason::Type Why)
{
	if (channel) 
	{
		channel->stop();
	}
	if (sound) 
	{
		
		sound->release();
	}
}

 

Hi,

Could you try setting it to the position of the actor in the world:

absolute.position = FMODUtils::ConvertUnitVector(this->GetActorLocation());
FMODUtils::Assign(absolute.position, soundLoc);

Let me know if that helps

Same result from as last test run:

void AMultiSoundActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	FMOD_VECTOR fmodVec = { {0} };
	FMOD_VECTOR fmodVel = { {0} };

	FVector soundLoc = this->GetActorLocation();
	fmodVec = FMODUtils::ConvertWorldVector(soundLoc);
	channel->set3DAttributes(&fmodVec, &fmodVel);

	DrawDebugSphere(GetWorld(), soundLoc, 100, 32, FColor::Blue, false, 0.0f, 0.0f, 2.0f);

	FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI multi = {};

	{
		//Calculate positioning values
		FMOD_3D_ATTRIBUTES absolute = {};
		FVector soundFwd = this->GetActorForwardVector();
		absolute.forward = FMODUtils::ConvertWorldVector(soundFwd);

		absolute.position = { 50,50,0 };
		absolute.position = FMODUtils::ConvertWorldVector(soundLoc);
//----------------------------------------------- NEW EDIT-----------------------
		FMODUtils::Assign(absolute.position, soundLoc);
//-------------------------------------------------------------------------------------

		FVector soundUp = this->GetActorUpVector();

		absolute.up = { 0,1,0 };
		absolute.up = FMODUtils::ConvertWorldVector(soundUp);

		absolute.velocity = { 0,0,0 };

		FMOD_3D_ATTRIBUTES relative = {};

		APlayerCameraManager* camManager = GetWorld()->GetFirstPlayerController()->PlayerCameraManager;
		FVector camLoc = camManager->GetCameraLocation();
		FVector camFwd = camManager->GetCameraRotation().Vector();
		FVector camUp = camManager->GetActorUpVector();
		FTransform xCam = camManager->GetActorTransform();

		FVector rLoc = xCam.TransformPosition(soundLoc);
		FVector rFwd = xCam.TransformPosition(soundFwd);
		FVector rUp = xCam.TransformPosition(soundUp);

		relative.forward = FMODUtils::ConvertWorldVector(rFwd);
		relative.position = FMODUtils::ConvertWorldVector(rLoc);
		relative.up = FMODUtils::ConvertWorldVector(rUp);

		//Assign values
		multi.numlisteners = 1;
		multi.weight[0] = 1;
		multi.absolute = absolute;
		multi.relative[0] = relative;
	}
	panner->setParameterInt(FMOD_DSP_PAN_3D_ROLLOFF, FMOD_DSP_PAN_3D_ROLLOFF_INVERSE);
...
}

The issue may be we are trying to call 3D commands on a 2D sound. This is further explained here: FMOD API | White Papers - 3D Sounds. You will need to add the FMOD_3D flag to the

that is currently used to create the sound.

FMOD_MODE mode = FMOD_OPENUSER | FMOD_LOOP_NORMAL | FMOD_3D;

I see you are using the verifyfmod() function sporadically through your code, I would recommend using it for any FMOD function that returns FMOD_RESULT as it is really useful for debugging issues like these. This would have shown that

was returning an error in the UE console.

Hope this helps!

1 Like

That’s exactly it, thank you soooo much!!!

1 Like

Hi Connor,

I am curious about Resonance doing early reflections. Can you point me towards any resources about this? I have only tried the Resonance Room reverb, but that seems to be more like a typical trigger box for setting up reverbs, I am curious about the early reflections created by raycasting as you mention here

Hi,

Unfortunately, the only documentation we have is what I have listed here: How to build early reflection? - #5 by Connor_FMOD.