Created
May 2, 2014 05:45
-
-
Save anonymous/4d62c4c4147f30be470d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*============================================================================== | |
Event Parameter Example | |
Copyright (c), Firelight Technologies Pty, Ltd 2012-2014. | |
This example demonstrates how to control event playback using game parameters. | |
==============================================================================*/ | |
#include "fmod_studio.hpp" | |
#include "fmod.hpp" | |
#include "common.h" | |
#include "fmod_errors.h" | |
//////////////////////////////////////////////////////////////////////////////// | |
// if defined, load from banks from memory | |
#define BANK_MEMORY | |
//! by NOT having async loading we get the strings loaded immediately and we will not fail on lookup | |
//! in the 'create_engine_sound' function | |
#define BANK_MEMORY_ASYNC_LOADING | |
//////////////////////////////////////////////////////////////////////////////// | |
#define LOG_OUT(s) OutputDebugStringA((s)) | |
#define VSNPRINTF(s, n, f, v) _vsnprintf_s((s), (n), _TRUNCATE, (f), (v)) | |
#define LOG_TEMP_BUFFER_SIZE (32*1024) | |
void log_message_format(const char *msg_format, ...) | |
{ | |
char buffer[LOG_TEMP_BUFFER_SIZE]; | |
va_list args; | |
va_start(args, msg_format); | |
VSNPRINTF(buffer, LOG_TEMP_BUFFER_SIZE-1, msg_format, args); | |
LOG_OUT(buffer); | |
va_end(args); | |
} | |
#define FLOG(s, ...) log_message_format(s "\n", ##__VA_ARGS__) | |
typedef unsigned __int64 tick_t; | |
typedef float deltatime_t; | |
static tick_t _time_freq = 0; | |
static double _time_oofreq = 0; | |
static tick_t _time_startup = 0; | |
tick_t time_current(void) | |
{ | |
tick_t curclock; | |
QueryPerformanceCounter( (LARGE_INTEGER*)&curclock ); | |
return curclock; | |
} | |
int time_init(void) | |
{ | |
tick_t unused; | |
if( !QueryPerformanceFrequency( (LARGE_INTEGER*)&_time_freq ) || | |
!QueryPerformanceCounter( (LARGE_INTEGER*)&unused ) ) | |
return -1; | |
_time_oofreq = 1.0 / (double)_time_freq; | |
_time_startup = time_current(); | |
return 0; | |
} | |
tick_t time_startup(void) { return _time_startup; } | |
tick_t time_ticks_per_second(void) { return _time_freq; } | |
tick_t time_seconds_to_ticks(const deltatime_t s) { return time_ticks_per_second() * (tick_t)s; } | |
tick_t time_diff(const tick_t from, const tick_t to) | |
{ | |
if(to <= from) | |
return 0; | |
return (to - from); | |
} | |
tick_t time_elapsed_ticks(const tick_t t) | |
{ | |
tick_t dt, curclock = t; | |
QueryPerformanceCounter( (LARGE_INTEGER*)&curclock ); | |
dt = curclock - t; | |
return dt; | |
} | |
deltatime_t time_seconds_elapsed(const tick_t t) { return (deltatime_t)( (double)time_elapsed_ticks(t) * _time_oofreq); } | |
deltatime_t time_ticks_to_seconds(const tick_t dt) { return (deltatime_t)( (double)dt * _time_oofreq ); } | |
#define XSTRINGIFY_FMOD(s) STRINGIFY_FMOD( (s) ) | |
#define STRINGIFY_FMOD(s) #s | |
static const char *instance_type_to_string(FMOD_ERRORCALLBACK_INSTANCETYPE t) | |
{ | |
#define MAKE_CASE(a) case (a) : return STRINGIFY_FMOD(a); | |
switch (t) | |
{ | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_NONE) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_SYSTEM) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_CHANNEL) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_CHANNELGROUP) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_CHANNELCONTROL) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_SOUND) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_SOUNDGROUP) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_DSP) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_DSPCONNECTION) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_GEOMETRY) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_REVERB3D) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_STUDIO_SYSTEM) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_STUDIO_EVENTDESCRIPTION) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_STUDIO_EVENTINSTANCE) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_STUDIO_PARAMETERINSTANCE) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_STUDIO_CUEINSTANCE) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_STUDIO_MIXERSTRIP) | |
MAKE_CASE(FMOD_ERRORCALLBACK_INSTANCETYPE_STUDIO_BANK) | |
default : return "UNKNOWN INSTANCE TYPE"; | |
} | |
#undef MAKE_CASE | |
} | |
static FMOD_RESULT F_CALLBACK FMOD_SYSTEM_CALLBACK_SELF(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void *userdata) | |
{ | |
(void)userdata; | |
(void)commanddata2; | |
(void)system; | |
switch (type) | |
{ | |
/* Called from System::update when the enumerated list of devices has changed. */ | |
case FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED : | |
FLOG("%s", STRINGIFY_FMOD(FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED)); | |
break; | |
/* Called from System::update when an output device has been lost due to control panel parameter changes and FMOD cannot automatically recover. */ | |
case FMOD_SYSTEM_CALLBACK_DEVICELOST : | |
FLOG("%s", STRINGIFY_FMOD( FMOD_SYSTEM_CALLBACK_DEVICELOST )); | |
break; | |
/* Called directly when a memory allocation fails somewhere in FMOD. (NOTE - 'system' will be NULL in this callback type.)*/ | |
case FMOD_SYSTEM_CALLBACK_MEMORYALLOCATIONFAILED : | |
FLOG("%s", STRINGIFY_FMOD( FMOD_SYSTEM_CALLBACK_MEMORYALLOCATIONFAILED )); | |
break; | |
/* Called directly when a thread is created. (NOTE - 'system' will be NULL in this callback type.) */ | |
case FMOD_SYSTEM_CALLBACK_THREADCREATED : | |
FLOG("%s. Thread ID [%d], name [%s]", STRINGIFY_FMOD( FMOD_SYSTEM_CALLBACK_THREADCREATED ), (int)commanddata1, (char*)commanddata2); | |
break; | |
/* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ | |
case FMOD_SYSTEM_CALLBACK_BADDSPCONNECTION : | |
FLOG("%s", STRINGIFY_FMOD( FMOD_SYSTEM_CALLBACK_BADDSPCONNECTION)); | |
break; | |
/* Called each tick before a mix update happens. */ | |
case FMOD_SYSTEM_CALLBACK_PREMIX : | |
FLOG("%s", STRINGIFY_FMOD( FMOD_SYSTEM_CALLBACK_PREMIX)); | |
break; | |
/* Called each tick after a mix update happens. */ | |
case FMOD_SYSTEM_CALLBACK_POSTMIX : | |
FLOG("%s", STRINGIFY_FMOD( FMOD_SYSTEM_CALLBACK_POSTMIX )); | |
break; | |
case FMOD_SYSTEM_CALLBACK_ERROR : | |
{ | |
FMOD_ERRORCALLBACK_INFO *error_info = (FMOD_ERRORCALLBACK_INFO*)commanddata1; | |
FMOD_RESULT fmod_error = error_info->result; | |
FLOG( "FMOD ERROR [%i] - %s. [%s 0x%p] %s(%s)", | |
fmod_error, FMOD_ErrorString(fmod_error), | |
instance_type_to_string(error_info->instancetype), error_info->instance, | |
error_info->functionname, error_info->functionparams); | |
fmod_error = fmod_error; | |
} | |
break; | |
} | |
return FMOD_OK; | |
} | |
#if defined(BANK_MEMORY) | |
static void read_file_aligned32(const char *name, void **buff, int *length) | |
{ | |
FILE *file = NULL; | |
fopen_s(&file, name, "rb"); | |
fseek(file, 0, SEEK_END); | |
long len = ftell(file); | |
fseek(file, 0, SEEK_SET); | |
void *mem = _aligned_malloc(len, 32); | |
fread(mem, 1, len, file); | |
fclose(file); | |
*buff = mem; | |
*length = len; | |
} | |
#endif | |
static int num_checks = 0; | |
static int create_engine_sound(FMOD::Studio::System *system, FMOD::Studio::EventInstance **eventInstance) | |
{ | |
++num_checks; | |
FMOD::Studio::ID eventID = {0}; | |
if (FMOD_OK != system->lookupID("event:/Vehicles/Basic Engine", &eventID)) | |
return 0; | |
FMOD::Studio::EventDescription* eventDescription = NULL; | |
if (FMOD_OK != system->getEvent(&eventID, FMOD_STUDIO_LOAD_BEGIN_NOW, &eventDescription) ) | |
return 0; | |
ERRCHECK( eventDescription->createInstance(eventInstance) ); | |
FMOD::Studio::ParameterInstance* surfaceParameter = NULL; | |
ERRCHECK( (*eventInstance)->getParameter("RPM", &surfaceParameter) ); | |
ERRCHECK( surfaceParameter->setValue(500.0f) ); | |
float surfaceParameterValue = 0; | |
ERRCHECK( surfaceParameter->getValue(&surfaceParameterValue) ); | |
ERRCHECK( (*eventInstance)->start() ); | |
FLOG("ENGINE SOUND CREATED %i! %p", num_checks, *eventInstance); | |
return 1; | |
} | |
int FMOD_Main() | |
{ | |
tick_t start_time, start_time_bank_sampledata_load; | |
deltatime_t delta_time_elapsed; | |
int sample_data_loaded; | |
FMOD_STUDIO_LOADING_STATE loading_state; | |
void *extraDriverData = NULL; | |
#if defined (BANK_MEMORY) | |
FLOG("BANKS FROM MEMORY"); | |
FMOD_STUDIO_LOAD_MEMORY_MODE load_bank_memory_mode = FMOD_STUDIO_LOAD_MEMORY_POINT; | |
#if defined(BANK_MEMORY_ASYNC_LOADING) | |
FMOD_STUDIO_LOAD_BANK_FLAGS load_bank_flags = FMOD_STUDIO_LOAD_BANK_NONBLOCKING; | |
#else | |
FMOD_STUDIO_LOAD_BANK_FLAGS load_bank_flags = FMOD_STUDIO_LOAD_BANK_NORMAL; | |
#endif | |
void *mem_master_bank, *mem_master_bank_strings, *mem_vehicles; | |
int mem_size_master_bank, mem_size_master_bank_strings, mem_size_vehicles; | |
read_file_aligned32(Common_MediaPath("Master Bank.bank"), &mem_master_bank, &mem_size_master_bank); | |
read_file_aligned32(Common_MediaPath("Master Bank.strings.bank"), &mem_master_bank_strings, &mem_size_master_bank_strings); | |
read_file_aligned32(Common_MediaPath("Vehicles.bank"), &mem_vehicles, &mem_size_vehicles); | |
#else | |
FLOG("NOT USING BANKS FROM MEMORY"); | |
#endif | |
Common_Init(&extraDriverData); | |
if (-1 == time_init()) | |
Common_Fatal("failed to init time"); | |
FMOD::Studio::System* system = NULL; | |
ERRCHECK( FMOD::Studio::System::create(&system) ); | |
start_time = time_current(); | |
ERRCHECK( system->initialize(32, FMOD_STUDIO_INIT_NORMAL, FMOD_INIT_NORMAL, extraDriverData) ); | |
delta_time_elapsed = time_ticks_to_seconds( time_diff(start_time, time_current()) ), start_time = time_current(); | |
FLOG("System initialize %f s", delta_time_elapsed); | |
FMOD::System *lls = 0; | |
ERRCHECK ( system->getLowLevelSystem(&lls) ); | |
FMOD_SYSTEM_CALLBACK_TYPE T = | |
FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED | /* Called from System::update when the enumerated list of devices has changed. */ | |
FMOD_SYSTEM_CALLBACK_DEVICELOST | /* Called from System::update when an output device has been lost due to control panel parameter changes and FMOD cannot automatically recover. */ | |
FMOD_SYSTEM_CALLBACK_MEMORYALLOCATIONFAILED | /* Called directly when a memory allocation fails somewhere in FMOD. (NOTE - 'system' will be NULL in this callback type.)*/ | |
FMOD_SYSTEM_CALLBACK_THREADCREATED | /* Called directly when a thread is created. (NOTE - 'system' will be NULL in this callback type.) */ | |
FMOD_SYSTEM_CALLBACK_BADDSPCONNECTION | /* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ | |
//FMOD_SYSTEM_CALLBACK_PREMIX | /* Called each tick before a mix update happens. */ | |
//FMOD_SYSTEM_CALLBACK_POSTMIX | /* Called each tick after a mix update happens. */ | |
FMOD_SYSTEM_CALLBACK_ERROR ; | |
lls->setCallback(FMOD_SYSTEM_CALLBACK_SELF, T); | |
FMOD::Studio::Bank* masterBank = NULL; | |
#if defined (BANK_MEMORY) | |
ERRCHECK( system->loadBankMemory((const char*)mem_master_bank, mem_size_master_bank, load_bank_memory_mode, load_bank_flags, &masterBank) ); | |
#else | |
ERRCHECK( system->loadBankFile(Common_MediaPath("Master Bank.bank"), FMOD_STUDIO_LOAD_BANK_NORMAL, &masterBank) ); | |
#endif | |
delta_time_elapsed = time_ticks_to_seconds( time_diff(start_time, time_current()) ), start_time = time_current(); | |
FLOG("Load bank %s. %f s", "Master Bank.bank", delta_time_elapsed); | |
FMOD::Studio::Bank* stringsBank = NULL; | |
#if defined (BANK_MEMORY) | |
ERRCHECK( system->loadBankMemory((const char*)mem_master_bank_strings, mem_size_master_bank_strings, load_bank_memory_mode, load_bank_flags, &stringsBank) ); | |
#else | |
ERRCHECK( system->loadBankFile(Common_MediaPath("Master Bank.strings.bank"), FMOD_STUDIO_LOAD_BANK_NORMAL, &stringsBank) ); | |
#endif | |
delta_time_elapsed = time_ticks_to_seconds( time_diff(start_time, time_current()) ), start_time = time_current(); | |
FLOG("Load bank %s. %f s", "Master Bank.strings.bank", delta_time_elapsed); | |
FMOD::Studio::Bank* vehiclesBank = NULL; | |
#if defined (BANK_MEMORY) | |
ERRCHECK( system->loadBankMemory((const char*)mem_vehicles, mem_size_vehicles, load_bank_memory_mode, load_bank_flags, &vehiclesBank) ); | |
#else | |
ERRCHECK( system->loadBankFile(Common_MediaPath("Vehicles.bank"), FMOD_STUDIO_LOAD_BANK_NORMAL, &vehiclesBank) ); | |
#endif | |
delta_time_elapsed = time_ticks_to_seconds( time_diff(start_time, time_current()) ), start_time = time_current(); | |
FLOG("Load bank %s. %f s", "Vehicles.bank", delta_time_elapsed); | |
sample_data_loaded = 0; | |
ERRCHECK( vehiclesBank->loadSampleData() ); | |
start_time_bank_sampledata_load = time_current(); | |
ERRCHECK( vehiclesBank->getSampleLoadingState(&loading_state) ); | |
if (loading_state == FMOD_STUDIO_LOADING_STATE_LOADED) { | |
sample_data_loaded = 1; | |
delta_time_elapsed = time_ticks_to_seconds( time_diff(start_time_bank_sampledata_load, time_current()) ); | |
FLOG("Load bank sample data(first). %f s", delta_time_elapsed); | |
} | |
FMOD::Studio::EventInstance* eventInstance = NULL; | |
#if 0 | |
FMOD::Studio::ID eventID = {0}; | |
//ERRCHECK( system->lookupID("event:/Character/Footsteps/Footsteps", &eventID) ); | |
ERRCHECK( system->lookupID("event:/Vehicles/Basic Engine", &eventID) ); | |
FMOD::Studio::EventDescription* eventDescription = NULL; | |
ERRCHECK( system->getEvent(&eventID, FMOD_STUDIO_LOAD_BEGIN_NOW, &eventDescription) ); | |
ERRCHECK( eventDescription->createInstance(&eventInstance) ); | |
FMOD::Studio::ParameterInstance* surfaceParameter = NULL; | |
//ERRCHECK( eventInstance->getParameter("Surface", &surfaceParameter) ); | |
ERRCHECK( eventInstance->getParameter("RPM", &surfaceParameter) ); | |
// Make the event audible to start with | |
ERRCHECK( surfaceParameter->setValue(500.0f) ); | |
float surfaceParameterValue = 0; | |
ERRCHECK( surfaceParameter->getValue(&surfaceParameterValue) ); | |
ERRCHECK( eventInstance->start() ); | |
#endif | |
FLOG("STARTING MAIN LOOP"); | |
ERRCHECK( system->update() ); | |
unsigned loop_count = 0; | |
do | |
{ | |
float surfaceParameterValue = -1.0f; | |
Common_Update(); | |
if (eventInstance == NULL) | |
create_engine_sound(system, &eventInstance); | |
if (eventInstance) { | |
FMOD::Studio::ParameterInstance* surfaceParameter = NULL; | |
ERRCHECK( eventInstance->getParameter("RPM", &surfaceParameter) ); | |
ERRCHECK( surfaceParameter->getValue(&surfaceParameterValue) ); | |
} | |
if (eventInstance && Common_BtnPress(BTN_ACTION1)) | |
{ | |
FMOD::Studio::ParameterInstance* surfaceParameter = NULL; | |
ERRCHECK( eventInstance->getParameter("RPM", &surfaceParameter) ); | |
ERRCHECK( surfaceParameter->getValue(&surfaceParameterValue) ); | |
surfaceParameterValue -= 100.0f; | |
ERRCHECK( surfaceParameter->setValue(surfaceParameterValue) ); | |
} | |
if (eventInstance && Common_BtnPress(BTN_ACTION2)) | |
{ | |
FMOD::Studio::ParameterInstance* surfaceParameter = NULL; | |
ERRCHECK( eventInstance->getParameter("RPM", &surfaceParameter) ); | |
ERRCHECK( surfaceParameter->getValue(&surfaceParameterValue) ); | |
surfaceParameterValue += 100.0f; | |
ERRCHECK( surfaceParameter->setValue(surfaceParameterValue) ); | |
} | |
ERRCHECK( system->update() ); | |
FMOD_STUDIO_BUFFER_USAGE buffer_usage; | |
ERRCHECK( system->getBufferUsage(&buffer_usage) ); | |
if (buffer_usage.studioCommandQueue.stallCount > 0) { | |
int break_here = 1; | |
break_here = 0; | |
} | |
if (buffer_usage.studioHandle.stallCount > 0) { | |
int break_here = 1; | |
break_here = 0; | |
} | |
if (sample_data_loaded == 0) { | |
ERRCHECK( vehiclesBank->getSampleLoadingState(&loading_state) ); | |
if (loading_state == FMOD_STUDIO_LOADING_STATE_LOADED) { | |
sample_data_loaded = 1; | |
delta_time_elapsed = time_ticks_to_seconds( time_diff(start_time_bank_sampledata_load, time_current()) ); | |
FLOG("Load bank sample data @loopcount[%u]. %f s", loop_count, delta_time_elapsed); | |
} | |
} | |
Common_Draw("=================================================="); | |
Common_Draw("Event Parameter Example."); | |
Common_Draw("Copyright (c) Firelight Technologies 2014-2014."); | |
Common_Draw("=================================================="); | |
Common_Draw(""); | |
Common_Draw("Surface Parameter = %1.1f", surfaceParameterValue); | |
Common_Draw(""); | |
Common_Draw("Surface Parameter:"); | |
Common_Draw("Press %s to decrease value", Common_BtnStr(BTN_ACTION1)); | |
Common_Draw("Press %s to increase value", Common_BtnStr(BTN_ACTION2)); | |
Common_Draw(""); | |
Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT)); | |
++loop_count; | |
Common_Sleep(50); | |
} while (!Common_BtnPress(BTN_QUIT)); | |
ERRCHECK( system->release() ); | |
Common_Close(); | |
#if defined (BANK_MEMORY) | |
_aligned_free(mem_master_bank); | |
_aligned_free(mem_master_bank_strings); | |
_aligned_free(mem_vehicles); | |
#endif | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment