241 lines
8.2 KiB
C++
241 lines
8.2 KiB
C++
/*==============================================================================
|
|
Event 3D Multi-Listener Example
|
|
Copyright (c), Firelight Technologies Pty, Ltd 2012-2025.
|
|
|
|
This example demonstrates how use listener weighting to crossfade listeners
|
|
in and out.
|
|
|
|
For information on using FMOD example code in your own programs, visit
|
|
https://www.fmod.com/legal
|
|
==============================================================================*/
|
|
#include "fmod_studio.hpp"
|
|
#include "fmod.hpp"
|
|
#include "common.h"
|
|
|
|
const int SCREEN_WIDTH = NUM_COLUMNS;
|
|
const int SCREEN_HEIGHT = 10;
|
|
|
|
char backBuffer[(SCREEN_WIDTH + 1) * SCREEN_HEIGHT + 1] = {0};
|
|
char screenBuffer[(SCREEN_WIDTH + 1) * SCREEN_HEIGHT + 1] = {0};
|
|
|
|
void initializeScreenBuffer();
|
|
void updateScreenPosition(const FMOD_VECTOR& worldPosition, float listenerDist, float weight1, float weight2);
|
|
|
|
int FMOD_Main()
|
|
{
|
|
void *extraDriverData = NULL;
|
|
Common_Init(&extraDriverData);
|
|
|
|
FMOD::Studio::System* system = NULL;
|
|
ERRCHECK( FMOD::Studio::System::create(&system) );
|
|
|
|
// The example Studio project is authored for 5.1 sound, so set up the system output mode to match
|
|
FMOD::System* coreSystem = NULL;
|
|
ERRCHECK( system->getCoreSystem(&coreSystem) );
|
|
ERRCHECK( coreSystem->setSoftwareFormat(0, FMOD_SPEAKERMODE_5POINT1, 0) );
|
|
|
|
ERRCHECK( system->initialize(1024, FMOD_STUDIO_INIT_NORMAL, FMOD_INIT_NORMAL, extraDriverData) );
|
|
|
|
FMOD::Studio::Bank* masterBank = NULL;
|
|
ERRCHECK( system->loadBankFile(Common_MediaPath("Master.bank"), FMOD_STUDIO_LOAD_BANK_NORMAL, &masterBank) );
|
|
|
|
FMOD::Studio::Bank* stringsBank = NULL;
|
|
ERRCHECK( system->loadBankFile(Common_MediaPath("Master.strings.bank"), FMOD_STUDIO_LOAD_BANK_NORMAL, &stringsBank) );
|
|
|
|
FMOD::Studio::Bank* vehiclesBank = NULL;
|
|
ERRCHECK( system->loadBankFile(Common_MediaPath("Vehicles.bank"), FMOD_STUDIO_LOAD_BANK_NORMAL, &vehiclesBank) );
|
|
|
|
FMOD::Studio::EventDescription* eventDescription = NULL;
|
|
ERRCHECK( system->getEvent("event:/Vehicles/Ride-on Mower", &eventDescription) );
|
|
|
|
FMOD::Studio::EventInstance* eventInstance = NULL;
|
|
ERRCHECK( eventDescription->createInstance(&eventInstance) );
|
|
|
|
ERRCHECK( eventInstance->setParameterByName("RPM", 650.0f) );
|
|
ERRCHECK( eventInstance->start() );
|
|
|
|
// Position two listeners
|
|
ERRCHECK( system->setNumListeners(2) );
|
|
int activeListener = 0;
|
|
float listenerDist = 8.0f;
|
|
float listenerWeight[2] = { 1.0f, 0.0f };
|
|
FMOD_3D_ATTRIBUTES listenerAttributes[2] = {};
|
|
listenerAttributes[0].forward.z = 1.0f;
|
|
listenerAttributes[0].up.y = 1.0f;
|
|
listenerAttributes[0].position.x = -listenerDist;
|
|
listenerAttributes[1].forward.z = 1.0f;
|
|
listenerAttributes[1].up.y = 1.0f;
|
|
listenerAttributes[1].position.x = listenerDist;
|
|
|
|
ERRCHECK( system->setListenerAttributes(0, &listenerAttributes[0]) );
|
|
ERRCHECK( system->setListenerWeight(0, listenerWeight[0]) );
|
|
ERRCHECK( system->setListenerAttributes(1, &listenerAttributes[1]) );
|
|
ERRCHECK( system->setListenerWeight(1, listenerWeight[1]) );
|
|
|
|
// Position the event 2 units in front of the listener
|
|
FMOD_3D_ATTRIBUTES carAttributes = {};
|
|
carAttributes.forward.z = 1.0f;
|
|
carAttributes.up.y = 1.0f;
|
|
carAttributes.position.x = 0.0f;
|
|
carAttributes.position.z = 2.0f;
|
|
ERRCHECK( eventInstance->set3DAttributes(&carAttributes) );
|
|
|
|
initializeScreenBuffer();
|
|
|
|
do
|
|
{
|
|
Common_Update();
|
|
|
|
if (Common_BtnPress(BTN_LEFT))
|
|
{
|
|
carAttributes.position.x -= 1.0f;
|
|
ERRCHECK( eventInstance->set3DAttributes(&carAttributes) );
|
|
}
|
|
|
|
if (Common_BtnPress(BTN_RIGHT))
|
|
{
|
|
carAttributes.position.x += 1.0f;
|
|
ERRCHECK( eventInstance->set3DAttributes(&carAttributes) );
|
|
}
|
|
|
|
if (Common_BtnPress(BTN_UP))
|
|
{
|
|
carAttributes.position.z += 1.0f;
|
|
ERRCHECK( eventInstance->set3DAttributes(&carAttributes) );
|
|
}
|
|
|
|
if (Common_BtnPress(BTN_DOWN))
|
|
{
|
|
carAttributes.position.z -= 1.0f;
|
|
ERRCHECK( eventInstance->set3DAttributes(&carAttributes) );
|
|
}
|
|
|
|
if (Common_BtnPress(BTN_ACTION1))
|
|
{
|
|
activeListener++;
|
|
if (activeListener > 2)
|
|
activeListener = 0;
|
|
}
|
|
|
|
if (Common_BtnPress(BTN_ACTION2))
|
|
{
|
|
activeListener--;
|
|
if (activeListener < 0)
|
|
activeListener = 2;
|
|
}
|
|
|
|
if (Common_BtnPress(BTN_ACTION3))
|
|
{
|
|
listenerDist -= 1.0f;
|
|
if (listenerDist < 0.0f)
|
|
listenerDist = 0.0f;
|
|
}
|
|
|
|
if (Common_BtnPress(BTN_ACTION4))
|
|
{
|
|
listenerDist += 1.0f;
|
|
if (listenerDist < 0.0f)
|
|
listenerDist = 0.0f;
|
|
}
|
|
|
|
for (int i=0; i<2; ++i)
|
|
{
|
|
float target = (activeListener == i || activeListener == 2); // 0 = left, 1 = right, 2 = both
|
|
|
|
float dist = (target - listenerWeight[i]);
|
|
float step = 50.0f / 1000.0f; // very rough estimate of 50ms per update, not properly timed
|
|
|
|
if (dist >= -step && dist <= step)
|
|
listenerWeight[i] = target;
|
|
else if (dist > 0.0f)
|
|
listenerWeight[i] += step;
|
|
else
|
|
listenerWeight[i] += -step;
|
|
}
|
|
|
|
listenerAttributes[0].position.x = -listenerDist;
|
|
listenerAttributes[1].position.x = listenerDist;
|
|
ERRCHECK( system->setListenerAttributes(0, &listenerAttributes[0]) );
|
|
ERRCHECK( system->setListenerAttributes(1, &listenerAttributes[1]) );
|
|
ERRCHECK( system->setListenerWeight(0, listenerWeight[0]) );
|
|
ERRCHECK( system->setListenerWeight(1, listenerWeight[1]) );
|
|
|
|
ERRCHECK( system->update() );
|
|
|
|
updateScreenPosition(carAttributes.position, listenerDist, listenerWeight[0], listenerWeight[1]);
|
|
|
|
Common_Draw("==================================================");
|
|
Common_Draw("Event 3D Multi-Listener Example.");
|
|
Common_Draw("Copyright (c) Firelight Technologies 2012-2025.");
|
|
Common_Draw("==================================================");
|
|
Common_Draw(screenBuffer);
|
|
|
|
Common_Draw("Left listener: %d%%", (int)(listenerWeight[0] * 100));
|
|
Common_Draw("Right listener: %d%%", (int)(listenerWeight[1] * 100));
|
|
Common_Draw("Use the arrow keys (%s, %s, %s, %s) to control the event position",
|
|
Common_BtnStr(BTN_LEFT), Common_BtnStr(BTN_RIGHT), Common_BtnStr(BTN_UP), Common_BtnStr(BTN_DOWN));
|
|
Common_Draw("Use %s and %s to toggle left/right/both listeners", Common_BtnStr(BTN_ACTION1), Common_BtnStr(BTN_ACTION2));
|
|
Common_Draw("Use %s and %s to move listeners closer or further apart", Common_BtnStr(BTN_ACTION3), Common_BtnStr(BTN_ACTION4));
|
|
Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
|
|
|
|
Common_Sleep(50);
|
|
} while (!Common_BtnPress(BTN_QUIT));
|
|
|
|
ERRCHECK( system->release() );
|
|
|
|
Common_Close();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void initializeScreenBuffer()
|
|
{
|
|
memset(backBuffer, ' ', sizeof(backBuffer));
|
|
|
|
int idx = SCREEN_WIDTH;
|
|
for (int i = 0; i < SCREEN_HEIGHT; ++i)
|
|
{
|
|
backBuffer[idx] = '\n';
|
|
idx += SCREEN_WIDTH + 1;
|
|
}
|
|
|
|
backBuffer[(SCREEN_WIDTH + 1) * SCREEN_HEIGHT] = '\0';
|
|
memcpy(screenBuffer, backBuffer, sizeof(screenBuffer));
|
|
}
|
|
|
|
void setCharacterIndex(const FMOD_VECTOR& position, char ch)
|
|
{
|
|
int row = static_cast<int>(-position.z + (SCREEN_HEIGHT / 2));
|
|
int col = static_cast<int>(position.x + (SCREEN_WIDTH / 2));
|
|
|
|
if (0 < row && row < SCREEN_HEIGHT && 0 < col && col < SCREEN_WIDTH)
|
|
{
|
|
screenBuffer[row * (SCREEN_WIDTH + 1) + col] = ch;
|
|
}
|
|
}
|
|
|
|
char symbolForWeight(float weight)
|
|
{
|
|
if (weight >= 0.95f)
|
|
return 'X';
|
|
else if (weight >= 0.05f)
|
|
return 'x';
|
|
else
|
|
return '.';
|
|
}
|
|
|
|
void updateScreenPosition(const FMOD_VECTOR& worldPosition, float listenerDist, float weight1, float weight2)
|
|
{
|
|
memcpy(screenBuffer, backBuffer, sizeof(screenBuffer));
|
|
|
|
FMOD_VECTOR pos = {0};
|
|
setCharacterIndex(pos, '^');
|
|
|
|
pos.x = -listenerDist;
|
|
setCharacterIndex(pos, symbolForWeight(weight1));
|
|
|
|
pos.x = listenerDist;
|
|
setCharacterIndex(pos, symbolForWeight(weight2));
|
|
|
|
setCharacterIndex(worldPosition, 'o');
|
|
}
|