- Added support for building with FMOD Studio Low Level API (partially based off of Emile Belanger's/Beloko Games Android work)

- Use with FMOD Studio 1.06.x. 1.07 and 1.08 compile but for some reason produce a lot of noise on vanilla Doom sounds.
	- Crashes when used with fluidsynth provided by Ubuntu 16.04, but a self compiled version of the library works just fine.
	- Reverbs are mostly untested, but implemented.
	- Debug waveform drawing is not implemented as it requires a non-trivial amount of work.
	- It will still show as FMOD Ex in the menus since I'm too lazy at the moment to make it a "separate" backend.
This commit is contained in:
Braden Obrzut 2016-08-27 22:14:57 -04:00
parent 5303526c70
commit 716fbec8ee
4 changed files with 354 additions and 41 deletions

View file

@ -1,11 +1,17 @@
cmake_minimum_required( VERSION 2.8.7 ) cmake_minimum_required( VERSION 2.8.7 )
if( NOT NO_FMOD AND FMOD_INCLUDE_DIR ) if( NOT NO_FMOD AND FMOD_INCLUDE_DIR )
add_library( output_sdl MODULE output_sdl.c )
include_directories( ${FMOD_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} ) include_directories( ${FMOD_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} )
target_link_libraries( output_sdl ${SDL2_LIBRARY} ) check_library_exists(${FMOD_LIBRARY} "FMOD_System_GetDriverCaps" "fmod.h" FMOD_IS_EX)
FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" ) # Only usable with FMOD Ex
add_custom_command( TARGET output_sdl POST_BUILD if( FMOD_IS_EX )
COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make include_directories( ${FMOD_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} )
COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) add_library( output_sdl MODULE output_sdl.c )
target_link_libraries( output_sdl ${SDL2_LIBRARY} )
FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" )
add_custom_command( TARGET output_sdl POST_BUILD
COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make
COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make )
endif()
endif() endif()

View file

@ -611,5 +611,14 @@ namespace FMOD
} }
#endif #endif
// FMOD Ex vs FMOD Studio
#if FMOD_VERSION >= 0x00040000 && FMOD_VERSION <= 0x0004FFFF
#define FMOD_STUDIO 0
#else
#define FMOD_STUDIO 1
#define FMOD_SOFTWARE 0
#endif
#endif #endif
#endif #endif

View file

@ -122,10 +122,14 @@ CUSTOM_CVAR (Int, snd_streambuffersize, 64, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
} }
#ifndef NO_FMOD #ifndef NO_FMOD
#if FMOD_VERSION < 0x43400 #if !FMOD_STUDIO && FMOD_VERSION < 0x43400
#define FMOD_OPENSTATE_PLAYING FMOD_OPENSTATE_STREAMING #define FMOD_OPENSTATE_PLAYING FMOD_OPENSTATE_STREAMING
#endif #endif
#if !FMOD_STUDIO
#define setParameterFloat setParameter
#endif
// TYPES ------------------------------------------------------------------- // TYPES -------------------------------------------------------------------
struct FEnumList struct FEnumList
@ -183,15 +187,28 @@ static const FEnumList OutputNames[] =
{ "WASAPI", FMOD_OUTPUTTYPE_WASAPI }, { "WASAPI", FMOD_OUTPUTTYPE_WASAPI },
{ "ASIO", FMOD_OUTPUTTYPE_ASIO }, { "ASIO", FMOD_OUTPUTTYPE_ASIO },
#if FMOD_STUDIO
//Android
{ "OPENSL", FMOD_OUTPUTTYPE_OPENSL },
{ "Android Audio Track", FMOD_OUTPUTTYPE_AUDIOTRACK },
#endif
// Linux // Linux
#if !FMOD_STUDIO
{ "OSS", FMOD_OUTPUTTYPE_OSS }, { "OSS", FMOD_OUTPUTTYPE_OSS },
#endif
{ "ALSA", FMOD_OUTPUTTYPE_ALSA }, { "ALSA", FMOD_OUTPUTTYPE_ALSA },
#if !FMOD_STUDIO
{ "ESD", FMOD_OUTPUTTYPE_ESD }, { "ESD", FMOD_OUTPUTTYPE_ESD },
#if FMOD_VERSION >= 0x43400 #endif
#if FMOD_STUDIO || FMOD_VERSION >= 0x43400
{ "PulseAudio", FMOD_OUTPUTTYPE_PULSEAUDIO }, { "PulseAudio", FMOD_OUTPUTTYPE_PULSEAUDIO },
{ "Pulse", FMOD_OUTPUTTYPE_PULSEAUDIO }, { "Pulse", FMOD_OUTPUTTYPE_PULSEAUDIO },
#endif #endif
#if !FMOD_STUDIO
{ "SDL", 666 }, { "SDL", 666 },
#endif
// Mac // Mac
{ "Core Audio", FMOD_OUTPUTTYPE_COREAUDIO }, { "Core Audio", FMOD_OUTPUTTYPE_COREAUDIO },
@ -207,7 +224,7 @@ static const FEnumList SpeakerModeNames[] =
{ "Surround", FMOD_SPEAKERMODE_SURROUND }, { "Surround", FMOD_SPEAKERMODE_SURROUND },
{ "5.1", FMOD_SPEAKERMODE_5POINT1 }, { "5.1", FMOD_SPEAKERMODE_5POINT1 },
{ "7.1", FMOD_SPEAKERMODE_7POINT1 }, { "7.1", FMOD_SPEAKERMODE_7POINT1 },
#if FMOD_VERSION < 0x44000 #if !FMOD_STUDIO && FMOD_VERSION < 0x44000
{ "Prologic", FMOD_SPEAKERMODE_PROLOGIC }, { "Prologic", FMOD_SPEAKERMODE_PROLOGIC },
#endif #endif
{ "1", FMOD_SPEAKERMODE_MONO }, { "1", FMOD_SPEAKERMODE_MONO },
@ -222,7 +239,7 @@ static const FEnumList ResamplerNames[] =
{ "NoInterp", FMOD_DSP_RESAMPLER_NOINTERP }, { "NoInterp", FMOD_DSP_RESAMPLER_NOINTERP },
{ "Linear", FMOD_DSP_RESAMPLER_LINEAR }, { "Linear", FMOD_DSP_RESAMPLER_LINEAR },
// [BL] 64-bit version of FMOD Ex 4.26 crashes with these resamplers. // [BL] 64-bit version of FMOD Ex 4.26 crashes with these resamplers.
#if !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42600 && FMOD_VERSION <= 0x426FF) #if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42600 && FMOD_VERSION <= 0x426FF)
{ "Cubic", FMOD_DSP_RESAMPLER_CUBIC }, { "Cubic", FMOD_DSP_RESAMPLER_CUBIC },
{ "Spline", FMOD_DSP_RESAMPLER_SPLINE }, { "Spline", FMOD_DSP_RESAMPLER_SPLINE },
#endif #endif
@ -237,11 +254,13 @@ static const FEnumList SoundFormatNames[] =
{ "PCM-24", FMOD_SOUND_FORMAT_PCM24 }, { "PCM-24", FMOD_SOUND_FORMAT_PCM24 },
{ "PCM-32", FMOD_SOUND_FORMAT_PCM32 }, { "PCM-32", FMOD_SOUND_FORMAT_PCM32 },
{ "PCM-Float", FMOD_SOUND_FORMAT_PCMFLOAT }, { "PCM-Float", FMOD_SOUND_FORMAT_PCMFLOAT },
#if FMOD_STUDIO && FMOD_VERSION < 0x10700
{ "GCADPCM", FMOD_SOUND_FORMAT_GCADPCM }, { "GCADPCM", FMOD_SOUND_FORMAT_GCADPCM },
{ "IMAADPCM", FMOD_SOUND_FORMAT_IMAADPCM }, { "IMAADPCM", FMOD_SOUND_FORMAT_IMAADPCM },
{ "VAG", FMOD_SOUND_FORMAT_VAG }, { "VAG", FMOD_SOUND_FORMAT_VAG },
{ "XMA", FMOD_SOUND_FORMAT_XMA }, { "XMA", FMOD_SOUND_FORMAT_XMA },
{ "MPEG", FMOD_SOUND_FORMAT_MPEG }, { "MPEG", FMOD_SOUND_FORMAT_MPEG },
#endif
{ NULL, 0 } { NULL, 0 }
}; };
@ -356,10 +375,13 @@ public:
Stream = stream; Stream = stream;
// As this interface is for music, make it super-high priority. // As this interface is for music, make it super-high priority.
#if FMOD_STUDIO
if (FMOD_OK == stream->getDefaults(&frequency, NULL))
stream->setDefaults(frequency, 1);
#else
if (FMOD_OK == stream->getDefaults(&frequency, NULL, NULL, NULL)) if (FMOD_OK == stream->getDefaults(&frequency, NULL, NULL, NULL))
{
stream->setDefaults(frequency, 1, 0, 0); stream->setDefaults(frequency, 1, 0, 0);
} #endif
} }
bool Play(bool looping, float volume) bool Play(bool looping, float volume)
@ -371,21 +393,33 @@ public:
looping = false; looping = false;
} }
Stream->setMode((looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF) | FMOD_SOFTWARE | FMOD_2D); Stream->setMode((looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF) | FMOD_SOFTWARE | FMOD_2D);
#if FMOD_STUDIO
result = Owner->Sys->playSound(Stream,0, true, &Channel);
#else
result = Owner->Sys->playSound(FMOD_CHANNEL_FREE, Stream, true, &Channel); result = Owner->Sys->playSound(FMOD_CHANNEL_FREE, Stream, true, &Channel);
#endif
if (result != FMOD_OK) if (result != FMOD_OK)
{ {
return false; return false;
} }
Channel->setChannelGroup(Owner->MusicGroup); Channel->setChannelGroup(Owner->MusicGroup);
#if FMOD_STUDIO
Channel->setMixLevelsOutput(1, 1, 1, 1, 1, 1, 1, 1);
#else
Channel->setSpeakerMix(1, 1, 1, 1, 1, 1, 1, 1); Channel->setSpeakerMix(1, 1, 1, 1, 1, 1, 1, 1);
#endif
Channel->setVolume(volume); Channel->setVolume(volume);
// Ensure reverb is disabled. // Ensure reverb is disabled.
#if FMOD_STUDIO
Channel->setReverbProperties(0,0.f);
#else
FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, };
if (FMOD_OK == Channel->getReverbProperties(&reverb)) if (FMOD_OK == Channel->getReverbProperties(&reverb))
{ {
reverb.Room = -10000; reverb.Room = -10000;
Channel->setReverbProperties(&reverb); Channel->setReverbProperties(&reverb);
} }
#endif
Channel->setPaused(false); Channel->setPaused(false);
Ended = false; Ended = false;
JustStarted = true; JustStarted = true;
@ -429,7 +463,7 @@ public:
bool is; bool is;
FMOD_OPENSTATE openstate = FMOD_OPENSTATE_MAX; FMOD_OPENSTATE openstate = FMOD_OPENSTATE_MAX;
bool starving; bool starving;
#if FMOD_VERSION >= 0x43400 #if FMOD_STUDIO || FMOD_VERSION >= 0x43400
bool diskbusy; bool diskbusy;
#endif #endif
@ -437,7 +471,7 @@ public:
{ {
return true; return true;
} }
#if FMOD_VERSION < 0x43400 #if !FMOD_STUDIO && FMOD_VERSION < 0x43400
if (FMOD_OK != Stream->getOpenState(&openstate, NULL, &starving)) if (FMOD_OK != Stream->getOpenState(&openstate, NULL, &starving))
#else #else
if (FMOD_OK != Stream->getOpenState(&openstate, NULL, &starving, &diskbusy)) if (FMOD_OK != Stream->getOpenState(&openstate, NULL, &starving, &diskbusy))
@ -526,7 +560,7 @@ public:
unsigned int percentbuffered; unsigned int percentbuffered;
unsigned int position; unsigned int position;
bool starving; bool starving;
#if FMOD_VERSION >= 0x43400 #if FMOD_STUDIO || FMOD_VERSION >= 0x43400
bool diskbusy; bool diskbusy;
#endif #endif
float volume; float volume;
@ -534,7 +568,7 @@ public:
bool paused; bool paused;
bool isplaying; bool isplaying;
#if FMOD_VERSION < 0x43400 #if !FMOD_STUDIO && FMOD_VERSION < 0x43400
if (FMOD_OK == Stream->getOpenState(&openstate, &percentbuffered, &starving)) if (FMOD_OK == Stream->getOpenState(&openstate, &percentbuffered, &starving))
#else #else
if (FMOD_OK == Stream->getOpenState(&openstate, &percentbuffered, &starving, &diskbusy)) if (FMOD_OK == Stream->getOpenState(&openstate, &percentbuffered, &starving, &diskbusy))
@ -710,7 +744,9 @@ bool FMODSoundRenderer::Init()
} }
const char *wrongver = NULL; const char *wrongver = NULL;
#if FMOD_VERSION >= 0x43600 #if FMOD_STUDIO
if (version < (FMOD_VERSION & 0xFFFF00))
#elif FMOD_VERSION >= 0x43600
if (version < 0x43600) if (version < 0x43600)
#else #else
if (version < 0x42000) if (version < 0x42000)
@ -718,7 +754,7 @@ bool FMODSoundRenderer::Init()
{ {
wrongver = "an old"; wrongver = "an old";
} }
#if FMOD_VERSION < 0x42700 #if !FMOD_STUDIO && FMOD_VERSION < 0x42700
else if ((version & 0xFFFF00) > 0x42600) else if ((version & 0xFFFF00) > 0x42600)
#else #else
else if ((version & 0xFFFF00) > (FMOD_VERSION & 0xFFFF00)) else if ((version & 0xFFFF00) > (FMOD_VERSION & 0xFFFF00))
@ -744,7 +780,7 @@ bool FMODSoundRenderer::Init()
Printf("Loaded FMOD version %x.%02x.%02x\n", version >> 16, (version >> 8) & 255, version & 255); Printf("Loaded FMOD version %x.%02x.%02x\n", version >> 16, (version >> 8) & 255, version & 255);
ShowedBanner = true; ShowedBanner = true;
} }
#ifdef _WIN32 #if defined(_WIN32) && !FMOD_STUDIO
if (OSPlatform == os_WinNT4) if (OSPlatform == os_WinNT4)
{ {
// The following was true as of FMOD 3. I don't know if it still // The following was true as of FMOD 3. I don't know if it still
@ -781,7 +817,7 @@ bool FMODSoundRenderer::Init()
} }
#endif #endif
#if !defined _WIN32 && !defined __APPLE__ #if !defined _WIN32 && !defined __APPLE__ && !FMOD_STUDIO
// Try to load SDL output plugin // Try to load SDL output plugin
result = Sys->setPluginPath(progdir); // Should we really look for it in the program directory? result = Sys->setPluginPath(progdir); // Should we really look for it in the program directory?
result = Sys->loadPlugin("liboutput_sdl.so", &OutputPlugin); result = Sys->loadPlugin("liboutput_sdl.so", &OutputPlugin);
@ -812,7 +848,7 @@ bool FMODSoundRenderer::Init()
} }
result = Sys->getNumDrivers(&driver); result = Sys->getNumDrivers(&driver);
#ifdef __unix__ #if defined(__unix__) && !FMOD_STUDIO
if (result == FMOD_OK) if (result == FMOD_OK)
{ {
// On Linux, FMOD defaults to OSS. If OSS is not present, it doesn't // On Linux, FMOD defaults to OSS. If OSS is not present, it doesn't
@ -852,7 +888,11 @@ bool FMODSoundRenderer::Init()
result = Sys->setDriver(driver); result = Sys->setDriver(driver);
} }
result = Sys->getDriver(&driver); result = Sys->getDriver(&driver);
#if FMOD_VERSION >= 0x43600 #if FMOD_STUDIO
// We were built with an FMOD Studio that only returns the control panel frequency
result = Sys->getDriverInfo(driver, nullptr, 0, nullptr, &Driver_MinFrequency, &speakermode, nullptr);
Driver_MaxFrequency = Driver_MinFrequency;
#elif FMOD_VERSION >= 0x43600
// We were built with an FMOD that only returns the control panel frequency // We were built with an FMOD that only returns the control panel frequency
result = Sys->getDriverCaps(driver, &Driver_Caps, &Driver_MinFrequency, &speakermode); result = Sys->getDriverCaps(driver, &Driver_Caps, &Driver_MinFrequency, &speakermode);
Driver_MaxFrequency = Driver_MinFrequency; Driver_MaxFrequency = Driver_MinFrequency;
@ -865,7 +905,9 @@ bool FMODSoundRenderer::Init()
Printf(TEXTCOLOR_BLUE"Could not ascertain driver capabilities. Some things may be weird. (Error %d)\n", result); Printf(TEXTCOLOR_BLUE"Could not ascertain driver capabilities. Some things may be weird. (Error %d)\n", result);
// Fill in some default to pretend it worked. (But as long as we specify a valid driver, // Fill in some default to pretend it worked. (But as long as we specify a valid driver,
// can this call actually fail?) // can this call actually fail?)
#if !FMOD_STUDIO
Driver_Caps = 0; Driver_Caps = 0;
#endif
Driver_MinFrequency = 4000; Driver_MinFrequency = 4000;
Driver_MaxFrequency = 48000; Driver_MaxFrequency = 48000;
speakermode = FMOD_SPEAKERMODE_STEREO; speakermode = FMOD_SPEAKERMODE_STEREO;
@ -877,11 +919,13 @@ bool FMODSoundRenderer::Init()
{ {
speakermode = FMOD_SPEAKERMODE(eval); speakermode = FMOD_SPEAKERMODE(eval);
} }
#if !FMOD_STUDIO
result = Sys->setSpeakerMode(speakermode); result = Sys->setSpeakerMode(speakermode);
if (result != FMOD_OK) if (result != FMOD_OK)
{ {
Printf(TEXTCOLOR_BLUE"Could not set speaker mode to '%s'. (Error %d)\n", *snd_speakermode, result); Printf(TEXTCOLOR_BLUE"Could not set speaker mode to '%s'. (Error %d)\n", *snd_speakermode, result);
} }
#endif
// Set software format // Set software format
eval = Enum_NumForName(SoundFormatNames, snd_output_format); eval = Enum_NumForName(SoundFormatNames, snd_output_format);
@ -902,7 +946,11 @@ bool FMODSoundRenderer::Init()
samplerate = snd_samplerate; samplerate = snd_samplerate;
if (samplerate == 0 || snd_samplerate == 0) if (samplerate == 0 || snd_samplerate == 0)
{ // Creative's ASIO drivers report the only supported frequency as 0! { // Creative's ASIO drivers report the only supported frequency as 0!
#if FMOD_STUDIO
if (FMOD_OK != Sys->getSoftwareFormat(&samplerate, NULL, NULL))
#else
if (FMOD_OK != Sys->getSoftwareFormat(&samplerate, NULL, NULL, NULL, NULL, NULL)) if (FMOD_OK != Sys->getSoftwareFormat(&samplerate, NULL, NULL, NULL, NULL, NULL))
#endif
{ {
samplerate = 48000; samplerate = 48000;
} }
@ -911,12 +959,26 @@ bool FMODSoundRenderer::Init()
{ {
Printf(TEXTCOLOR_BLUE"Sample rate %d is unsupported. Trying %d.\n", *snd_samplerate, samplerate); Printf(TEXTCOLOR_BLUE"Sample rate %d is unsupported. Trying %d.\n", *snd_samplerate, samplerate);
} }
#if FMOD_STUDIO
result = Sys->setSoftwareFormat(samplerate, speakermode, 0);
#else
result = Sys->setSoftwareFormat(samplerate, format, 0, 0, resampler); result = Sys->setSoftwareFormat(samplerate, format, 0, 0, resampler);
#endif
if (result != FMOD_OK) if (result != FMOD_OK)
{ {
Printf(TEXTCOLOR_BLUE"Could not set mixing format. Defaults will be used. (Error %d)\n", result); Printf(TEXTCOLOR_BLUE"Could not set mixing format. Defaults will be used. (Error %d)\n", result);
} }
#if FMOD_STUDIO
FMOD_ADVANCEDSETTINGS advSettings = {};
advSettings.resamplerMethod = resampler;
result = Sys->setAdvancedSettings(&advSettings);
if (result != FMOD_OK)
{
Printf(TEXTCOLOR_BLUE"Could not set resampler method. Defaults will be used. (Error %d)\n", result);
}
#endif
// Set software channels according to snd_channels // Set software channels according to snd_channels
result = Sys->setSoftwareChannels(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS); result = Sys->setSoftwareChannels(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS);
if (result != FMOD_OK) if (result != FMOD_OK)
@ -924,6 +986,7 @@ bool FMODSoundRenderer::Init()
Printf(TEXTCOLOR_BLUE"Failed to set the preferred number of channels. (Error %d)\n", result); Printf(TEXTCOLOR_BLUE"Failed to set the preferred number of channels. (Error %d)\n", result);
} }
#if !FMOD_STUDIO
if (Driver_Caps & FMOD_CAPS_HARDWARE_EMULATED) if (Driver_Caps & FMOD_CAPS_HARDWARE_EMULATED)
{ // The user has the 'Acceleration' slider set to off! { // The user has the 'Acceleration' slider set to off!
// This is really bad for latency! // This is really bad for latency!
@ -931,7 +994,9 @@ bool FMODSoundRenderer::Init()
Printf (TEXTCOLOR_BLUE"Please turn it back on if you want decent sound.\n"); Printf (TEXTCOLOR_BLUE"Please turn it back on if you want decent sound.\n");
result = Sys->setDSPBufferSize(1024, 10); // At 48khz, the latency between issuing an fmod command and hearing it will now be about 213ms. result = Sys->setDSPBufferSize(1024, 10); // At 48khz, the latency between issuing an fmod command and hearing it will now be about 213ms.
} }
else if (snd_buffersize != 0 || snd_buffercount != 0) else
#endif
if (snd_buffersize != 0 || snd_buffercount != 0)
{ {
int buffersize = snd_buffersize ? snd_buffersize : 1024; int buffersize = snd_buffersize ? snd_buffersize : 1024;
int buffercount = snd_buffercount ? snd_buffercount : 4; int buffercount = snd_buffercount ? snd_buffercount : 4;
@ -951,7 +1016,9 @@ bool FMODSoundRenderer::Init()
if (snd_hrtf) if (snd_hrtf)
{ {
// These flags are the same thing, just with different names. // These flags are the same thing, just with different names.
#ifdef FMOD_INIT_SOFTWARE_HRTF #ifdef FMOD_INIT_CHANNEL_LOWPASS
initflags |= FMOD_INIT_CHANNEL_LOWPASS;
#elif defined(FMOD_INIT_SOFTWARE_HRTF)
initflags |= FMOD_INIT_SOFTWARE_HRTF; initflags |= FMOD_INIT_SOFTWARE_HRTF;
#else #else
initflags |= FMOD_INIT_HRTF_LOWPASS; initflags |= FMOD_INIT_HRTF_LOWPASS;
@ -959,7 +1026,11 @@ bool FMODSoundRenderer::Init()
} }
if (snd_profile) if (snd_profile)
{ {
#ifdef FMOD_INIT_PROFILE_ENABLE
initflags |= FMOD_INIT_PROFILE_ENABLE;
#else
initflags |= FMOD_INIT_ENABLE_PROFILE; initflags |= FMOD_INIT_ENABLE_PROFILE;
#endif
} }
for (;;) for (;;)
{ {
@ -970,14 +1041,23 @@ bool FMODSoundRenderer::Init()
// 1. The speaker mode selected isn't supported by this soundcard. Force it to stereo. // 1. The speaker mode selected isn't supported by this soundcard. Force it to stereo.
// 2. The output format is unsupported. Force it to 16-bit PCM. // 2. The output format is unsupported. Force it to 16-bit PCM.
// 3. ??? // 3. ???
#if FMOD_STUDIO
result = Sys->getSoftwareFormat(nullptr, &speakermode, nullptr);
#else
result = Sys->getSpeakerMode(&speakermode); result = Sys->getSpeakerMode(&speakermode);
#endif
if (result == FMOD_OK && if (result == FMOD_OK &&
speakermode != FMOD_SPEAKERMODE_STEREO && speakermode != FMOD_SPEAKERMODE_STEREO &&
#if FMOD_STUDIO
FMOD_OK == Sys->setSoftwareFormat(samplerate, FMOD_SPEAKERMODE_STEREO, 0))
#else
FMOD_OK == Sys->setSpeakerMode(FMOD_SPEAKERMODE_STEREO)) FMOD_OK == Sys->setSpeakerMode(FMOD_SPEAKERMODE_STEREO))
#endif
{ {
Printf(TEXTCOLOR_RED" Buffer creation failed. Retrying with stereo output.\n"); Printf(TEXTCOLOR_RED" Buffer creation failed. Retrying with stereo output.\n");
continue; continue;
} }
#if !FMOD_STUDIO
result = Sys->getSoftwareFormat(&samplerate, &format, NULL, NULL, &resampler, NULL); result = Sys->getSoftwareFormat(&samplerate, &format, NULL, NULL, &resampler, NULL);
if (result == FMOD_OK && if (result == FMOD_OK &&
format != FMOD_SOUND_FORMAT_PCM16 && format != FMOD_SOUND_FORMAT_PCM16 &&
@ -986,11 +1066,21 @@ bool FMODSoundRenderer::Init()
Printf(TEXTCOLOR_RED" Buffer creation failed. Retrying with PCM-16 output.\n"); Printf(TEXTCOLOR_RED" Buffer creation failed. Retrying with PCM-16 output.\n");
continue; continue;
} }
#endif
} }
else if (result == FMOD_ERR_NET_SOCKET_ERROR && (initflags & FMOD_INIT_ENABLE_PROFILE)) else if (result == FMOD_ERR_NET_SOCKET_ERROR &&
#ifdef FMOD_INIT_PROFILE_ENABLE
(initflags & FMOD_INIT_PROFILE_ENABLE))
#else
(initflags & FMOD_INIT_ENABLE_PROFILE))
#endif
{ {
Printf(TEXTCOLOR_RED" Could not create socket. Retrying without profiling.\n"); Printf(TEXTCOLOR_RED" Could not create socket. Retrying without profiling.\n");
#ifdef FMOD_INIT_PROFILE_ENABLE
initflags &= ~FMOD_INIT_PROFILE_ENABLE;
#else
initflags &= ~FMOD_INIT_ENABLE_PROFILE; initflags &= ~FMOD_INIT_ENABLE_PROFILE;
#endif
continue; continue;
} }
#ifdef _WIN32 #ifdef _WIN32
@ -1066,7 +1156,11 @@ bool FMODSoundRenderer::Init()
{ {
FMOD::DSP *sfx_head, *pausable_head; FMOD::DSP *sfx_head, *pausable_head;
#if FMOD_STUDIO
result = SfxGroup->getDSP(FMOD_CHANNELCONTROL_DSP_HEAD, &sfx_head);
#else
result = SfxGroup->getDSPHead(&sfx_head); result = SfxGroup->getDSPHead(&sfx_head);
#endif
if (result == FMOD_OK) if (result == FMOD_OK)
{ {
result = sfx_head->getInput(0, &pausable_head, &SfxConnection); result = sfx_head->getInput(0, &pausable_head, &SfxConnection);
@ -1103,8 +1197,8 @@ bool FMODSoundRenderer::Init()
} }
result = WaterLP->addInput(pausable_head, NULL); result = WaterLP->addInput(pausable_head, NULL);
WaterLP->setActive(false); WaterLP->setActive(false);
WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); WaterLP->setParameterFloat(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp);
WaterLP->setParameter(FMOD_DSP_LOWPASS_RESONANCE, 2); WaterLP->setParameterFloat(FMOD_DSP_LOWPASS_RESONANCE, 2);
if (WaterReverb != NULL) if (WaterReverb != NULL)
{ {
@ -1120,15 +1214,25 @@ bool FMODSoundRenderer::Init()
// These parameters are entirely empirical and can probably // These parameters are entirely empirical and can probably
// stand some improvement, but it sounds remarkably close // stand some improvement, but it sounds remarkably close
// to the old reverb unit's output. // to the old reverb unit's output.
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_LFREFERENCE, 150); #if FMOD_STUDIO
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_HFREFERENCE, 10000); WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_LOWSHELFFREQUENCY, 150);
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_ROOM, 0); #else
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_ROOMHF, -5000); WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_LFREFERENCE, 150);
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DRYLEVEL, 0); #endif
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DECAYHFRATIO, 1); WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_HFREFERENCE, 10000);
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DECAYTIME, 0.25f); #if !FMOD_STUDIO
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DENSITY, 100); WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_ROOM, 0);
WaterReverb->setParameter(FMOD_DSP_SFXREVERB_DIFFUSION, 100); WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_ROOMHF, -5000);
#endif
WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DRYLEVEL, 0);
#if FMOD_STUDIO
WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_HFDECAYRATIO, 100);
#else
WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DECAYHFRATIO, 1);
#endif
WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DECAYTIME, 0.25f);
WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DENSITY, 100);
WaterReverb->setParameterFloat(FMOD_DSP_SFXREVERB_DIFFUSION, 100);
WaterReverb->setActive(false); WaterReverb->setActive(false);
} }
} }
@ -1154,7 +1258,11 @@ bool FMODSoundRenderer::Init()
{ {
FMOD::DSP *master_head; FMOD::DSP *master_head;
#if FMOD_STUDIO
result = master_group->getDSP(FMOD_CHANNELCONTROL_DSP_HEAD, &master_head);
#else
result = master_group->getDSPHead(&master_head); result = master_group->getDSPHead(&master_head);
#endif
if (result == FMOD_OK) if (result == FMOD_OK)
{ {
result = master_head->getOutput(0, &ChannelGroupTargetUnit, NULL); result = master_head->getOutput(0, &ChannelGroupTargetUnit, NULL);
@ -1174,7 +1282,11 @@ bool FMODSoundRenderer::Init()
} }
} }
#if FMOD_STUDIO
if (FMOD_OK != Sys->getSoftwareFormat(&OutputRate, NULL, NULL))
#else
if (FMOD_OK != Sys->getSoftwareFormat(&OutputRate, NULL, NULL, NULL, NULL, NULL)) if (FMOD_OK != Sys->getSoftwareFormat(&OutputRate, NULL, NULL, NULL, NULL, NULL))
#endif
{ {
OutputRate = 48000; // Guess, but this should never happen. OutputRate = 48000; // Guess, but this should never happen.
} }
@ -1272,20 +1384,35 @@ void FMODSoundRenderer::PrintStatus()
{ {
Printf ("Output type: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(OutputNames, output)); Printf ("Output type: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(OutputNames, output));
} }
#if FMOD_STUDIO
if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &speakermode, nullptr))
{
Printf ("Speaker mode: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(SpeakerModeNames, speakermode));
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate);
}
#else
if (FMOD_OK == Sys->getSpeakerMode(&speakermode)) if (FMOD_OK == Sys->getSpeakerMode(&speakermode))
{ {
Printf ("Speaker mode: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(SpeakerModeNames, speakermode)); Printf ("Speaker mode: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(SpeakerModeNames, speakermode));
} }
#endif
if (FMOD_OK == Sys->getDriver(&driver)) if (FMOD_OK == Sys->getDriver(&driver))
{ {
char name[256]; char name[256];
#if FMOD_STUDIO
if (FMOD_OK != Sys->getDriverInfo(driver, name, sizeof(name), nullptr, nullptr, nullptr, nullptr))
#else
if (FMOD_OK != Sys->getDriverInfo(driver, name, sizeof(name), NULL)) if (FMOD_OK != Sys->getDriverInfo(driver, name, sizeof(name), NULL))
#endif
{ {
strcpy(name, "Unknown"); strcpy(name, "Unknown");
} }
Printf ("Driver: " TEXTCOLOR_GREEN "%d" TEXTCOLOR_NORMAL " (" TEXTCOLOR_ORANGE "%s" TEXTCOLOR_NORMAL ")\n", driver, name); Printf ("Driver: " TEXTCOLOR_GREEN "%d" TEXTCOLOR_NORMAL " (" TEXTCOLOR_ORANGE "%s" TEXTCOLOR_NORMAL ")\n", driver, name);
#if !FMOD_STUDIO
DumpDriverCaps(Driver_Caps, Driver_MinFrequency, Driver_MaxFrequency); DumpDriverCaps(Driver_Caps, Driver_MinFrequency, Driver_MaxFrequency);
#endif
} }
#if !FMOD_STUDIO
if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &format, &numoutputchannels, NULL, &resampler, NULL)) if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &format, &numoutputchannels, NULL, &resampler, NULL))
{ {
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate); Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate);
@ -1293,6 +1420,7 @@ void FMODSoundRenderer::PrintStatus()
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer channels: " TEXTCOLOR_GREEN "%d\n", numoutputchannels); Printf (TEXTCOLOR_LIGHTBLUE "Software mixer channels: " TEXTCOLOR_GREEN "%d\n", numoutputchannels);
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer resampler: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(ResamplerNames, resampler)); Printf (TEXTCOLOR_LIGHTBLUE "Software mixer resampler: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(ResamplerNames, resampler));
} }
#endif
if (FMOD_OK == Sys->getDSPBufferSize(&bufferlength, &numbuffers)) if (FMOD_OK == Sys->getDSPBufferSize(&bufferlength, &numbuffers))
{ {
Printf (TEXTCOLOR_LIGHTBLUE "DSP buffers: " TEXTCOLOR_GREEN "%u samples x %d\n", bufferlength, numbuffers); Printf (TEXTCOLOR_LIGHTBLUE "DSP buffers: " TEXTCOLOR_GREEN "%u samples x %d\n", bufferlength, numbuffers);
@ -1305,6 +1433,7 @@ void FMODSoundRenderer::PrintStatus()
// //
//========================================================================== //==========================================================================
#if !FMOD_STUDIO
void FMODSoundRenderer::DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency) void FMODSoundRenderer::DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency)
{ {
Printf (TEXTCOLOR_OLIVE " Min. frequency: " TEXTCOLOR_GREEN "%d\n", minfrequency); Printf (TEXTCOLOR_OLIVE " Min. frequency: " TEXTCOLOR_GREEN "%d\n", minfrequency);
@ -1325,6 +1454,7 @@ void FMODSoundRenderer::DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int max
} }
if (caps & FMOD_CAPS_REVERB_LIMITED) Printf(TEXTCOLOR_OLIVE " Limited reverb\n"); if (caps & FMOD_CAPS_REVERB_LIMITED) Printf(TEXTCOLOR_OLIVE " Limited reverb\n");
} }
#endif
//========================================================================== //==========================================================================
// //
@ -1342,7 +1472,11 @@ void FMODSoundRenderer::PrintDriversList()
{ {
for (i = 0; i < numdrivers; ++i) for (i = 0; i < numdrivers; ++i)
{ {
#if FMOD_STUDIO
if (FMOD_OK == Sys->getDriverInfo(i, name, sizeof(name), nullptr, nullptr, nullptr, nullptr))
#else
if (FMOD_OK == Sys->getDriverInfo(i, name, sizeof(name), NULL)) if (FMOD_OK == Sys->getDriverInfo(i, name, sizeof(name), NULL))
#endif
{ {
Printf("%d. %s\n", i, name); Printf("%d. %s\n", i, name);
} }
@ -1365,7 +1499,7 @@ FString FMODSoundRenderer::GatherStats()
channels = 0; channels = 0;
total = update = geometry = stream = dsp = 0; total = update = geometry = stream = dsp = 0;
Sys->getChannelsPlaying(&channels); Sys->getChannelsPlaying(&channels);
#if FMOD_VERSION >= 0x42501 #if FMOD_STUDIO || FMOD_VERSION >= 0x42501
// We were built with an FMOD with the geometry parameter. // We were built with an FMOD with the geometry parameter.
if (ActiveFMODVersion >= 0x42501) if (ActiveFMODVersion >= 0x42501)
{ // And we are running with an FMOD that includes it. { // And we are running with an FMOD that includes it.
@ -1612,7 +1746,11 @@ static void SetCustomLoopPts(FMOD::Sound *sound)
// //
//========================================================================== //==========================================================================
#if FMOD_STUDIO
static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, unsigned int *filesize, void **handle, void *userdata)
#else
static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata) static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata)
#endif
{ {
FileReader *reader = NULL; FileReader *reader = NULL;
if(sscanf(name, "_FileReader_%p", &reader) != 1) if(sscanf(name, "_FileReader_%p", &reader) != 1)
@ -1623,7 +1761,9 @@ static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode
*filesize = reader->GetLength(); *filesize = reader->GetLength();
*handle = reader; *handle = reader;
#if !FMOD_STUDIO
*userdata = reader; *userdata = reader;
#endif
return FMOD_OK; return FMOD_OK;
} }
@ -1667,10 +1807,17 @@ SoundStream *FMODSoundRenderer::OpenStream(FileReader *reader, int flags)
FString name; FString name;
InitCreateSoundExInfo(&exinfo); InitCreateSoundExInfo(&exinfo);
#if FMOD_STUDIO
exinfo.fileuseropen = open_reader_callback;
exinfo.fileuserclose = close_reader_callback;
exinfo.fileuserread = read_reader_callback;
exinfo.fileuserseek = seek_reader_callback;
#else
exinfo.useropen = open_reader_callback; exinfo.useropen = open_reader_callback;
exinfo.userclose = close_reader_callback; exinfo.userclose = close_reader_callback;
exinfo.userread = read_reader_callback; exinfo.userread = read_reader_callback;
exinfo.userseek = seek_reader_callback; exinfo.userseek = seek_reader_callback;
#endif
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM; mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
if(flags & SoundStream::Loop) if(flags & SoundStream::Loop)
@ -1775,7 +1922,11 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi
FMOD::Channel *chan; FMOD::Channel *chan;
float freq; float freq;
#if FMOD_STUDIO
if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&freq, NULL))
#else
if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&freq, NULL, NULL, NULL)) if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&freq, NULL, NULL, NULL))
#endif
{ {
freq = PITCH(freq, pitch); freq = PITCH(freq, pitch);
} }
@ -1785,7 +1936,11 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi
} }
GRolloff = NULL; // Do 2D sounds need rolloff? GRolloff = NULL; // Do 2D sounds need rolloff?
#if FMOD_STUDIO
result = Sys->playSound((FMOD::Sound *)sfx.data, (flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx, true, &chan);
#else
result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx.data, true, &chan); result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx.data, true, &chan);
#endif
if (FMOD_OK == result) if (FMOD_OK == result)
{ {
result = chan->getMode(&mode); result = chan->getMode(&mode);
@ -1809,7 +1964,9 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi
mode |= FMOD_LOOP_OFF; mode |= FMOD_LOOP_OFF;
} }
chan->setMode(mode); chan->setMode(mode);
#if !FMOD_STUDIO
chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx); chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx);
#endif
if (freq != 0) if (freq != 0)
{ {
chan->setFrequency(freq); chan->setFrequency(freq);
@ -1822,12 +1979,16 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi
} }
if (flags & SNDF_NOREVERB) if (flags & SNDF_NOREVERB)
{ {
#if FMOD_STUDIO
chan->setReverbProperties(0,0.f);
#else
FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, };
if (FMOD_OK == chan->getReverbProperties(&reverb)) if (FMOD_OK == chan->getReverbProperties(&reverb))
{ {
reverb.Room = -10000; reverb.Room = -10000;
chan->setReverbProperties(&reverb); chan->setReverbProperties(&reverb);
} }
#endif
} }
chan->setPaused(false); chan->setPaused(false);
return CommonChannelSetup(chan, reuse_chan); return CommonChannelSetup(chan, reuse_chan);
@ -1852,15 +2013,26 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
FMOD_MODE mode; FMOD_MODE mode;
FMOD::Channel *chan; FMOD::Channel *chan;
float freq; float freq;
float def_freq, def_vol, def_pan; float def_freq;
#if !FMOD_STUDIO
float def_vol, def_pan;
#endif
int numchans; int numchans;
int def_priority; int def_priority;
#if FMOD_STUDIO
if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&def_freq, &def_priority))
#else
if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&def_freq, &def_vol, &def_pan, &def_priority)) if (FMOD_OK == ((FMOD::Sound *)sfx.data)->getDefaults(&def_freq, &def_vol, &def_pan, &def_priority))
#endif
{ {
freq = PITCH(def_freq, pitch); freq = PITCH(def_freq, pitch);
// Change the sound's default priority before playing it. // Change the sound's default priority before playing it.
#if FMOD_STUDIO
((FMOD::Sound *)sfx.data)->setDefaults(def_freq, clamp(def_priority - priority, 1, 256));
#else
((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_vol, def_pan, clamp(def_priority - priority, 1, 256)); ((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_vol, def_pan, clamp(def_priority - priority, 1, 256));
#endif
} }
else else
{ {
@ -1876,12 +2048,20 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
// as long as the parameters are set properly. It will first try to kick out sounds // as long as the parameters are set properly. It will first try to kick out sounds
// with the same priority level but has no problem with kicking out sounds at // with the same priority level but has no problem with kicking out sounds at
// higher priority levels if it needs to. // higher priority levels if it needs to.
#if FMOD_STUDIO
result = Sys->playSound((FMOD::Sound *)sfx.data, (flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx, true, &chan);
#else
result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx.data, true, &chan); result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx.data, true, &chan);
#endif
// Then set the priority back. // Then set the priority back.
if (def_priority >= 0) if (def_priority >= 0)
{ {
#if FMOD_STUDIO
((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_priority);
#else
((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_vol, def_pan, def_priority); ((FMOD::Sound *)sfx.data)->setDefaults(def_freq, def_vol, def_pan, def_priority);
#endif
} }
if (FMOD_OK == result) if (FMOD_OK == result)
@ -1906,7 +2086,9 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
} }
mode = SetChanHeadSettings(listener, chan, pos, !!(flags & SNDF_AREA), mode); mode = SetChanHeadSettings(listener, chan, pos, !!(flags & SNDF_AREA), mode);
chan->setMode(mode); chan->setMode(mode);
#if !FMOD_STUDIO
chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx); chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx);
#endif
if (mode & FMOD_3D) if (mode & FMOD_3D)
{ {
@ -1941,12 +2123,16 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
} }
if (flags & SNDF_NOREVERB) if (flags & SNDF_NOREVERB)
{ {
#if FMOD_STUDIO
chan->setReverbProperties(0,0.f);
#else
FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, }; FMOD_REVERB_CHANNELPROPERTIES reverb = { 0, };
if (FMOD_OK == chan->getReverbProperties(&reverb)) if (FMOD_OK == chan->getReverbProperties(&reverb))
{ {
reverb.Room = -10000; reverb.Room = -10000;
chan->setReverbProperties(&reverb); chan->setReverbProperties(&reverb);
} }
#endif
} }
chan->setPaused(false); chan->setPaused(false);
chan->getPriority(&def_priority); chan->getPriority(&def_priority);
@ -1970,7 +2156,14 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
void FMODSoundRenderer::MarkStartTime(FISoundChannel *chan) void FMODSoundRenderer::MarkStartTime(FISoundChannel *chan)
{ {
#if FMOD_STUDIO
unsigned long long int dsp_time;
((FMOD::Channel *)chan->SysChannel)->getDSPClock(&dsp_time,NULL);
chan->StartTime.Lo = dsp_time & 0xFFFFFFFF;
chan->StartTime.Hi = dsp_time >> 32;
#else
Sys->getDSPClock(&chan->StartTime.Hi, &chan->StartTime.Lo); Sys->getDSPClock(&chan->StartTime.Hi, &chan->StartTime.Lo);
#endif
} }
//========================================================================== //==========================================================================
@ -1990,7 +2183,14 @@ bool FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FISoundChannel *
{ // Sound is being restarted, so seek it to the position { // Sound is being restarted, so seek it to the position
// it would be in now if it had never been evicted. // it would be in now if it had never been evicted.
QWORD_UNION nowtime; QWORD_UNION nowtime;
#if FMOD_STUDIO
unsigned long long int delay;
chan->getDelay(&delay,NULL,NULL);
nowtime.Lo = delay & 0xFFFFFFFF;
nowtime.Hi = delay >> 32;
#else
chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &nowtime.Hi, &nowtime.Lo); chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &nowtime.Hi, &nowtime.Lo);
#endif
// If abstime is set, the sound is being restored, and // If abstime is set, the sound is being restored, and
// the channel's start time is actually its seek position. // the channel's start time is actually its seek position.
@ -2078,14 +2278,24 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(SoundListener *listener, FMOD::
{ // Beyond interp_range: Normal 3D panning. { // Beyond interp_range: Normal 3D panning.
level = 1; level = 1;
} }
#if FMOD_STUDIO
if (chan->get3DLevel(&old_level) == FMOD_OK && old_level != level)
{ // Only set it if it's different.
chan->set3DLevel(level);
#else
if (chan->get3DPanLevel(&old_level) == FMOD_OK && old_level != level) if (chan->get3DPanLevel(&old_level) == FMOD_OK && old_level != level)
{ // Only set it if it's different. { // Only set it if it's different.
chan->set3DPanLevel(level); chan->set3DPanLevel(level);
#endif
if (level < 1) if (level < 1)
{ // Let the noise come from all speakers, not just the front ones. { // Let the noise come from all speakers, not just the front ones.
// A centered 3D sound does not play at full volume, so neither should the 2D-panned one. // A centered 3D sound does not play at full volume, so neither should the 2D-panned one.
// This is sqrt(0.5), which is the result for a centered equal power panning. // This is sqrt(0.5), which is the result for a centered equal power panning.
#if FMOD_STUDIO
chan->setMixLevelsOutput(0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f);
#else
chan->setSpeakerMix(0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f); chan->setSpeakerMix(0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f,0.70711f);
#endif
} }
} }
return oldmode; return oldmode;
@ -2119,7 +2329,14 @@ FISoundChannel *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan, FISou
else else
{ {
schan = S_GetChannel(chan); schan = S_GetChannel(chan);
#if FMOD_STUDIO
unsigned long long int time;
chan->getDelay(&time,NULL,NULL);
schan->StartTime.Lo = time & 0xFFFFFFFF;
schan->StartTime.Hi = time >> 32;
#else
chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &schan->StartTime.Hi, &schan->StartTime.Lo); chan->getDelay(FMOD_DELAYTYPE_DSPCLOCK_START, &schan->StartTime.Hi, &schan->StartTime.Lo);
#endif
} }
chan->setUserData(schan); chan->setUserData(schan);
chan->setCallback(ChannelCallback); chan->setCallback(ChannelCallback);
@ -2369,7 +2586,7 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener)
if (LastWaterLP != snd_waterlp) if (LastWaterLP != snd_waterlp)
{ {
LastWaterLP = snd_waterlp; LastWaterLP = snd_waterlp;
WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); WaterLP->setParameterFloat(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp);
} }
WaterLP->setActive(true); WaterLP->setActive(true);
if (WaterReverb != NULL && snd_waterreverb) if (WaterReverb != NULL && snd_waterreverb)
@ -2481,7 +2698,14 @@ void FMODSoundRenderer::Sync(bool sync)
if (sync) if (sync)
{ {
Sys->lockDSP(); Sys->lockDSP();
#if FMOD_STUDIO
unsigned long long int clock;
SfxGroup->getDSPClock(&clock,NULL);
DSPClock.Lo = clock & 0xFFFFFFFF;
DSPClock.Hi = clock >> 32;
#else
Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo); Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo);
#endif
} }
else else
{ {
@ -2499,7 +2723,14 @@ void FMODSoundRenderer::UpdateSounds()
{ {
// Any sounds played between now and the next call to this function // Any sounds played between now and the next call to this function
// will start exactly one tic from now. // will start exactly one tic from now.
#if FMOD_STUDIO
unsigned long long int clock;
SfxGroup->getDSPClock(&clock,NULL);
DSPClock.Lo = clock & 0xFFFFFFFF;
DSPClock.Hi = clock >> 32;
#else
Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo); Sys->getDSPClock(&DSPClock.Hi, &DSPClock.Lo);
#endif
DSPClock.AsOne += OutputRate / TICRATE; DSPClock.AsOne += OutputRate / TICRATE;
Sys->update(); Sys->update();
} }
@ -2673,18 +2904,34 @@ unsigned int FMODSoundRenderer::GetSampleLength(SoundHandle sfx)
//========================================================================== //==========================================================================
FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelCallback FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelCallback
#if FMOD_STUDIO
(FMOD_CHANNELCONTROL *channel, FMOD_CHANNELCONTROL_TYPE controltype, FMOD_CHANNELCONTROL_CALLBACK_TYPE type, void *data1, void *data2)
#else
(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *data1, void *data2) (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *data1, void *data2)
#endif
{ {
#if FMOD_STUDIO
FMOD::ChannelControl *chan = (FMOD::ChannelControl *)channel;
#else
FMOD::Channel *chan = (FMOD::Channel *)channel; FMOD::Channel *chan = (FMOD::Channel *)channel;
#endif
FISoundChannel *schan; FISoundChannel *schan;
if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL) if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL)
{ {
#if FMOD_STUDIO
if (type == FMOD_CHANNELCONTROL_CALLBACK_END)
#else
if (type == FMOD_CHANNEL_CALLBACKTYPE_END) if (type == FMOD_CHANNEL_CALLBACKTYPE_END)
#endif
{ {
S_ChannelEnded(schan); S_ChannelEnded(schan);
} }
#if FMOD_STUDIO
else if (type == FMOD_CHANNELCONTROL_CALLBACK_VIRTUALVOICE)
#else
else if (type == FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE) else if (type == FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE)
#endif
{ {
S_ChannelVirtualChanged(schan, data1 != 0); S_ChannelVirtualChanged(schan, data1 != 0);
} }
@ -2701,9 +2948,17 @@ FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelCallback
// //
//========================================================================== //==========================================================================
#if FMOD_STUDIO
float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNELCONTROL *channel, float distance)
#else
float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNEL *channel, float distance) float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNEL *channel, float distance)
#endif
{ {
#if FMOD_STUDIO
FMOD::ChannelControl *chan = (FMOD::ChannelControl *)channel;
#else
FMOD::Channel *chan = (FMOD::Channel *)channel; FMOD::Channel *chan = (FMOD::Channel *)channel;
#endif
FISoundChannel *schan; FISoundChannel *schan;
if (GRolloff != NULL) if (GRolloff != NULL)
@ -2742,7 +2997,11 @@ void FMODSoundRenderer::DrawWaveDebug(int mode)
const spk *labels; const spk *labels;
int labelcount; int labelcount;
#if FMOD_STUDIO
if (FMOD_OK != Sys->getSoftwareFormat(NULL, NULL, &numoutchans))
#else
if (FMOD_OK != Sys->getSoftwareFormat(NULL, NULL, &numoutchans, NULL, NULL, NULL)) if (FMOD_OK != Sys->getSoftwareFormat(NULL, NULL, &numoutchans, NULL, NULL, NULL))
#endif
{ {
return; return;
} }
@ -2866,12 +3125,14 @@ int FMODSoundRenderer::DrawChannelGroupWaveData(FMOD::ChannelGroup *group, float
int drawn = 0; int drawn = 0;
int x = 16; int x = 16;
#if !FMOD_STUDIO
while (FMOD_OK == group->getWaveData(wavearray, width, drawn)) while (FMOD_OK == group->getWaveData(wavearray, width, drawn))
{ {
drawn++; drawn++;
DrawWave(wavearray, x, y, width, height); DrawWave(wavearray, x, y, width, height);
x += (width + 16) << int(skip); x += (width + 16) << int(skip);
} }
#endif
if (drawn) if (drawn)
{ {
y += height + 16; y += height + 16;
@ -2893,12 +3154,14 @@ int FMODSoundRenderer::DrawSystemWaveData(float *wavearray, int width, int heigh
int drawn = 0; int drawn = 0;
int x = 16; int x = 16;
#if !FMOD_STUDIO
while (FMOD_OK == Sys->getWaveData(wavearray, width, drawn)) while (FMOD_OK == Sys->getWaveData(wavearray, width, drawn))
{ {
drawn++; drawn++;
DrawWave(wavearray, x, y, width, height); DrawWave(wavearray, x, y, width, height);
x += (width + 16) << int(skip); x += (width + 16) << int(skip);
} }
#endif
if (drawn) if (drawn)
{ {
y += height + 16; y += height + 16;
@ -2970,12 +3233,15 @@ int FMODSoundRenderer::DrawChannelGroupSpectrum(FMOD::ChannelGroup *group, float
{ {
x += width + 16; x += width + 16;
} }
// TODO: FMOD Studio: Grab from DSP
#if !FMOD_STUDIO
while (FMOD_OK == group->getSpectrum(spectrumarray, SPECTRUM_SIZE, drawn, FMOD_DSP_FFT_WINDOW_TRIANGLE)) while (FMOD_OK == group->getSpectrum(spectrumarray, SPECTRUM_SIZE, drawn, FMOD_DSP_FFT_WINDOW_TRIANGLE))
{ {
drawn++; drawn++;
DrawSpectrum(spectrumarray, x, y, width, height); DrawSpectrum(spectrumarray, x, y, width, height);
x += (width + 16) << int(skip); x += (width + 16) << int(skip);
} }
#endif
if (drawn) if (drawn)
{ {
y += height + 16; y += height + 16;
@ -3001,12 +3267,15 @@ int FMODSoundRenderer::DrawSystemSpectrum(float *spectrumarray, int width, int h
{ {
x += width + 16; x += width + 16;
} }
// TODO: FMOD Studio: Grab from DSP
#if !FMOD_STUDIO
while (FMOD_OK == Sys->getSpectrum(spectrumarray, SPECTRUM_SIZE, drawn, FMOD_DSP_FFT_WINDOW_TRIANGLE)) while (FMOD_OK == Sys->getSpectrum(spectrumarray, SPECTRUM_SIZE, drawn, FMOD_DSP_FFT_WINDOW_TRIANGLE))
{ {
drawn++; drawn++;
DrawSpectrum(spectrumarray, x, y, width, height); DrawSpectrum(spectrumarray, x, y, width, height);
x += (width + 16) << int(skip); x += (width + 16) << int(skip);
} }
#endif
if (drawn) if (drawn)
{ {
y += height + 16; y += height + 16;
@ -3121,7 +3390,7 @@ short *FMODSoundRenderer::DecodeSample(int outlen, const void *coded, int sizeby
void FMODSoundRenderer::InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) const void FMODSoundRenderer::InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) const
{ {
memset(exinfo, 0, sizeof(*exinfo)); memset(exinfo, 0, sizeof(*exinfo));
#if FMOD_VERSION >= 0x42600 && FMOD_VERSION < 0x43800 #if !FMOD_STUDIO && FMOD_VERSION >= 0x42600 && FMOD_VERSION < 0x43800
if (ActiveFMODVersion < 0x42600) if (ActiveFMODVersion < 0x42600)
{ {
// This parameter was added for 4.26.00, and trying to pass it to older // This parameter was added for 4.26.00, and trying to pass it to older
@ -3145,13 +3414,32 @@ void FMODSoundRenderer::InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) co
FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES *props) FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES *props)
{ {
#if FMOD_VERSION < 0x43600 #if !FMOD_STUDIO && FMOD_VERSION < 0x43600
return Sys->setReverbProperties((const FMOD_REVERB_PROPERTIES *)props); return Sys->setReverbProperties((const FMOD_REVERB_PROPERTIES *)props);
#else #else
// The reverb format changed when hardware mixing support was dropped, because // The reverb format changed when hardware mixing support was dropped, because
// all EAX-only properties were removed from the structure. // all EAX-only properties were removed from the structure.
FMOD_REVERB_PROPERTIES fr; FMOD_REVERB_PROPERTIES fr;
#if FMOD_STUDIO
const float LateEarlyRatio = powf(10.f, (props->Reverb - props->Reflections)/2000.f);
const float EarlyAndLatePower = powf(10.f, props->Reflections/1000.f) + powf(10, props->Reverb/1000.f);
const float HFGain = powf(10.f, props->RoomHF/2000.f);
fr.DecayTime = props->DecayTime*1000.f;
fr.EarlyDelay = props->ReflectionsDelay*1000.f;
fr.LateDelay = props->ReverbDelay*1000.f;
fr.HFReference = props->HFReference;
fr.HFDecayRatio = clamp<float>(props->DecayHFRatio*100.f, 0.f, 100.f);
fr.Diffusion = props->Diffusion;
fr.Density = props->Density;
fr.LowShelfFrequency = props->DecayLFRatio;
fr.LowShelfGain = clamp<float>(props->RoomLF/100.f, -48.f, 12.f);
fr.HighCut = clamp<float>(props->RoomLF < 0 ? props->HFReference/sqrtf((1.f-HFGain)/HFGain) : 20000.f, 20.f, 20000.f);
fr.EarlyLateMix = props->Reflections > -10000.f ? LateEarlyRatio/(LateEarlyRatio + 1)*100.f : 100.f;
fr.WetLevel = clamp<float>(10*log10f(EarlyAndLatePower)+props->Room/100.f, -80.f, 20.f);
return Sys->setReverbProperties(0, &fr);
#else
fr.Instance = props->Instance; fr.Instance = props->Instance;
fr.Environment = props->Environment; fr.Environment = props->Environment;
fr.EnvDiffusion = props->EnvDiffusion; fr.EnvDiffusion = props->EnvDiffusion;
@ -3175,6 +3463,7 @@ FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES
return Sys->setReverbProperties(&fr); return Sys->setReverbProperties(&fr);
#endif #endif
#endif
} }
#endif // NO_FMOD #endif // NO_FMOD

View file

@ -76,8 +76,13 @@ private:
QWORD_UNION DSPClock; QWORD_UNION DSPClock;
int OutputRate; int OutputRate;
#if FMOD_STUDIO
static FMOD_RESULT F_CALLBACK ChannelCallback(FMOD_CHANNELCONTROL *channel, FMOD_CHANNELCONTROL_TYPE controltype, FMOD_CHANNELCONTROL_CALLBACK_TYPE type, void *data1, void *data2);
static float F_CALLBACK RolloffCallback(FMOD_CHANNELCONTROL *channel, float distance);
#else
static FMOD_RESULT F_CALLBACK ChannelCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *data1, void *data2); static FMOD_RESULT F_CALLBACK ChannelCallback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *data1, void *data2);
static float F_CALLBACK RolloffCallback(FMOD_CHANNEL *channel, float distance); static float F_CALLBACK RolloffCallback(FMOD_CHANNEL *channel, float distance);
#endif
bool HandleChannelDelay(FMOD::Channel *chan, FISoundChannel *reuse_chan, int flags, float freq) const; bool HandleChannelDelay(FMOD::Channel *chan, FISoundChannel *reuse_chan, int flags, float freq) const;
FISoundChannel *CommonChannelSetup(FMOD::Channel *chan, FISoundChannel *reuse_chan) const; FISoundChannel *CommonChannelSetup(FMOD::Channel *chan, FISoundChannel *reuse_chan) const;
@ -89,7 +94,9 @@ private:
bool Init (); bool Init ();
void Shutdown (); void Shutdown ();
#if !FMOD_STUDIO
void DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency); void DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency);
#endif
int DrawChannelGroupOutput(FMOD::ChannelGroup *group, float *wavearray, int width, int height, int y, int mode); int DrawChannelGroupOutput(FMOD::ChannelGroup *group, float *wavearray, int width, int height, int y, int mode);
int DrawSystemOutput(float *wavearray, int width, int height, int y, int mode); int DrawSystemOutput(float *wavearray, int width, int height, int y, int mode);
@ -121,7 +128,9 @@ private:
// Just for snd_status display // Just for snd_status display
int Driver_MinFrequency; int Driver_MinFrequency;
int Driver_MaxFrequency; int Driver_MaxFrequency;
#if !FMOD_STUDIO
FMOD_CAPS Driver_Caps; FMOD_CAPS Driver_Caps;
#endif
friend class FMODStreamCapsule; friend class FMODStreamCapsule;
}; };