Merge pull request #1730 from marauder2k9-torque/SFXSystem-Refactor

Sfx system refactor
This commit is contained in:
Brian Roberts 2026-05-24 11:40:50 -05:00 committed by GitHub
commit dae2a7714f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 3710 additions and 7727 deletions

View file

@ -197,22 +197,44 @@ add_subdirectory(squish ${TORQUE_LIB_TARG_DIRECTORY}/squish EXCLUDE_FROM_ALL)
add_subdirectory(collada ${TORQUE_LIB_TARG_DIRECTORY}/collada EXCLUDE_FROM_ALL)
add_subdirectory(glad ${TORQUE_LIB_TARG_DIRECTORY}/glad EXCLUDE_FROM_ALL)
set(ALSOFT_REQUIRE_LINUX OFF)
set(ALSOFT_REQUIRE_WINDOWS OFF)
set(ALSOFT_REQUIRE_WINDOWS_NOT_UWP OFF)
set(ALSOFT_REQUIRE_APPLE OFF)
set(ALSOFT_CPUEXT_NEON OFF)
if(UNIX AND NOT APPLE)
set(ALSOFT_REQUIRE_LINUX ON)
endif()
if(WIN32)
set(ALSOFT_REQUIRE_WINDOWS ON)
endif()
if(APPLE)
set(ALSOFT_REQUIRE_APPLE ON)
endif()
#hidden options
if(TORQUE_SFX_OPENAL)
advanced_option(TORQUE_OGGVORBIS "Enable OGG Vorbis" ON)
advanced_option(ALSOFT_EAX "Enable legacy EAX extensions" ${WIN32})
advanced_option(ALSOFT_UPDATE_BUILD_VERSION "Update git build version info" ON)
mark_as_advanced(ALSOFT_BACKEND_COREAUDIO)
advanced_option(ALSOFT_BACKEND_DSOUND "Enable DirectSound backend" OFF)
advanced_option(ALSOFT_BACKEND_ALSA "Enable ALSA Backend" ${ALSOFT_REQUIRE_LINUX})
advanced_option(ALSOFT_REQUIRE_ALSA "Require ALSA Backend" ${ALSOFT_REQUIRE_LINUX})
advanced_option(ALSOFT_BACKEND_DSOUND "Enable DirectSound backend" ${ALSOFT_REQUIRE_WINDOWS})
advanced_option(ALSOFT_REQUIRE_DSOUND "Require DirectSound Backend" ${ALSOFT_REQUIRE_WINDOWS})
advanced_option(ALSOFT_BACKEND_JACK "Enable Jack backend" OFF)
advanced_option(ALSOFT_BACKEND_OBOE "Enable OBOE backend" OFF)
advanced_option(ALSOFT_BACKEND_OPENSL "Enable OpenSL backend" OFF)
advanced_option(ALSOFT_BACKEND_PIPEWIRE "Enable PipeWire backend" OFF)
advanced_option(ALSOFT_BACKEND_PORTAUDIO "Enable PortAudio backend" OFF)
advanced_option(ALSOFT_BACKEND_PULSEAUDIO "Enable PulseAudio backend" OFF)
advanced_option(ALSOFT_BACKEND_SDL2 "Use SDL2 Backend" ON)
advanced_option(ALSOFT_BACKEND_WASAPI "Enable WASAPI backend" OFF)
advanced_option(ALSOFT_BACKEND_WAVE "Enable Wave backend" OFF)
advanced_option(ALSOFT_BACKEND_SDL2 "Use SDL2 Backend" OFF)
advanced_option(ALSOFT_BACKEND_COREAUDIO "Enable CoreAudio backend" ${ALSOFT_REQUIRE_APPLE})
advanced_option(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" ${ALSOFT_REQUIRE_APPLE})
advanced_option(ALSOFT_BACKEND_WASAPI "Enable WASAPI backend" ${ALSOFT_REQUIRE_WINDOWS})
advanced_option(ALSOFT_REQUIRE_WASAPI "Require WASAPI backend" ${ALSOFT_REQUIRE_WINDOWS})
advanced_option(ALSOFT_BACKEND_WAVE "Enable Wave backend" ON)
advanced_option(ALSOFT_BACKEND_WINMM "Enable WinMM backend" OFF)
mark_as_advanced(ALSOFT_BUILD_ROUTER)
mark_as_advanced(ALSOFT_CPUEXT_NEON)
@ -232,8 +254,6 @@ if(TORQUE_SFX_OPENAL)
advanced_option(ALSOFT_INSTALL_UTILS "Install utility programs (openal-info, alsoft-config, ...)" OFF)
mark_as_advanced(ALSOFT_UPDATE_BUILD_VERSION)
mark_as_advanced(ALSOFT_NO_CONFIG_UTIL)
mark_as_advanced(ALSOFT_REQUIRE_COREAUDIO)
mark_as_advanced(ALSOFT_REQUIRE_DSOUND)
mark_as_advanced(ALSOFT_REQUIRE_JACK)
mark_as_advanced(ALSOFT_REQUIRE_NEON)
mark_as_advanced(ALSOFT_REQUIRE_OBOE)
@ -246,7 +266,6 @@ if(TORQUE_SFX_OPENAL)
mark_as_advanced(ALSOFT_REQUIRE_SSE2)
mark_as_advanced(ALSOFT_REQUIRE_SSE3)
mark_as_advanced(ALSOFT_REQUIRE_SSE4_1)
mark_as_advanced(ALSOFT_REQUIRE_WASAPI)
mark_as_advanced(ALSOFT_REQUIRE_WINMM)
mark_as_advanced(ALSOFT_SEARCH_INSTALL_DATADIR)
mark_as_advanced(ALSOFT_TESTS)

View file

@ -59,31 +59,43 @@
IMPLEMENT_CONOBJECT(SoundAsset);
ConsoleType(SoundAssetPtr, TypeSoundAssetPtr, const char*, ASSET_ID_FIELD_PREFIX)
IMPLEMENT_STRUCT(AssetPtr<SoundAsset>, AssetPtrSoundAsset, , "")
END_IMPLEMENT_STRUCT
//-----------------------------------------------------------------------------
ConsoleType(SoundAssetPtr, TypeSoundAssetPtr, AssetPtr<SoundAsset>, ASSET_ID_FIELD_PREFIX)
ConsoleGetType(TypeSoundAssetPtr)
{
// Fetch asset Id.
return *((const char**)(dptr));
return (*((AssetPtr<SoundAsset>*)dptr)).getAssetId();
}
//-----------------------------------------------------------------------------
ConsoleSetType(TypeSoundAssetPtr)
{
// Was a single argument specified?
if (argc == 1)
{
// Yes, so fetch field value.
*((const char**)dptr) = StringTable->insert(argv[0]);
const char* pFieldValue = argv[0];
// Fetch asset pointer.
AssetPtr<SoundAsset>* pAssetPtr = dynamic_cast<AssetPtr<SoundAsset>*>((AssetPtrBase*)(dptr));
// Is the asset pointer the correct type?
if (pAssetPtr == NULL)
{
Con::warnf("(TypeSoundAssetPtrRefactor) - Failed to set asset Id '%d'.", pFieldValue);
return;
}
// Set asset.
pAssetPtr->setAssetId(pFieldValue);
return;
}
// Warn.
Con::warnf("(TypeSoundAssetPtr) - Cannot set multiple args to a single asset.");
Con::warnf("(TypeSoundAssetPtrRefactor) - Cannot set multiple args to a single asset.");
}
//-----------------------------------------------------------------------------
@ -134,7 +146,7 @@ SoundAsset::SoundAsset()
for (U32 i = 0; i < SFXPlayList::NUM_SLOTS; i++)
{
mSoundFile[i] = StringTable->EmptyString();
mSoundPath[i] = StringTable->EmptyString();
mSoundResource[i] = NULL;
mPlaylist.mSlots.mTransitionOut[i] = SFXPlayList::TRANSITION_Wait;
mPlaylist.mSlots.mVolumeScale.mValue[i] = 1.f;
@ -173,7 +185,8 @@ SoundAsset::SoundAsset()
mProfileDesc.mPriority = 1.0f;
mProfileDesc.mSourceGroup = NULL;
mProfileDesc.mFadeInEase = EaseF();
mProfileDesc.mReverb = SFXSoundReverbProperties();
mProfileDesc.mSourceGroup = dynamic_cast<SFXSource*>(Sim::findObject("AudioChannelMaster"));
dMemset(mProfileDesc.mParameters, 0, sizeof(mProfileDesc.mParameters));
mIsPlaylist = false;
@ -183,6 +196,9 @@ SoundAsset::SoundAsset()
mPlaylist.mLoopMode = SFXPlayList::LOOP_All;
mPlaylist.mActiveSlots = 1;
mResolvedTrack = NULL;
mResolvedDescription = NULL;
}
//-----------------------------------------------------------------------------
@ -190,8 +206,17 @@ SoundAsset::SoundAsset()
SoundAsset::~SoundAsset()
{
if (mPlaylist.isProperlyAdded() && !mPlaylist.isDeleted())
mPlaylist.unregisterObject();
if (mResolvedTrack)
{
if (mResolvedTrack->isProperlyAdded() && !mResolvedTrack->isDeleted())
mResolvedTrack->deleteObject();
}
if (mResolvedDescription)
{
if (mResolvedDescription->isProperlyAdded() && !mResolvedDescription->isDeleted())
mResolvedDescription->deleteObject();
}
}
//-----------------------------------------------------------------------------
@ -202,77 +227,77 @@ void SoundAsset::initPersistFields()
Parent::initPersistFields();
addGroup("SoundSlots");
addArray("slots", SFXPlayList::SFXPlaylistSettings::NUM_SLOTS);
addProtectedField("soundFile", TypeAssetLooseFilePath, Offset(mSoundFile, SoundAsset),
&_setSoundFile, &defaultProtectedGetFn, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, "Path to the sound file.");
addProtectedField("soundFile", TypeAssetLooseFilePath, Offset(mSoundFile, SoundAsset),
&_setSoundFile, &defaultProtectedGetFn, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, "Path to the sound file.");
addField("replay", TYPEID< SFXPlayList::EReplayMode >(), Offset(mPlaylist.mSlots.mReplayMode, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when an already playing sound is encountered on this slot from a previous cycle.\n"
"Each slot can have an arbitrary number of sounds playing on it from previous cycles. This field determines "
"how SFXController will handle these sources.");
addField("transitionIn", TYPEID< SFXPlayList::ETransitionMode >(), Offset(mPlaylist.mSlots.mTransitionIn, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when moving into this slot.\n"
"After the delayIn time has expired (if any), this slot determines what the controller "
"will do before actually playing the slot.");
addField("transitionOut", TYPEID< SFXPlayList::ETransitionMode >(), Offset(mPlaylist.mSlots.mTransitionOut, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when moving out of this slot.\n"
"After the #detailTimeOut has expired (if any), this slot determines what the controller "
"will do before moving on to the next slot.");
addFieldV("delayTimeIn", TypeRangedF32, Offset(mPlaylist.mSlots.mDelayTimeIn.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to wait after moving into slot before #transitionIn.");
addField("delayTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #delayTimeIn.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("delayTimeOut", TypeRangedF32, Offset(mPlaylist.mSlots.mDelayTimeOut.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to wait before moving out of slot after #transitionOut.");
addField("delayTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #delayTimeOut.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("fadeTimeIn", TypeRangedF32, Offset(mPlaylist.mSlots.mFadeTimeIn.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to fade sound in (-1 to use the track's own fadeInTime.)\n"
"@see SFXDescription::fadeTimeIn");
addField("fadeTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #fadeInTime.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("fadeTimeOut", TypeRangedF32, Offset(mPlaylist.mSlots.mFadeTimeOut.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to fade sound out (-1 to use the track's own fadeOutTime.)\n"
"@see SFXDescription::fadeTimeOut");
addField("fadeTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #fadeOutTime\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("referenceDistance", TypeRangedF32, Offset(mPlaylist.mSlots.mMinDistance.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"@c referenceDistance to set for 3D sounds in this slot (<1 to use @c referenceDistance of track's own description).\n"
"@see SFXDescription::referenceDistance");
addField("referenceDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMinDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #referenceDistance.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("maxSlotDistance", TypeRangedF32, Offset(mPlaylist.mSlots.mMaxDistance.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"@c maxDistance to apply to 3D sounds in this slot (<1 to use @c maxDistance of track's own description).\n"
"@see SFXDescription::maxDistance");
addField("maxSlotDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMaxDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #maxDistance.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("volumeScale", TypeRangedF32, Offset(mPlaylist.mSlots.mVolumeScale.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Scale factor to apply to volume of sounds played on this list slot.\n"
"This value will scale the actual volume level set on the track assigned to the slot, i.e. a value of 0.5 will "
"cause the track to play at half-volume.");
addField("volumeScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mVolumeScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #volumeScale.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("pitchScale", TypeRangedF32, Offset(mPlaylist.mSlots.mPitchScale.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Scale factor to apply to pitch of sounds played on this list slot.\n"
"This value will scale the actual pitch set on the track assigned to the slot, i.e. a value of 0.5 will "
"cause the track to play at half its assigned speed.");
addField("pitchScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mPitchScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #pitchScale.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("repeatCount", TypeRangedS32, Offset(mPlaylist.mSlots.mRepeatCount, SoundAsset), &CommonValidators::PositiveInt, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Number of times to loop this slot.");
addField("state", TypeSFXStateName, Offset(mPlaylist.mSlots.mState, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"State that must be active for this slot to play.\n\n"
"@ref SFXPlayList_states");
addField("stateMode", TYPEID< SFXPlayList::EStateMode >(), Offset(mPlaylist.mSlots.mStateMode, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when assigned state is deactivated while slot is playing.\n\n"
"@ref SFXPlayList_states");
addField("replay", TYPEID< SFXPlayList::EReplayMode >(), Offset(mPlaylist.mSlots.mReplayMode, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when an already playing sound is encountered on this slot from a previous cycle.\n"
"Each slot can have an arbitrary number of sounds playing on it from previous cycles. This field determines "
"how SFXController will handle these sources.");
addField("transitionIn", TYPEID< SFXPlayList::ETransitionMode >(), Offset(mPlaylist.mSlots.mTransitionIn, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when moving into this slot.\n"
"After the delayIn time has expired (if any), this slot determines what the controller "
"will do before actually playing the slot.");
addField("transitionOut", TYPEID< SFXPlayList::ETransitionMode >(), Offset(mPlaylist.mSlots.mTransitionOut, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when moving out of this slot.\n"
"After the #detailTimeOut has expired (if any), this slot determines what the controller "
"will do before moving on to the next slot.");
addFieldV("delayTimeIn", TypeRangedF32, Offset(mPlaylist.mSlots.mDelayTimeIn.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to wait after moving into slot before #transitionIn.");
addField("delayTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #delayTimeIn.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("delayTimeOut", TypeRangedF32, Offset(mPlaylist.mSlots.mDelayTimeOut.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to wait before moving out of slot after #transitionOut.");
addField("delayTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #delayTimeOut.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("fadeTimeIn", TypeRangedF32, Offset(mPlaylist.mSlots.mFadeTimeIn.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to fade sound in (-1 to use the track's own fadeInTime.)\n"
"@see SFXDescription::fadeTimeIn");
addField("fadeTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #fadeInTime.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("fadeTimeOut", TypeRangedF32, Offset(mPlaylist.mSlots.mFadeTimeOut.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Seconds to fade sound out (-1 to use the track's own fadeOutTime.)\n"
"@see SFXDescription::fadeTimeOut");
addField("fadeTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #fadeOutTime\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("referenceDistance", TypeRangedF32, Offset(mPlaylist.mSlots.mMinDistance.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"@c referenceDistance to set for 3D sounds in this slot (<1 to use @c referenceDistance of track's own description).\n"
"@see SFXDescription::referenceDistance");
addField("referenceDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMinDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #referenceDistance.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("maxSlotDistance", TypeRangedF32, Offset(mPlaylist.mSlots.mMaxDistance.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"@c maxDistance to apply to 3D sounds in this slot (<1 to use @c maxDistance of track's own description).\n"
"@see SFXDescription::maxDistance");
addField("maxSlotDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMaxDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #maxDistance.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("volumeScale", TypeRangedF32, Offset(mPlaylist.mSlots.mVolumeScale.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Scale factor to apply to volume of sounds played on this list slot.\n"
"This value will scale the actual volume level set on the track assigned to the slot, i.e. a value of 0.5 will "
"cause the track to play at half-volume.");
addField("volumeScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mVolumeScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #volumeScale.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("pitchScale", TypeRangedF32, Offset(mPlaylist.mSlots.mPitchScale.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Scale factor to apply to pitch of sounds played on this list slot.\n"
"This value will scale the actual pitch set on the track assigned to the slot, i.e. a value of 0.5 will "
"cause the track to play at half its assigned speed.");
addField("pitchScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mPitchScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Bounds on randomization of #pitchScale.\n\n"
"@ref SFXPlayList_randomization\n");
addFieldV("repeatCount", TypeRangedS32, Offset(mPlaylist.mSlots.mRepeatCount, SoundAsset), &CommonValidators::PositiveInt, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Number of times to loop this slot.");
addField("state", TypeSFXStateName, Offset(mPlaylist.mSlots.mState, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"State that must be active for this slot to play.\n\n"
"@ref SFXPlayList_states");
addField("stateMode", TYPEID< SFXPlayList::EStateMode >(), Offset(mPlaylist.mSlots.mStateMode, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
"Behavior when assigned state is deactivated while slot is playing.\n\n"
"@ref SFXPlayList_states");
endArray("slots");
endGroup("SoundSlots");
@ -284,48 +309,79 @@ void SoundAsset::initPersistFields()
// if streaming, a default packet size should be chosen for all sounds.
addField("isStreaming", TypeBool, Offset(mProfileDesc.mIsStreaming, SoundAsset), "Use streaming.");
//....why?
addFieldV("priority", TypeRangedF32, Offset(mProfileDesc.mPriority, SoundAsset), &CommonValidators::PositiveFloat, "Priority level for virtualization of sounds (1 = base level).\n"
"When there are more concurrently active sounds than supported by the audio mixer, some of the sounds "
"need to be culled. Which sounds are culled first depends primarily on total audibility of individual sounds. "
"However, the priority of invidual sounds may be decreased or decreased through this field.\n\n"
"@ref SFXSound_virtualization");
addField("parameters", TypeSFXParameterName, Offset(mProfileDesc.mParameters, SoundAsset), SFXDescription::MaxNumParameters,
"Names of the parameters to which sources using this description will automatically be linked.\n\n"
"Individual parameters are identified by their #internalName.\n\n"
"@ref SFX_interactive");
addField("useHardware", TypeBool, Offset(mProfileDesc.mUseHardware, SoundAsset), "Use hardware mixing for this sound.");
addField("sourceGroup", TypeSFXSourceName, Offset(mProfileDesc.mSourceGroup, SoundAsset), "Group that sources playing with this description should be put into.");
addField("preload", TypeBool, Offset(mPreload, SoundAsset), "Whether to preload sound data when the profile is added to system.");
endGroup("General Profile");
addGroup("Fading");
addFieldV("fadeInTime", TypeRangedF32, Offset(mProfileDesc.mFadeInTime, SoundAsset), &CommonValidators::PositiveFloat, "Number of seconds to gradually fade in volume from zero when playback starts.");
addFieldV("fadeOutTime", TypeRangedF32, Offset(mProfileDesc.mFadeOutTime, SoundAsset), &CommonValidators::PositiveFloat, "Number of seconds to gradually fade out volume down to zero when playback is stopped or paused.");
addField("fadeInEase", TypeEaseF, Offset(mProfileDesc.mFadeInEase, SoundAsset), "Easing curve for fade-in transition.");
addField("fadeOutEase", TypeEaseF, Offset(mProfileDesc.mFadeOutEase, SoundAsset), "Easing curve for fade-out transition.");
addField("fadeLoops", TypeBool, Offset(mProfileDesc.mFadeLoops, SoundAsset), "Fade each cycle of a loop in and/or out; otherwise only fade-in first cycle.");
addFieldV("fadeInTime", TypeRangedF32, Offset(mProfileDesc.mFadeInTime, SoundAsset), &CommonValidators::PositiveFloat, "Number of seconds to gradually fade in volume from zero when playback starts.");
addFieldV("fadeOutTime", TypeRangedF32, Offset(mProfileDesc.mFadeOutTime, SoundAsset), &CommonValidators::PositiveFloat, "Number of seconds to gradually fade out volume down to zero when playback is stopped or paused.");
addField("fadeInEase", TypeEaseF, Offset(mProfileDesc.mFadeInEase, SoundAsset), "Easing curve for fade-in transition.");
addField("fadeOutEase", TypeEaseF, Offset(mProfileDesc.mFadeOutEase, SoundAsset), "Easing curve for fade-out transition.");
addField("fadeLoops", TypeBool, Offset(mProfileDesc.mFadeLoops, SoundAsset), "Fade each cycle of a loop in and/or out; otherwise only fade-in first cycle.");
endGroup("Fading");
addGroup("3D");
addFieldV("minDistance", TypeRangedF32, Offset(mProfileDesc.mMinDistance, SoundAsset), &CommonValidators::PositiveFloat, "Minimum distance for sound.");
addFieldV("maxDistance", TypeRangedF32, Offset(mProfileDesc.mMaxDistance, SoundAsset), &CommonValidators::PositiveFloat, "Max distance for sound.");
addFieldV("coneInsideAngle", TypeRangedS32, Offset(mProfileDesc.mConeInsideAngle, SoundAsset), &CommonValidators::S32_PosDegreeRange, "Cone inside angle.");
addFieldV("coneOutsideAngle", TypeRangedS32, Offset(mProfileDesc.mConeOutsideAngle, SoundAsset), &CommonValidators::S32_PosDegreeRange, "Cone outside angle.");
addFieldV("coneOutsideVolume", TypeRangedF32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), &CommonValidators::NormalizedFloat, "Cone outside volume.");
addFieldV("rolloffFactor", TypeRangedF32, Offset(mProfileDesc.mRolloffFactor, SoundAsset), &CommonValidators::NegDefaultF32, "Rolloff factor.");
addField("scatterDistance", TypePoint3F, Offset(mProfileDesc.mScatterDistance, SoundAsset), "Randomization to the spacial position of the sound.");
addFieldV("minDistance", TypeRangedF32, Offset(mProfileDesc.mMinDistance, SoundAsset), &CommonValidators::PositiveFloat, "Minimum distance for sound.");
addFieldV("maxDistance", TypeRangedF32, Offset(mProfileDesc.mMaxDistance, SoundAsset), &CommonValidators::PositiveFloat, "Max distance for sound.");
addFieldV("coneInsideAngle", TypeRangedS32, Offset(mProfileDesc.mConeInsideAngle, SoundAsset), &CommonValidators::S32_PosDegreeRange, "Cone inside angle.");
addFieldV("coneOutsideAngle", TypeRangedS32, Offset(mProfileDesc.mConeOutsideAngle, SoundAsset), &CommonValidators::S32_PosDegreeRange, "Cone outside angle.");
addFieldV("coneOutsideVolume", TypeRangedF32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), &CommonValidators::NormalizedFloat, "Cone outside volume.");
addFieldV("rolloffFactor", TypeRangedF32, Offset(mProfileDesc.mRolloffFactor, SoundAsset), &CommonValidators::NegDefaultF32, "Rolloff factor.");
addField("scatterDistance", TypePoint3F, Offset(mProfileDesc.mScatterDistance, SoundAsset), "Randomization to the spacial position of the sound.");
endGroup("3D");
addGroup("Playlist settings");
addField("random", TYPEID< SFXPlayList::ERandomMode >(), Offset(mPlaylist.mRandomMode, SoundAsset), "Slot playback order randomization pattern.");
addField("loopMode", TYPEID< SFXPlayList::ELoopMode >(), Offset(mPlaylist.mLoopMode, SoundAsset), "Behavior when description has looping enabled.");
addFieldV("numSlotsToPlay", TypeRangedS32, Offset(mPlaylist.mNumSlotsToPlay, SoundAsset), &playlistSlotRange, "Number of slots to play.");
addField("trace", TypeBool, Offset(mPlaylist.mTrace, SoundAsset), "Enable/disable execution tracing for this playlist (local only).");
addField("random", TYPEID< SFXPlayList::ERandomMode >(), Offset(mPlaylist.mRandomMode, SoundAsset), "Slot playback order randomization pattern.");
addField("loopMode", TYPEID< SFXPlayList::ELoopMode >(), Offset(mPlaylist.mLoopMode, SoundAsset), "Behavior when description has looping enabled.");
addFieldV("numSlotsToPlay", TypeRangedS32, Offset(mPlaylist.mNumSlotsToPlay, SoundAsset), &playlistSlotRange, "Number of slots to play.");
addField("trace", TypeBool, Offset(mPlaylist.mTrace, SoundAsset), "Enable/disable execution tracing for this playlist (local only).");
endGroup("Playlist settings");
}
//------------------------------------------------------------------------------
void SoundAsset::onRemove()
{
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++)
{
if (mSoundFile[i] == StringTable->EmptyString())
break;
Torque::FS::RemoveChangeNotification(mSoundFile[i], this, &SoundAsset::_onResourceChanged);
}
Parent::onRemove();
}
void SoundAsset::inspectPostApply()
{
Parent::inspectPostApply();
refreshAsset();
}
void SoundAsset::copyTo(SimObject* object)
{
// Call to parent.
Parent::copyTo(object);
}
void SoundAsset::initializeAsset(void)
{
Parent::initializeAsset();
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++)
{
if (i == 0 && mSoundFile[i] == StringTable->EmptyString())
@ -334,134 +390,59 @@ void SoundAsset::initializeAsset(void)
if (mSoundFile[i] == StringTable->EmptyString())
break;
mSoundPath[i] = getOwned() ? expandAssetFilePath(mSoundFile[i]) : mSoundPath[i];
if (!Torque::FS::IsFile(mSoundPath[i]))
Con::errorf("SoundAsset::initializeAsset (%s)[%d] could not find %s!", getAssetName(), i, mSoundPath[i]);
mSoundFile[i] = expandAssetFilePath(mSoundFile[i]);
if (getOwned())
Torque::FS::AddChangeNotification(mSoundFile[i], this, &SoundAsset::_onResourceChanged);
}
populateSFXTrack();
}
void SoundAsset::_onResourceChanged(const Torque::Path &path)
void SoundAsset::_onResourceChanged(const Torque::Path& path)
{
for (U32 i = 0; i < SFXPlayList::NUM_SLOTS; i++)
{
if (path != Torque::Path(mSoundPath[i]))
if (path != Torque::Path(mSoundFile[i]))
return;
}
refreshAsset();
}
void SoundAsset::onAssetRefresh(void)
{
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++)
{
if (i == 0 && mSoundFile[i] == StringTable->EmptyString())
return;
if (!isProperlyAdded())
return;
if (mSoundFile[i] == StringTable->EmptyString())
break;
mSoundPath[i] = getOwned() ? expandAssetFilePath(mSoundFile[i]) : mSoundPath[i];
}
Parent::onAssetRefresh();
populateSFXTrack();
}
U32 SoundAsset::load()
{
if (mLoadedState == AssetErrCode::Ok) return mLoadedState;
if (mLoadedState == AssetErrCode::Ok)
return mLoadedState;
// find out how many active slots we have.
U32 numSlots = 0;
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++)
if (!mResolvedTrack)
{
if (i == 0 && mSoundPath[i] == StringTable->EmptyString())
return false;
if (mSoundPath[i] == StringTable->EmptyString())
break;
numSlots++;
}
if (mProfileDesc.mSourceGroup == NULL)
mProfileDesc.mSourceGroup = dynamic_cast<SFXSource*>(Sim::findObject("AudioChannelMaster"));
if (numSlots > 1)
{
mIsPlaylist = true;
for (U32 i = 0; i < numSlots; i++)
if (mIsPlaylist)
{
if (mSoundPath[i])
{
if (!Torque::FS::IsFile(mSoundPath[i]))
{
Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[i]);
mLoadedState = BadFileReference;
return mLoadedState;
}
else
{
mSFXProfile[i] = new SFXProfile;
mSFXProfile[i]->setDescription(&mProfileDesc);
mSFXProfile[i]->setSoundFileName(mSoundPath[i]);
mSFXProfile[i]->setPreload(mPreload);
mSFXProfile[i]->registerObject(String::ToString("%s_profile_track%d", getAssetName()).c_str());
mPlaylist.mSlots.mTrack[i] = mSFXProfile[i];
}
}
mResolvedTrack = buildPlaylist();
}
else
{
mResolvedTrack = buildProfile();
}
mPlaylist.setDescription(&mProfileDesc);
mPlaylist.registerObject(String::ToString("%s_playlist", getAssetName()).c_str());
}
else
{
if (mSoundPath[0])
{
if (!Torque::FS::IsFile(mSoundPath[0]))
{
Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[0]);
mLoadedState = BadFileReference;
return mLoadedState;
}
else
{
mSFXProfile[0] = new SFXProfile;
mSFXProfile[0]->setDescription(&mProfileDesc);
mSFXProfile[0]->setSoundFileName(mSoundPath[0]);
mSFXProfile[0]->setPreload(mPreload);
mSFXProfile[0]->registerObject(String::ToString("%s_profile", getAssetName()).c_str());
}
}
mResolvedTrack->registerObject(String::ToString("%s_profile_track", getAssetName()).c_str());
}
mChangeSignal.trigger();
mLoadedState = Ok;
return mLoadedState;
}
bool SoundAsset::_setSoundFile(void* object, const char* index, const char* data)
{
SoundAsset* pData = static_cast<SoundAsset*>(object);
U32 id = 0;
if (index)
id = dAtoui(index);
// Update.
pData->mSoundFile[id] = StringTable->insert(data, true);
if (pData->mSoundFile[id] == StringTable->EmptyString())
pData->mSoundPath[id] = StringTable->EmptyString();
// Refresh the asset.
pData->refreshAsset();
return true;
}
StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
{
if (fileName == StringTable->EmptyString())
@ -478,7 +459,7 @@ StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
SoundAsset* soundAsset = AssetDatabase.acquireAsset<SoundAsset>(query.mAssetList[i]);
if (soundAsset)
{
if (soundAsset->getSoundPath() == fileName)
if (soundAsset->getSoundFile() == fileName)
soundAssetId = soundAsset->getAssetId();
AssetDatabase.releaseAsset(query.mAssetList[i]);
@ -505,7 +486,7 @@ U32 SoundAsset::getAssetById(StringTableEntry assetId, AssetPtr<SoundAsset>* sou
}
}
U32 SoundAsset::getAssetByFileName(StringTableEntry fileName, AssetPtr<SoundAsset>* soundAsset)
U32 SoundAsset::getAssetByFilename(StringTableEntry fileName, AssetPtr<SoundAsset>* soundAsset)
{
AssetQuery query;
U32 foundAssetcount = AssetDatabase.findAssetType(&query, "SoundAsset");
@ -520,7 +501,7 @@ U32 SoundAsset::getAssetByFileName(StringTableEntry fileName, AssetPtr<SoundAsse
for (U32 i = 0; i < foundAssetcount; i++)
{
SoundAsset* tSoundAsset = AssetDatabase.acquireAsset<SoundAsset>(query.mAssetList[i]);
if (tSoundAsset && tSoundAsset->getSoundPath() == fileName)
if (tSoundAsset && tSoundAsset->getSoundFile() == fileName)
{
soundAsset->setAssetId(query.mAssetList[i]);
AssetDatabase.releaseAsset(query.mAssetList[i]);
@ -534,9 +515,172 @@ U32 SoundAsset::getAssetByFileName(StringTableEntry fileName, AssetPtr<SoundAsse
return AssetErrCode::Failed;
}
void SoundAsset::buildDescription()
{
if (!mResolvedDescription)
{
mResolvedDescription = new SFXDescription;
// calls on add which should validate the description. but do it on mProfileDesc before applying values anyway.
mResolvedDescription->registerObject(String::ToString("%s_profile_description", getAssetName()).c_str());
}
mProfileDesc.validate();
mResolvedDescription->mPitch = mProfileDesc.mPitch;
mResolvedDescription->mVolume = mProfileDesc.mVolume;
mResolvedDescription->mIs3D = mProfileDesc.mIs3D;
mResolvedDescription->mIsLooping = mProfileDesc.mIsLooping;
mResolvedDescription->mIsStreaming = mProfileDesc.mIsStreaming;
mResolvedDescription->mUseHardware = mProfileDesc.mUseHardware;
mResolvedDescription->mMinDistance = mProfileDesc.mMinDistance;
mResolvedDescription->mMaxDistance = mProfileDesc.mMaxDistance;
mResolvedDescription->mConeInsideAngle = mProfileDesc.mConeInsideAngle;
mResolvedDescription->mConeOutsideAngle = mProfileDesc.mConeOutsideAngle;
mResolvedDescription->mConeOutsideVolume = mProfileDesc.mConeOutsideVolume;
mResolvedDescription->mRolloffFactor = mProfileDesc.mRolloffFactor;
mResolvedDescription->mFadeInTime = mProfileDesc.mFadeInTime;
mResolvedDescription->mFadeOutTime = mProfileDesc.mFadeOutTime;
mResolvedDescription->mFadeLoops = mProfileDesc.mFadeLoops;
mResolvedDescription->mScatterDistance = mProfileDesc.mScatterDistance;
mResolvedDescription->mStreamPacketSize = mProfileDesc.mStreamPacketSize;
mResolvedDescription->mStreamReadAhead = mProfileDesc.mStreamReadAhead;
mResolvedDescription->mPriority = mProfileDesc.mPriority;
mResolvedDescription->mSourceGroup = mProfileDesc.mSourceGroup;
mResolvedDescription->mFadeInEase = mProfileDesc.mFadeInEase;
mResolvedDescription->mSourceGroup = mProfileDesc.mSourceGroup;
}
SFXProfile* SoundAsset::buildProfile()
{
SFXProfile* profile = new SFXProfile(mResolvedDescription, mSoundFile[0], mPreload);
mSoundResource[0] = profile->getResource();
return profile;
}
//-----------------------------------------------------------------------------
// BUILD PLAYLIST
//-----------------------------------------------------------------------------
SFXPlayList* SoundAsset::buildPlaylist()
{
SFXPlayList* pl = new SFXPlayList();
pl->mRandomMode = mPlaylist.mRandomMode;
pl->mLoopMode = mPlaylist.mLoopMode;
pl->mNumSlotsToPlay = mPlaylist.mNumSlotsToPlay;
pl->mTrace = mPlaylist.mTrace;
pl->mSlots = mPlaylist.mSlots;
// Build child tracks for each valid slot
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; ++i)
{
if (mSoundFile[i] == StringTable->EmptyString())
continue;
// Build child SFXProfile
SFXProfile* child = new SFXProfile(mResolvedDescription, mSoundFile[i], mPreload);
mSoundResource[i] = child->getResource();
pl->mSlots.mTrack[i] = child;
}
return pl;
}
void SoundAsset::populateSFXTrack(void)
{
U32 count = 0;
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; ++i)
{
if (mSoundFile[i] != StringTable->EmptyString())
{
if (!Torque::FS::IsFile(mSoundFile[i]))
{
mLoadedState = AssetErrCode::BadFileReference;
return;
}
++count;
}
}
mIsPlaylist = (count > 1);
buildDescription();
if (mResolvedTrack && mResolvedDescription)
{
if (SFX)
SFX->notifyDescriptionChanged(mResolvedDescription);
return;
}
mResolvedTrack = NULL;
// reset loaded state.
mLoadedState = AssetErrCode::NotLoaded;
}
void SoundAsset::setSoundFile(StringTableEntry pSoundFile, U32 slot)
{
AssertFatal(pSoundFile != NULL, "Cannot use a NULL sound file.");
pSoundFile = StringTable->insert(pSoundFile);
if (pSoundFile == mSoundFile[slot])
return;
mSoundFile[slot] = getOwned() ? expandAssetFilePath(pSoundFile) : StringTable->insert(pSoundFile);;
refreshAsset();
}
void SoundAsset::onTamlPreWrite(void)
{
// Call parent.
Parent::onTamlPreWrite();
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++)
{
if (mSoundFile[i] == StringTable->EmptyString())
break;
mSoundFile[i] = collapseAssetFilePath(mSoundFile[i]);
}
}
void SoundAsset::onTamlPostWrite(void)
{
for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++)
{
if (mSoundFile[i] == StringTable->EmptyString())
break;
mSoundFile[i] = expandAssetFilePath(mSoundFile[i]);
}
}
void SoundAsset::onTamlCustomWrite(TamlCustomNodes& customNodes)
{
// Debug Profiling.
PROFILE_SCOPE(SoundAsset_OnTamlCustomWrite);
// Call parent.
Parent::onTamlCustomRead(customNodes);
}
void SoundAsset::onTamlCustomRead(const TamlCustomNodes& customNodes)
{
// Debug Profiling.
PROFILE_SCOPE(SoundAsset_OnTamlCustomRead);
// Call parent.
Parent::onTamlCustomRead(customNodes);
}
DefineEngineMethod(SoundAsset, getSoundPath, const char*, (), , "")
{
return object->getSoundPath();
return object->getSoundFile();
}
DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zero),
@ -548,12 +692,18 @@ DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zer
MatrixF transform;
transform.setPosition(position);
SFXSource* source;
if (position == Point3F::Zero || !object->is3D())
if (position == Point3F::Zero && !object->is3D())
{
source = SFX->playOnce(object->getSFXTrack());
}
else
{
if (position == Point3F::Zero)
transform = SFX->getListener().getTransform();
source = SFX->playOnce(object->getSFXTrack(), &transform, NULL, -1);
}
if(source)
if (source)
return source->getId();
else
return 0;
@ -584,7 +734,7 @@ void GuiInspectorTypeSoundAssetPtr::consoleInit()
ConsoleBaseType::getType(TypeSoundAssetPtr)->setInspectorFieldType("GuiInspectorTypeSoundAssetPtr");
}
GuiControl * GuiInspectorTypeSoundAssetPtr::constructEditControl()
GuiControl* GuiInspectorTypeSoundAssetPtr::constructEditControl()
{
// Create base filename edit controls
GuiControl* retCtrl = Parent::constructEditControl();

View file

@ -87,21 +87,12 @@ class SoundAsset : public AssetBase
typedef AssetPtr<SoundAsset> ConcreteAssetPtr;
protected:
StringTableEntry mSoundFile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
StringTableEntry mSoundPath[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
SimObjectPtr<SFXProfile> mSFXProfile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
SFXDescription mProfileDesc;
SFXPlayList mPlaylist;
// subtitles
StringTableEntry mSubtitleString;
bool mPreload;
bool mIsPlaylist;
//SFXPlayList::SlotData mSlots;
/*These will be needed in the refactor!
Resource<SFXResource> mSoundResource;
// SFXDesctriptions, some off these will be removed
F32 mPitchAdjust;
@ -121,9 +112,6 @@ protected:
F32 mPriority;
*/
typedef Signal<void()> SoundAssetChanged;
SoundAssetChanged mChangeSignal;
public:
enum SoundAssetErrCode
{
@ -142,41 +130,79 @@ public:
if (errCode > SoundAssetErrCode::Extended) return "undefined error";
return mErrCodeStrings[errCode - Parent::Extended];
};
private:
StringTableEntry mSoundFile[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
Resource<SFXResource> mSoundResource[SFXPlayList::SFXPlaylistSettings::NUM_SLOTS];
SFXDescription mProfileDesc;
SFXPlayList mPlaylist;
// subtitles
StringTableEntry mSubtitleString;
bool mPreload;
bool mIsPlaylist;
SFXTrack* mResolvedTrack;
SFXDescription* mResolvedDescription;
public:
SoundAsset();
virtual ~SoundAsset();
/// Engine.
static void initPersistFields();
void onRemove() override;
void inspectPostApply() override;
void copyTo(SimObject* object) override;
//SFXResource* getSound() { return mSoundResource; }
Resource<SFXResource> getSoundResource(const U32 slotId = 0) { load(); return mSFXProfile[slotId]->getResource(); }
Resource<SFXResource> getSoundResource(const U32 slotId = 0) { load(); return mSoundResource[slotId]; }
/// Declare Console Object.
DECLARE_CONOBJECT(SoundAsset);
static bool _setSoundFile(void* object, const char* index, const char* data);
// asset Base load
U32 load() override;
inline StringTableEntry getSoundPath(const U32 slotId = 0) const { return mSoundPath[slotId]; };
SFXProfile* getSfxProfile(const U32 slotId = 0) { return mSFXProfile[slotId]; }
SFXPlayList* getSfxPlaylist() { return &mPlaylist; }
SFXTrack* getSFXTrack() { load(); return mIsPlaylist ? dynamic_cast<SFXTrack*>(&mPlaylist) : dynamic_cast<SFXTrack*>(mSFXProfile[0].getPointer()); }
SFXDescription* getSfxDescription() { return &mProfileDesc; }
bool isPlaylist(){ return mIsPlaylist; }
void setSoundFile(StringTableEntry pSoundFile, U32 slot = 0);
inline StringTableEntry getSoundFile(U32 slot = 0) { return mSoundFile[slot]; }
inline StringTableEntry getRelativeSoundFile(U32 slot = 0) { return collapseAssetFilePath(mSoundFile[slot]); }
SFXTrack* getSFXTrack() { load(); return mResolvedTrack; }
SFXDescription* getSfxDescription() { return mResolvedDescription ? mResolvedDescription : &mProfileDesc; }
bool isPlaylist() { return mIsPlaylist; }
bool isLoop() { return mProfileDesc.mIsLooping; }
bool is3D() { return mProfileDesc.mIs3D; }
static StringTableEntry getAssetIdByFileName(StringTableEntry fileName);
static U32 getAssetById(StringTableEntry assetId, AssetPtr<SoundAsset>* materialAsset);
static U32 getAssetByFileName(StringTableEntry fileName, AssetPtr<SoundAsset>* matAsset);
static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr<SoundAsset>* matAsset);
void buildDescription();
SFXProfile* buildProfile();
SFXPlayList* buildPlaylist();
void populateSFXTrack(void);
protected:
void initializeAsset(void) override;
void _onResourceChanged(const Torque::Path & path);
void onAssetRefresh(void) override;
// Asset Base callback
void initializeAsset(void) override;
void _onResourceChanged(const Torque::Path& path);
void onAssetRefresh(void) override;
/// Taml callbacks.
void onTamlPreWrite(void) override;
void onTamlPostWrite(void) override;
void onTamlCustomWrite(TamlCustomNodes& customNodes) override;
void onTamlCustomRead(const TamlCustomNodes& customNodes) override;
protected:
static bool _setSoundFile(void* obj, const char* index, const char* data) { U32 idx = 0; if (index) idx = dAtoi(index); static_cast<SoundAsset*>(obj)->setSoundFile(data, idx); return false; }
};
DECLARE_STRUCT(AssetPtr<SoundAsset>)
DefineConsoleType(TypeSoundAssetPtr, SoundAsset)
DefineConsoleType(TypeSoundAssetId, String)
@ -272,8 +298,8 @@ public: \
\
const StringTableEntry get##name() const\
{\
if (m##name##Asset && (m##name##Asset->getSoundPath() != StringTable->EmptyString()))\
return m##name##Asset->getSoundPath();\
if (m##name##Asset && (m##name##Asset->getSoundFile() != StringTable->EmptyString()))\
return m##name##Asset->getSoundFile();\
else if (m##name##AssetId != StringTable->EmptyString())\
return m##name##AssetId;\
else if (m##name##Name != StringTable->EmptyString())\
@ -467,8 +493,8 @@ public: \
\
const StringTableEntry get##name(const U32& index) const\
{\
if (m##name##Asset[index] && (m##name##Asset[index]->getSoundPath() != StringTable->EmptyString()))\
return m##name##Asset[index]->getSoundPath();\
if (m##name##Asset[index] && (m##name##Asset[index]->getSoundFile() != StringTable->EmptyString()))\
return m##name##Asset[index]->getSoundFile();\
else if (m##name##AssetId[index] != StringTable->EmptyString())\
return m##name##AssetId[index];\
else if (m##name##Name[index] != StringTable->EmptyString())\

View file

@ -3309,30 +3309,19 @@ Torque::Path AssetImporter::importSoundAsset(AssetImportObject* assetItem)
StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
String soundFileName = assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension();
String assetPath = targetPath + "/" + soundFileName;
String soundFileName = assetItem->filePath.getFullFileName();
String assetPath = "@" + soundFileName;
String tamlPath = targetPath + "/" + assetName + ".asset.taml";
String originalPath = assetItem->filePath.getFullPath().c_str();
char qualifiedFromFile[2048];
char qualifiedToFile[2048];
#ifndef TORQUE_SECURE_VFS
Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile));
#else
dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile));
dStrcpy(qualifiedToFile, assetPath.c_str(), sizeof(qualifiedToFile));
#endif
newAsset->setAssetName(assetName);
newAsset->_setSoundFile(newAsset, "0", soundFileName.c_str());
newAsset->setSoundFile(assetPath.c_str());
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::IsFile(qualifiedFromFile))
if (!isReimport)
{
newAsset->setDataField(StringTable->insert("originalFilePath"), NULL, qualifiedFromFile);
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, originalPath.c_str());
}
Taml tamlWriter;
@ -3345,18 +3334,6 @@ Torque::Path AssetImporter::importSoundAsset(AssetImportObject* assetItem)
return "";
}
if (!isReimport)
{
bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile);
if (!isInPlace && !Torque::FS::CopyFile(qualifiedFromFile, qualifiedToFile, !isReimport))
{
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str());
activityLog.push_back(importLogBuffer);
return "";
}
}
return tamlPath;
}

View file

@ -217,7 +217,7 @@ U32 LevelInfo::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
mathWrite( *stream, mAmbientLightBlendCurve );
sfxWrite( stream, mSoundAmbience );
stream->writeInt( mSoundDistanceModel, 1 );
stream->writeInt( mSoundDistanceModel, 4 );
PACK_ASSET_REFACTOR(conn, AccuTexture);
@ -251,7 +251,7 @@ void LevelInfo::unpackUpdate(NetConnection *conn, BitStream *stream)
String errorStr;
if( !sfxReadAndResolve( stream, &mSoundAmbience, errorStr ) )
Con::errorf( "%s", errorStr.c_str() );
mSoundDistanceModel = ( SFXDistanceModel ) stream->readInt( 1 );
mSoundDistanceModel = ( SFXDistanceModel ) stream->readInt( 4 );
if( isProperlyAdded() )
{

View file

@ -820,7 +820,7 @@ void SFXEmitter::_update()
// is toggled on a local profile sound. It makes the
// editor feel responsive and that things are working.
if( gEditingMission &&
(SoundAsset::getAssetErrCode(mSoundAsset) || !mSoundAsset->getSfxProfile()) &&
(SoundAsset::getAssetErrCode(mSoundAsset) || !mSoundAsset->getSFXTrack()) &&
mPlayOnAdd &&
mDirty.test( IsLooping ) )
prevState = SFXStatusPlaying;

View file

@ -231,6 +231,12 @@ bool GuiCanvas::onAdd()
{
// ensure that we have a cursor
setCursor(dynamic_cast<GuiCursor*>(Sim::findObject("DefaultCursor")));
SFXSystem::enumerateProviders();
SFXProvider* p = SFXSystem::getBestProviderChoice();
if (p)
SFX->createDevice(p);
// Enumerate things for GFX before we have an active device.
GFXInit::enumerateAdapters();

View file

@ -1,27 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// The various functions we need to grab from DSound.dll
DS_FUNCTION( DirectSoundEnumerateA, HRESULT, (LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext) )
DS_FUNCTION( DirectSoundEnumerateW, HRESULT, (LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext) )
DS_FUNCTION( DirectSoundCreate8, HRESULT, (LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter) )

View file

@ -1,277 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/dsound/sfxDSBuffer.h"
#include "sfx/sfxStream.h"
#include "sfx/sfxDescription.h"
#include "sfx/sfxInternal.h"
#include "platform/async/asyncUpdate.h"
#include "core/util/safeRelease.h"
#include "core/util/safeCast.h"
SFXDSBuffer* SFXDSBuffer::create( IDirectSound8 *dsound,
const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware )
{
AssertFatal( dsound, "SFXDSBuffer::create() - Got null dsound!" );
AssertFatal( stream, "SFXDSBuffer::create() - Got a null stream!" );
AssertFatal( description, "SFXDSBuffer::create() - Got a null description" );
SFXDSBuffer* buffer = new SFXDSBuffer( dsound,
stream,
description,
useHardware );
if( !buffer->_createBuffer( &buffer->mBuffer ) )
SAFE_DELETE( buffer );
return buffer;
}
SFXDSBuffer::SFXDSBuffer( IDirectSound8* dsound,
const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware )
: Parent( stream, description ),
mDSound( dsound ),
mIs3d( description->mIs3D ),
mUseHardware( useHardware ),
mBuffer( NULL ),
mDuplicate( false )
{
AssertFatal( mDSound, "SFXDSBuffer::SFXDSBuffer() - Got null dsound!" );
mDSound->AddRef();
}
SFXDSBuffer::~SFXDSBuffer()
{
SAFE_RELEASE( mBuffer );
SAFE_RELEASE( mDSound );
}
bool SFXDSBuffer::_createBuffer( IDirectSoundBuffer8 **buffer8 )
{
AssertFatal( mAsyncState != NULL,
"SFXDSBuffer::_createBuffer() - Can't create buffer when not connected to stream!" );
const SFXFormat& format = getFormat();
// Set up WAV format structure.
WAVEFORMATEX wfx;
dMemset( &wfx, 0, sizeof( WAVEFORMATEX ) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = format.getChannels();
wfx.nSamplesPerSec = format.getSamplesPerSecond();
wfx.wBitsPerSample = format.getBitsPerChannel();
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
// Set up DSBUFFERDESC structure.
DSBUFFERDESC dsbdesc;
dMemset( &dsbdesc, 0, sizeof( DSBUFFERDESC ) );
dsbdesc.dwSize = sizeof( DSBUFFERDESC );
dsbdesc.dwFlags =
( mIs3d ? DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE : DSBCAPS_CTRLPAN ) |
( isStreaming() ? DSBCAPS_CTRLPOSITIONNOTIFY : 0 ) |
DSBCAPS_CTRLFREQUENCY |
DSBCAPS_CTRLVOLUME |
DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_GLOBALFOCUS |
DSBCAPS_STATIC |
( mUseHardware ? DSBCAPS_LOCHARDWARE : DSBCAPS_LOCSOFTWARE );
dsbdesc.dwBufferBytes = mBufferSize;
if ( mIs3d )
dsbdesc.guid3DAlgorithm = DS3DALG_HRTF_FULL;
dsbdesc.lpwfxFormat = &wfx;
// Create the buffer.
IDirectSoundBuffer *buffer = NULL;
HRESULT hr = mDSound->CreateSoundBuffer( &dsbdesc, &buffer, NULL );
if ( FAILED( hr ) || !buffer )
return false;
// Grab the version 8 interface.
IDirectSoundBuffer8* buffer8Ptr;
hr = buffer->QueryInterface( IID_IDirectSoundBuffer8, ( LPVOID* ) &buffer8Ptr );
// Release the original interface.
buffer->Release();
// If we failed to get the 8 interface... exit.
if ( FAILED( hr ) || !buffer8Ptr )
return false;
// Set up notification positions, if this is a streaming buffer.
if( isStreaming() )
{
using namespace SFXInternal;
const U32 maxQueuedPackets = SFXAsyncQueue::DEFAULT_STREAM_QUEUE_LENGTH;
const U32 packetSize = mAsyncState->mStream->getPacketSize();
LPDIRECTSOUNDNOTIFY8 lpDsNotify;
if( FAILED( hr = buffer8Ptr->QueryInterface( IID_IDirectSoundNotify8, ( LPVOID* ) &lpDsNotify ) ) )
{
SAFE_RELEASE( buffer8Ptr );
return false;
}
const U32 numNotifies = maxQueuedPackets + 1; // Add one for end-of-stream notification pos.
DSBPOSITIONNOTIFY* dsbNotifyPos =
( DSBPOSITIONNOTIFY* ) _alloca( numNotifies * sizeof( DSBPOSITIONNOTIFY ) );
// Events seem to be triggered way too early by DS causing the playback queues to
// reject updates, so we nudge the update markers "somewhat" to the right here.
// This value here is based on experimentation. No harm should result if we don't
// hit it other than updates happening in sub-optimal timing.
enum { OFFSET_DELTA = 5000 };
U32 offset = ( packetSize + OFFSET_DELTA ) % mBufferSize;
HANDLE updateEvent = ( HANDLE ) UPDATE_THREAD()->getUpdateEvent();
for( U32 i = 0; i < maxQueuedPackets; ++ i, offset = ( offset + packetSize ) % mBufferSize )
{
dsbNotifyPos[ i ].dwOffset = offset;
dsbNotifyPos[ i ].hEventNotify = updateEvent;
}
// A end-of-stream notification position.
//FIXME: this position will start to be wrong when doing stream seeks
dsbNotifyPos[ numNotifies - 1 ].dwOffset = ( format.getDataLength( getDuration() ) + OFFSET_DELTA ) % mBufferSize;
dsbNotifyPos[ numNotifies - 1 ].hEventNotify = updateEvent;
// Install the notifications.
lpDsNotify->SetNotificationPositions( numNotifies, dsbNotifyPos );
SAFE_RELEASE( lpDsNotify );
// Don't need to notify on stop as when playback is stopped,
// the packet buffers will just fill up and stop updating
// when saturated.
}
*buffer8 = buffer8Ptr;
return true;
}
bool SFXDSBuffer::_copyData( U32 offset,
const U8 *data,
U32 length )
{
AssertFatal( mBuffer, "SFXDSBuffer::_copyData() - no buffer" );
// Fill the buffer with the resource data.
VOID* lpvWrite;
DWORD dwLength;
VOID* lpvWrite2;
DWORD dwLength2;
HRESULT hr = mBuffer->Lock(
offset, // Offset at which to start lock.
length, // Size of lock.
&lpvWrite, // Gets address of first part of lock.
&dwLength, // Gets size of first part of lock.
&lpvWrite2, // Address of wraparound not needed.
&dwLength2, // Size of wraparound not needed.
0 );
if ( FAILED( hr ) )
return false;
// Copy the first part.
dMemcpy( lpvWrite, data, dwLength );
// Do we have a wrap?
if ( lpvWrite2 )
dMemcpy( lpvWrite2, data + dwLength, dwLength2 );
// And finally, unlock.
hr = mBuffer->Unlock(
lpvWrite, // Address of lock start.
dwLength, // Size of lock.
lpvWrite2, // No wraparound portion.
dwLength2 ); // No wraparound size.
// Return success code.
return SUCCEEDED(hr);
}
void SFXDSBuffer::_flush()
{
AssertFatal( isStreaming(), "SFXDSBuffer::_flush() - not a streaming buffer" );
AssertFatal( SFXInternal::isSFXThread(), "SFXDSBuffer::_flush() - not on SFX thread" );
Parent::_flush();
mBuffer->SetCurrentPosition( 0 );
}
bool SFXDSBuffer::_duplicateBuffer( IDirectSoundBuffer8 **buffer8 )
{
AssertFatal( mBuffer, "SFXDSBuffer::_duplicateBuffer() - Duplicate buffer is null!" );
// If this is the first duplicate then
// give the caller our original buffer.
if ( !mDuplicate )
{
mDuplicate = true;
*buffer8 = mBuffer;
(*buffer8)->AddRef();
return true;
}
IDirectSoundBuffer *buffer1 = NULL;
HRESULT hr = mDSound->DuplicateSoundBuffer( mBuffer, &buffer1 );
if ( FAILED( hr ) || !buffer1 )
return false;
// Grab the version 8 interface.
hr = buffer1->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*)buffer8 );
// Release the original interface.
buffer1->Release();
return SUCCEEDED( hr ) && (*buffer8);
}
bool SFXDSBuffer::createVoice( IDirectSoundBuffer8 **buffer8 )
{
return ( mBuffer && _duplicateBuffer( buffer8 ) && *buffer8 );
}
void SFXDSBuffer::releaseVoice( IDirectSoundBuffer8 **buffer )
{
AssertFatal( *buffer, "SFXDSBuffer::releaseVoice() - Got null buffer!" );
if ( *buffer == mBuffer )
{
mDuplicate = false;
(*buffer)->Stop();
}
SAFE_RELEASE( (*buffer) );
}

View file

@ -1,101 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _SFXDSBUFFER_H_
#define _SFXDSBUFFER_H_
#include <dsound.h>
#ifndef _SFXINTERNAL_H_
# include "sfx/sfxInternal.h"
#endif
/// DirectSound SFXBuffer implementation.
///
/// Note that the actual sound buffer held by the buffer may
/// get duplicated around for individual voices. This is kind
/// of ugly as the resulting buffers aren't tied to a SFXDSBuffer
/// anymore.
class SFXDSBuffer : public SFXInternal::SFXWrapAroundBuffer
{
typedef SFXInternal::SFXWrapAroundBuffer Parent;
friend class SFXDSDevice;
friend class SFXDSVoice;
protected:
///
bool mIs3d;
///
bool mUseHardware;
IDirectSound8 *mDSound;
/// The buffer used when duplication is allowed.
IDirectSoundBuffer8 *mBuffer;
/// We set this to true when the original buffer has
/// been handed out and duplicates need to be made.
bool mDuplicate;
///
SFXDSBuffer( IDirectSound8 *dsound,
const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware );
virtual ~SFXDSBuffer();
/// Set up a DirectSound buffer.
/// @note This method will not fill the buffer with data.
/// @note If this is a streaming buffer, the resulting buffer
/// will have its notification positions set up and already
/// be registered with SFXDSStreamThread.
bool _createBuffer( IDirectSoundBuffer8 **buffer8 );
///
bool _duplicateBuffer( IDirectSoundBuffer8 **buffer8 );
// SFXWrapAroundBuffer.
virtual bool _copyData( U32 offset, const U8* data, U32 length );
virtual void _flush();
public:
///
static SFXDSBuffer* create( IDirectSound8* dsound,
const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware );
//
bool createVoice( IDirectSoundBuffer8 **buffer );
//
void releaseVoice( IDirectSoundBuffer8 **buffer );
};
#endif // _SFXDSBUFFER_H_

View file

@ -1,229 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/dsound/sfxDSDevice.h"
#include "sfx/dsound/sfxDSBuffer.h"
#include "sfx/dsound/sfxDSVoice.h"
#include "platformWin32/platformWin32.h"
#include "core/util/safeRelease.h"
#include "platform/async/asyncUpdate.h"
#include "console/console.h"
SFXDSDevice::SFXDSDevice( SFXProvider* provider,
DSoundFNTable *dsFnTbl,
GUID* guid,
String name,
bool useHardware,
S32 maxBuffers )
: SFXDevice( name, provider, useHardware, maxBuffers ),
mDSound( NULL ),
mPrimaryBuffer( NULL ),
mListener( NULL ),
mDSoundTbl( dsFnTbl ),
mGUID( guid )
{
}
bool SFXDSDevice::_init()
{
HRESULT hr = mDSoundTbl->DirectSoundCreate8( mGUID, &mDSound, NULL );
if ( FAILED( hr ) || !mDSound )
{
Con::errorf( "SFXDSDevice::SFXDSDevice() - DirectSoundCreate8 failed" );
return false;
}
hr = mDSound->SetCooperativeLevel( getWin32WindowHandle(), DSSCL_PRIORITY );
if ( FAILED( hr ) )
{
Con::errorf( "SFXDSDevice::SFXDSDevice() - SetCooperativeLevel failed" );
return false;
}
// Get the primary buffer.
DSBUFFERDESC dsbd;
dMemset( &dsbd, 0, sizeof( DSBUFFERDESC ) );
dsbd.dwSize = sizeof( DSBUFFERDESC );
dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
hr = mDSound->CreateSoundBuffer( &dsbd, &mPrimaryBuffer, NULL );
if ( FAILED( hr ) )
{
Con::errorf( "SFXDSDevice::SFXDSDevice - Creating primary sound buffer failed" );
return false;
}
// Set the format and bitrate on the primary buffer.
S32 frequency = Con::getIntVariable( "$pref::SFX::frequency", 44100 );
S32 bitrate = Con::getIntVariable( "$pref::SFX::bitrate", 32 );
WAVEFORMATEX wfx;
dMemset( &wfx, 0, sizeof( WAVEFORMATEX ) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = frequency;
wfx.wBitsPerSample = bitrate;
wfx.nBlockAlign = ( wfx.nChannels * wfx.wBitsPerSample ) / 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
hr = mPrimaryBuffer->SetFormat( &wfx );
if( FAILED( hr ) )
{
Con::errorf( "SFXDSDevice::SFXDSDevice() - Setting format of primary buffer failed" );
return false;
}
// Grab the 3d listener.
hr = mPrimaryBuffer->QueryInterface( IID_IDirectSound3DListener8, (LPVOID*)&mListener );
if ( FAILED( hr ) )
{
Con::errorf( "SFXDSDevice::SFXDevice() - Querying the listener interface failed!" );
mListener = NULL;
}
mCaps.dwSize = sizeof( DSCAPS );
mDSound->GetCaps( &mCaps );
// If the device reports no hardware buffers then
// we have no choice but to disable hardware.
if ( mCaps.dwMaxHw3DAllBuffers == 0 )
mUseHardware = false;
// If mMaxBuffers is negative then use the caps
// to decide on a good maximum value... or set 8.
if ( mMaxBuffers < 0 )
mMaxBuffers = getMax( mCaps.dwMaxHw3DAllBuffers, 8 );
// Start the stream thread.
if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
{
SFXInternal::gUpdateThread =
new AsyncUpdateThread( "DirectSound Update Thread", SFXInternal::gBufferUpdateList );
SFXInternal::gUpdateThread->start();
}
return true;
}
SFXDSDevice::~SFXDSDevice()
{
// And release our resources.
SAFE_RELEASE( mListener );
SAFE_RELEASE( mPrimaryBuffer );
SAFE_RELEASE( mDSound );
}
SFXBuffer* SFXDSDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
{
AssertFatal( stream, "SFXDSDevice::createBuffer() - Got null stream!" );
AssertFatal( description, "SFXDSDevice::createBuffer() - Got null description!" );
SFXDSBuffer* buffer = SFXDSBuffer::create( mDSound,
stream,
description,
mUseHardware );
if( buffer )
_addBuffer( buffer );
return buffer;
}
SFXVoice* SFXDSDevice::createVoice( bool is3D, SFXBuffer *buffer )
{
// Don't bother going any further if we've
// exceeded the maximum voices.
if ( mVoices.size() >= mMaxBuffers )
return NULL;
AssertFatal( buffer, "SFXDSDevice::createVoice() - Got null buffer!" );
SFXDSBuffer* dsBuffer = dynamic_cast<SFXDSBuffer*>( buffer );
AssertFatal( dsBuffer, "SFXDSDevice::createVoice() - Got bad buffer!" );
SFXDSVoice* voice = SFXDSVoice::create( this, dsBuffer );
if ( !voice )
return NULL;
_addVoice( voice );
return voice;
}
void SFXDSDevice::_commitDeferred()
{
if( mListener )
mListener->CommitDeferredSettings();
}
void SFXDSDevice::update()
{
Parent::update();
// Apply the deferred settings that changed between updates.
mListener->CommitDeferredSettings();
}
void SFXDSDevice::setListener( U32 index, const SFXListenerProperties& listener )
{
// Get the transform from the listener.
const MatrixF& transform = listener.getTransform();
Point3F pos, dir, up;
transform.getColumn( 3, &pos );
transform.getColumn( 1, &dir );
transform.getColumn( 2, &up );
// And the velocity...
const VectorF& velocity = listener.getVelocity();
// Finally, set it all to DSound!
mListener->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED );
mListener->SetOrientation( dir.x, dir.z, dir.y, up.x, up.z, up.y, DS3D_DEFERRED );
mListener->SetVelocity( velocity.x, velocity.z, velocity.y, DS3D_DEFERRED );
}
void SFXDSDevice::setDistanceModel( SFXDistanceModel model )
{
switch( model )
{
case SFXDistanceModelLinear:
Con::errorf( "SFXDSDevice::setDistanceModel - 'linear' distance attenuation not supported by DirectSound" );
break;
case SFXDistanceModelLogarithmic:
break; // Nothing to do.
default:
AssertWarn( false, "SFXDSDevice::setDistanceModel() - model not implemented" );
}
}
void SFXDSDevice::setDopplerFactor( F32 factor )
{
if( mListener )
mListener->SetDopplerFactor( factor, DS3D_DEFERRED ); // Committed in update.
}
void SFXDSDevice::setRolloffFactor( F32 factor )
{
if( mListener )
mListener->SetRolloffFactor( factor, DS3D_DEFERRED ); // Committed in update.
}

View file

@ -1,142 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _SFXDSDEVICE_H_
#define _SFXDSDEVICE_H_
#ifndef _STRINGFUNCTIONS_H_
# include "core/strings/stringFunctions.h"
#endif
#ifndef _SFXDEVICE_H_
#include "sfx/sfxDevice.h"
#endif
#ifndef _SFXDSVOICE_H_
#include "sfx/dsound/sfxDSVoice.h"
#endif
#ifndef OS_DLIBRARY_H
#include "platform/platformDlibrary.h"
#endif
#include <dsound.h>
// Typedefs
#define DS_FUNCTION(fn_name, fn_return, fn_args) \
typedef fn_return (WINAPI *DSFNPTR##fn_name##)##fn_args##;
#include "sfx/dsound/dsFunctions.h"
#undef DS_FUNCTION
// Function table
struct DSoundFNTable
{
DSoundFNTable() : isLoaded( false ) {};
bool isLoaded;
DLibraryRef dllRef;
#define DS_FUNCTION(fn_name, fn_return, fn_args) \
DSFNPTR##fn_name fn_name;
#include "sfx/dsound/dsFunctions.h"
#undef DS_FUNCTION
};
/// Helper for asserting on dsound HRESULTS.
inline void DSAssert( HRESULT hr, const char *info )
{
#ifdef TORQUE_DEBUG
if( FAILED( hr ) )
{
char buf[256];
dSprintf( buf, 256, "Error code: %x\n%s", hr, info );
AssertFatal( false, buf );
}
#endif
}
/// The DirectSound device implementation exposes a couple
/// of settings to script that you should be aware of:
///
/// $DirectSound::dopplerFactor - This controls the scale of
/// the doppler effect. Valid factors are 0.0 to 10.0 and it
/// defaults to 0.75.
///
/// $DirectSound::distanceFactor - This sets the unit conversion
/// for
///
/// $DirectSound::rolloffFactor - ;
///
///
class SFXDSDevice : public SFXDevice
{
typedef SFXDevice Parent;
friend class SFXDSVoice;
friend class SFXDSProvider; // _init
public:
//explicit SFXDSDevice();
SFXDSDevice( SFXProvider* provider,
DSoundFNTable *dsFnTbl,
GUID* guid,
String name,
bool useHardware,
S32 maxBuffers );
virtual ~SFXDSDevice();
protected:
IDirectSound8 *mDSound;
IDirectSound3DListener8 *mListener;
IDirectSoundBuffer *mPrimaryBuffer;
DSoundFNTable *mDSoundTbl;
DSCAPS mCaps;
GUID* mGUID;
bool _init();
/// Called from SFXDSVoice to commit any deferred
/// settings before playback begins.
void _commitDeferred();
public:
// SFXDevice
virtual SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
virtual SFXVoice* createVoice( bool is3D, SFXBuffer *buffer );
virtual void update();
virtual void setListener( U32 index, const SFXListenerProperties& listener );
virtual void setDistanceModel( SFXDistanceModel mode );
virtual void setDopplerFactor( F32 factor );
virtual void setRolloffFactor( F32 factor );
};
#endif // _SFXDSDEVICE_H_

View file

@ -1,198 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/sfxProvider.h"
#include "sfx/dsound/sfxDSDevice.h"
#include "core/util/safeRelease.h"
#include "console/console.h"
#include "core/strings/unicode.h"
#include "core/util/safeDelete.h"
#include "core/module.h"
class SFXDSProvider : public SFXProvider
{
public:
SFXDSProvider()
: SFXProvider( "DirectSound" ) {}
virtual ~SFXDSProvider();
void init();
protected:
DSoundFNTable mDSound;
struct DSDeviceInfo : SFXDeviceInfo
{
GUID* guid;
DSCAPS caps;
};
static BOOL CALLBACK dsEnumProc(
LPGUID lpGUID,
LPCTSTR lpszDesc,
LPCTSTR lpszDrvName,
LPVOID lpContext );
void addDeviceDesc( GUID* guid, const String& name, const String& desc );
public:
SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers );
};
MODULE_BEGIN( DirectSound )
MODULE_INIT_BEFORE( SFX )
MODULE_SHUTDOWN_AFTER( SFX )
SFXDSProvider* mProvider;
MODULE_INIT
{
mProvider = new SFXDSProvider;
}
MODULE_SHUTDOWN
{
delete mProvider;
}
MODULE_END;
//------------------------------------------------------------------------------
// Helper
bool dsBindFunction( DLibrary *dll, void *&fnAddress, const char *name )
{
fnAddress = dll->bind( name );
if (!fnAddress)
Con::warnf( "DSound Loader: DLL bind failed for %s", name );
return fnAddress != 0;
}
//------------------------------------------------------------------------------
SFXDSProvider::~SFXDSProvider()
{
}
void SFXDSProvider::init()
{
// Grab the functions we'll want from the dsound DLL.
mDSound.dllRef = OsLoadLibrary( "dsound.dll" );
mDSound.isLoaded = true;
#define DS_FUNCTION(fn_name, fn_return, fn_args) \
mDSound.isLoaded &= dsBindFunction(mDSound.dllRef, *(void**)&mDSound.fn_name, #fn_name);
#include "sfx/dsound/dsFunctions.h"
#undef DS_FUNCTION
AssertISV( mDSound.isLoaded, "DirectSound failed to load." );
// All we need to do to init is enumerate the
// devices... if this fails then don't register
// the provider as it's broken in some way.
if ( FAILED( mDSound.DirectSoundEnumerate( dsEnumProc, (VOID*)this ) ) )
{
Con::errorf( "SFXDSProvider - Device enumeration failed!" );
return;
}
// Did we get any devices?
if ( mDeviceInfo.empty() )
{
Con::errorf( "SFXDSProvider - No valid devices found!" );
return;
}
// Wow, we made it - register the provider.
regProvider( this );
}
BOOL CALLBACK SFXDSProvider::dsEnumProc(
LPGUID lpGUID,
LPCTSTR lpszDesc,
LPCTSTR lpszDrvName,
LPVOID lpContext )
{
SFXDSProvider* provider = (SFXDSProvider*)lpContext;
provider->addDeviceDesc( lpGUID, lpszDrvName, lpszDesc );
return TRUE;
}
void SFXDSProvider::addDeviceDesc( GUID* guid, const String& name, const String& desc )
{
// Create a dummy device to get the caps.
IDirectSound8* dsound;
HRESULT hr = mDSound.DirectSoundCreate8( guid, &dsound, NULL );
if ( FAILED( hr ) || !dsound )
return;
// Init the caps structure and have the device fill it out.
DSCAPS caps;
dMemset( &caps, 0, sizeof( caps ) );
caps.dwSize = sizeof( caps );
hr = dsound->GetCaps( &caps );
// Clean up and handle errors.
SAFE_RELEASE( dsound );
if ( FAILED( hr ) )
return;
// Now, record the desc info into our own internal list.
DSDeviceInfo* info = new DSDeviceInfo;
info->name = desc;
info->driver = name;
info->hasHardware = caps.dwMaxHw3DAllBuffers > 0;
info->maxBuffers = caps.dwMaxHw3DAllBuffers;
info->guid = guid;
info->caps = caps;
mDeviceInfo.push_back( info );
}
SFXDevice* SFXDSProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
{
DSDeviceInfo* info = dynamic_cast< DSDeviceInfo* >
( _findDeviceInfo( deviceName ) );
if( !info )
return NULL;
SFXDSDevice* device = new SFXDSDevice( this,
&mDSound,
info->guid,
info->name,
useHardware,
maxBuffers );
if( !device->_init() )
SAFE_DELETE( device );
return device;
}

View file

@ -1,229 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/dsound/sfxDSVoice.h"
#include "sfx/dsound/sfxDSDevice.h"
#include "core/util/safeRelease.h"
SFXDSVoice* SFXDSVoice::create( SFXDSDevice *device, SFXDSBuffer *buffer )
{
AssertFatal( buffer, "SFXDSVoice::create() - Got null buffer!" );
IDirectSoundBuffer8 *dsBuffer8 = NULL;
if ( !buffer->createVoice( &dsBuffer8 ) || !dsBuffer8 )
return NULL;
// Now try to grab a 3D interface... if we don't
// get one its probably because its not a 3d sound.
IDirectSound3DBuffer8* dsBuffer3d8 = NULL;
dsBuffer8->QueryInterface( IID_IDirectSound3DBuffer8, (LPVOID*)&dsBuffer3d8 );
// Create the voice and return!
SFXDSVoice* voice = new SFXDSVoice( device,
buffer,
dsBuffer8,
dsBuffer3d8 );
// Now set the voice to a default state.
// The buffer from which we have duplicated may have been assigned different
// properties and we don't want to inherit these.
voice->setVolume( 1.0 );
voice->setPitch( 1.0 );
return voice;
}
SFXDSVoice::SFXDSVoice( SFXDSDevice *device,
SFXDSBuffer *buffer,
IDirectSoundBuffer8 *dsBuffer,
IDirectSound3DBuffer8 *dsBuffer3d )
: Parent( buffer ),
mDevice( device ),
mDSBuffer( dsBuffer ),
mDSBuffer3D( dsBuffer3d ),
mIsLooping( false )
{
AssertFatal( mDevice, "SFXDSVoice::SFXDSVoice() - SFXDSDevice is null!" );
AssertFatal( mBuffer, "SFXDSVoice::SFXDSVoice() - SFXDSBuffer is null!" );
AssertFatal( mDSBuffer, "SFXDSVoice::SFXDSVoice() - Dsound buffer is null!" );
}
SFXDSVoice::~SFXDSVoice()
{
SAFE_RELEASE( mDSBuffer3D );
SFXDSBuffer* dsBuffer = _getBuffer();
if( dsBuffer )
dsBuffer->releaseVoice( &mDSBuffer );
mBuffer = NULL;
}
SFXStatus SFXDSVoice::_status() const
{
DWORD status = 0;
mDSBuffer->GetStatus( &status );
if ( status & DSBSTATUS_PLAYING )
return SFXStatusPlaying;
else
return SFXStatusStopped;
}
void SFXDSVoice::_play()
{
DSAssert( mDSBuffer->Play( 0, 0, mIsLooping ? DSBPLAY_LOOPING : 0 ),
"SFXDSVoice::_play() - Playback failed!" );
}
void SFXDSVoice::_stop()
{
DSAssert( mDSBuffer->Stop(), "SFXDSVoice::pause - stop failed!" );
mDSBuffer->SetCurrentPosition( 0 );
}
void SFXDSVoice::_pause()
{
DSAssert( mDSBuffer->Stop(), "SFXDSVoice::pause - stop failed!" );
}
void SFXDSVoice::_seek( U32 sample )
{
U32 pos = mBuffer->getFormat().getBytesPerSample() * sample;
mDSBuffer->SetCurrentPosition( pos );
}
U32 SFXDSVoice::_tell() const
{
DWORD position = 0;
mDSBuffer->GetCurrentPosition( &position, NULL );
U32 samplePos = _getBuffer()->getSamplePos( position );
return samplePos;
}
void SFXDSVoice::setMinMaxDistance( F32 min, F32 max )
{
if ( !mDSBuffer3D )
return;
mDSBuffer3D->SetMinDistance( min, DS3D_DEFERRED );
mDSBuffer3D->SetMaxDistance( max, DS3D_DEFERRED );
}
void SFXDSVoice::play( bool looping )
{
// If this is a 3d sound then we need
// to commit any deferred settings before
// we start playback else we can get some
// glitches.
if ( mDSBuffer3D )
mDevice->_commitDeferred();
// If this is a streaming buffer,
// force looping.
const bool isStreaming = mBuffer->isStreaming();
if( isStreaming )
looping = true;
mIsLooping = looping;
Parent::play( looping );
}
void SFXDSVoice::setVelocity( const VectorF& velocity )
{
if ( !mDSBuffer3D )
return;
DSAssert( mDSBuffer3D->SetVelocity( velocity.x, velocity.z, velocity.y, DS3D_DEFERRED ),
"SFXDSVoice::setVelocity - couldn't update buffer!" );
}
void SFXDSVoice::setTransform( const MatrixF& transform )
{
if ( !mDSBuffer3D )
return;
Point3F pos, dir;
transform.getColumn( 3, &pos );
transform.getColumn( 1, &dir );
DSAssert( mDSBuffer3D->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED ),
"SFXDSVoice::setTransform - couldn't set position of the buffer." );
DSAssert( mDSBuffer3D->SetConeOrientation( dir.x, dir.z, dir.y, DS3D_DEFERRED ),
"SFXDSVoice::setTransform - couldn't set cone orientation of the buffer." );
}
/// Helper for converting floating point linear volume
/// to a logrithmic integer volume for dsound.
LONG SFXDSVoice::_linearToLogVolume( F32 linVolume )
{
LONG logVolume;
if ( linVolume <= 0.0f )
logVolume = DSBVOLUME_MIN;
else
{
logVolume = -2000.0 * mLog( 1.0f / linVolume );
logVolume = mClamp( logVolume, DSBVOLUME_MIN, DSBVOLUME_MAX );
}
return logVolume;
}
void SFXDSVoice::setVolume( F32 volume )
{
LONG logVolume = _linearToLogVolume( volume );
HRESULT hr = mDSBuffer->SetVolume( logVolume );
DSAssert( hr, "SFXDSVoice::setVolume - couldn't set volume!" );
}
void SFXDSVoice::setPitch( F32 pitch )
{
F32 sampleRate = _getBuffer()->getFormat().getSamplesPerSecond();
F32 frequency = mFloor( mClampF( sampleRate * pitch, DSBFREQUENCY_MIN, DSBFREQUENCY_MAX ) );
DSAssert( mDSBuffer->SetFrequency( ( U32 )frequency ),
"SFXDSVoice::setPitch - couldn't set playback frequency.");
}
void SFXDSVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
{
if ( !mDSBuffer3D )
return;
DSAssert( mDSBuffer3D->SetConeAngles( innerAngle,
outerAngle,
DS3D_DEFERRED ),
"SFXDSVoice::setCone - couldn't set cone angles!" );
LONG logVolume = _linearToLogVolume( outerVolume );
DSAssert( mDSBuffer3D->SetConeOutsideVolume( logVolume,
DS3D_DEFERRED ),
"SFXDSVoice::setCone - couldn't set cone outside volume!" );
}

View file

@ -1,92 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _SFXDSVOICE_H_
#define _SFXDSVOICE_H_
#ifndef _SFXVOICE_H_
#include "sfx/sfxVoice.h"
#endif
#ifndef _SFXDSBUFFER_H_
#include "sfx/dsound/sfxDSBuffer.h"
#endif
#include <dsound.h>
class SFXDSDevice;
class SFXDSVoice : public SFXVoice
{
typedef SFXVoice Parent;
protected:
SFXDSVoice( SFXDSDevice *device,
SFXDSBuffer *buffer,
IDirectSoundBuffer8 *dsBuffer,
IDirectSound3DBuffer8 *dsBuffer3d );
/// The device used to commit deferred settings.
SFXDSDevice *mDevice;
IDirectSoundBuffer8 *mDSBuffer;
IDirectSound3DBuffer8 *mDSBuffer3D;
bool mIsLooping;
SFXDSBuffer* _getBuffer() const { return ( SFXDSBuffer* ) mBuffer.getPointer(); }
/// Helper for converting floating point linear volume
/// to a logrithmic integer volume for dsound.
static LONG _linearToLogVolume( F32 linVolume );
// SFXVoice
virtual SFXStatus _status() const;
virtual void _play();
virtual void _pause();
virtual void _stop();
virtual void _seek( U32 sample );
virtual U32 _tell() const;
public:
///
static SFXDSVoice* create( SFXDSDevice *device,
SFXDSBuffer *buffer );
///
virtual ~SFXDSVoice();
// SFXVoice
void setMinMaxDistance( F32 min, F32 max );
void play( bool looping );
void setVelocity( const VectorF& velocity );
void setTransform( const MatrixF& transform );
void setVolume( F32 volume );
void setPitch( F32 pitch );
void setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume );
};
#endif // _SFXDSBUFFER_H_

View file

@ -43,36 +43,117 @@ bool SFXSndStream::_readHeader()
vio_data.offset = 0;
vio_data.data = mStream;
vio_data.sampleBlockAlign = 1;
vio_data.byteBlockAlign = 0;
if ((sndFile = sf_open_virtual(&vio, SFM_READ, &sfinfo, &vio_data)) == NULL)
{
Con::printf("SFXSndStream - _readHeader failed: %s", sf_strerror(sndFile));
return false;
}
S32 bitsPerSample = 0;
switch ((sfinfo.format & SF_FORMAT_SUBMASK))
S32 bitsPerSample = 16;
switch (sfinfo.format & SF_FORMAT_SUBMASK)
{
case SF_FORMAT_PCM_S8:
case SF_FORMAT_PCM_U8:
bitsPerSample = 8;
mSampleType = Sample_Int8; // Still decode using sf_readf_short()
break;
case SF_FORMAT_PCM_16:
bitsPerSample = 16;
mSampleType = Sample_Int16;
break;
case SF_FORMAT_VORBIS:
case SF_FORMAT_PCM_24:
case SF_FORMAT_PCM_32:
case SF_FORMAT_FLOAT:
bitsPerSample = 16;
sf_command(sndFile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
case SF_FORMAT_DOUBLE:
case SF_FORMAT_VORBIS:
case SF_FORMAT_OPUS:
case SF_FORMAT_ALAC_20:
case SF_FORMAT_ALAC_24:
case SF_FORMAT_ALAC_32:
case 0x0080/*SF_FORMAT_MPEG_LAYER_I*/:
case 0x0081/*SF_FORMAT_MPEG_LAYER_II*/:
case 0x0082/*SF_FORMAT_MPEG_LAYER_III*/:
bitsPerSample = 32;
mSampleType = Sample_Float;
break;
default:
// missed, set it to 16 anyway.
case SF_FORMAT_IMA_ADPCM:
bitsPerSample = 16;
mSampleType = Sample_IMA4;
break;
case SF_FORMAT_MS_ADPCM:
bitsPerSample = 16;
mSampleType = Sample_MSADPCM;
break;
default:
bitsPerSample = 16;
mSampleType = Sample_Int16;
break;
}
mFormat.set(sfinfo.channels, bitsPerSample * sfinfo.channels, sfinfo.samplerate);
//------------------------------------------------------------
// Block alignment logic for ADPCM formats
//------------------------------------------------------------
int byteBlockAlign = 0;
int sampleBlockAlign = 1;
if (mSampleType == Sample_IMA4 || mSampleType == Sample_MSADPCM)
{
SF_CHUNK_INFO inf = { "fmt ", 4, 0, NULL };
SF_CHUNK_ITERATOR* iter = sf_get_chunk_iterator(sndFile, &inf);
if (!iter || sf_get_chunk_size(iter, &inf) != SF_ERR_NO_ERROR || inf.datalen < 14)
mSampleType = Sample_Int16;
else
{
uint8_t* fmtbuf = (uint8_t*)malloc(inf.datalen);
inf.data = fmtbuf;
if (sf_get_chunk_data(iter, &inf) != SF_ERR_NO_ERROR)
mSampleType = Sample_Int16;
else
{
byteBlockAlign = fmtbuf[12] | (fmtbuf[13] << 8);
int ch = sfinfo.channels;
if (mSampleType == Sample_IMA4)
sampleBlockAlign = (byteBlockAlign / ch - 4) / 4 * 8 + 1;
else
sampleBlockAlign = (byteBlockAlign / ch - 7) * 2 + 2;
}
dFree(fmtbuf);
}
}
//------------------------------------------------------------
// Commit alignment to class + VIO data
//------------------------------------------------------------
if (mSampleType == Sample_Int16)
{
sampleBlockAlign = 1;
byteBlockAlign = sfinfo.channels * 2;
}
else if (mSampleType == Sample_Float)
{
sampleBlockAlign = 1;
byteBlockAlign = sfinfo.channels * 4;
}
vio_data.sampleBlockAlign = sampleBlockAlign;
vio_data.byteBlockAlign = byteBlockAlign;
mSampleBlockAlign = sampleBlockAlign;
mByteBlockAlign = byteBlockAlign;
mFormat.set(sfinfo.channels, bitsPerSample * sfinfo.channels, sfinfo.samplerate, mSampleType);
mSamples = sfinfo.frames;
@ -136,22 +217,20 @@ U32 SFXSndStream::read(U8* buffer, U32 length)
U32 framesRead = 0;
switch (sfinfo.format & SF_FORMAT_SUBMASK)
switch (mSampleType)
{
case SF_FORMAT_PCM_S8:
case SF_FORMAT_PCM_U8:
framesRead = sf_readf_int(sndFile, (int*)buffer, framesToRead);
case SFXSampleType::Sample_Int8: framesRead = sf_readf_int(sndFile, (int*)buffer, framesToRead);
break;
case SF_FORMAT_PCM_16:
case SF_FORMAT_VORBIS:
case SF_FORMAT_PCM_24:
case SF_FORMAT_PCM_32:
case SF_FORMAT_FLOAT:
framesRead = sf_readf_short(sndFile, (short*)buffer, framesToRead);
case SFXSampleType::Sample_Int16: framesRead = sf_readf_short(sndFile, (short*)buffer, framesToRead);
break;
case SFXSampleType::Sample_Float: framesRead = sf_readf_float(sndFile, (float*)buffer, framesToRead);
break;
case SFXSampleType::Sample_IMA4:
case SFXSampleType::Sample_MSADPCM:
framesRead = sf_read_raw(sndFile, buffer, framesToRead);
break;
default:
Con::errorf("SFXSndStream - read: Unsupported format.");
return 0;
break;
}
if (framesRead != framesToRead)

View file

@ -39,11 +39,18 @@ public:
protected:
SFXSampleType mSampleType;
S32 mSampleBlockAlign;
S32 mByteBlockAlign;
// setup our vio_data struct.
typedef struct
{
sf_count_t offset, length;
Stream* data;
S32 sampleBlockAlign;
S32 byteBlockAlign;
} VIO_DATA;
/// Total number of bytes read from the stream so far.
@ -58,11 +65,11 @@ protected:
// vio callbacks
static sf_count_t sndSeek(sf_count_t offset, int whence, void* user_data);
static sf_count_t sndRead(void *ptr, sf_count_t count, void* user_data);
static sf_count_t sndRead(void* ptr, sf_count_t count, void* user_data);
static sf_count_t sndWrite(const void* ptr, sf_count_t count, void* user_data);
static sf_count_t sndTell(void* user_data);
static sf_count_t sndFileLen(void* user_data);
// SFXStream
bool _readHeader() override;
void _close() override;

View file

@ -24,15 +24,30 @@
#include "sfx/null/sfxNullBuffer.h"
#include "sfx/sfxInternal.h"
SFXNullDevice::SFXNullDevice( SFXProvider* provider,
String name,
bool useHardware,
S32 maxBuffers )
: SFXDevice( name, provider, useHardware, maxBuffers )
class SFXNULLRegisterProvider
{
mMaxBuffers = getMax( maxBuffers, 8 );
public:
SFXNULLRegisterProvider()
{
SFXSystem::getRegisterProviderSignal().notify(&SFXNullDevice::enumerateProviders);
}
};
static SFXNULLRegisterProvider pSFXNULLRegisterProvider;
SFXProvider::CreateProviderInstanceDelegate SFXNullDevice::mCreateDeviceInstance(SFXNullDevice::createInstance);
SFXDevice* SFXNullDevice::createInstance(U32 providerIndex)
{
SFXNullDevice* dev = new SFXNullDevice(providerIndex);
return dev;
}
SFXNullDevice::SFXNullDevice( U32 providerIndex )
{
mMaxBuffers = 8;
}
SFXNullDevice::~SFXNullDevice()
@ -65,6 +80,17 @@ SFXVoice* SFXNullDevice::createVoice( bool is3D, SFXBuffer *buffer )
return voice;
}
void SFXNullDevice::enumerateProviders(Vector<SFXProvider*>& providerList)
{
SFXProvider* toAdd = new SFXProvider;
toAdd->mName = String::ToString("SFX Null Device");
toAdd->mIndex = providerList.size();
toAdd->mDeviceType = Output;
toAdd->mType = NullProvider;
toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance;
providerList.push_back(toAdd);
}
void SFXNullDevice::update()
{
// Do nothing. Prevent SFXDevice from running

View file

@ -23,8 +23,6 @@
#ifndef _SFXNULLDEVICE_H_
#define _SFXNULLDEVICE_H_
class SFXProvider;
#ifndef _SFXDEVICE_H_
#include "sfx/sfxDevice.h"
#endif
@ -37,27 +35,28 @@ class SFXProvider;
#ifndef _SFXNULLVOICE_H_
#include "sfx/null/sfxNullVoice.h"
#endif
#ifndef _SFXSYSTEM_H_
#include "sfx/sfxSystem.h"
#endif
class SFXNullDevice : public SFXDevice
{
typedef SFXDevice Parent;
protected:
static SFXProvider::CreateProviderInstanceDelegate mCreateDeviceInstance;
public:
public:
static void enumerateProviders(Vector<SFXProvider*>& providerList);
SFXNullDevice( U32 providerIndex );
static SFXDevice* createInstance(U32 adapterIndex);
virtual ~SFXNullDevice();
SFXNullDevice( SFXProvider* provider,
String name,
bool useHardware,
S32 maxBuffers );
public:
virtual ~SFXNullDevice();
public:
// SFXDevice.
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
void update() override;
// SFXDevice.
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
void update() override;
};
#endif // _SFXNULLDEVICE_H_
#endif // _SFXNULLDEVICE_H_

View file

@ -1,98 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/sfxProvider.h"
#include "sfx/null/sfxNullDevice.h"
#include "core/strings/stringFunctions.h"
#include "core/module.h"
class SFXNullProvider : public SFXProvider
{
public:
SFXNullProvider()
: SFXProvider( "Null" ) {}
virtual ~SFXNullProvider();
protected:
void addDeviceDesc( const String& name, const String& desc );
void init() override;
public:
SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers ) override;
};
MODULE_BEGIN( SFXNull )
MODULE_INIT_BEFORE( SFX )
MODULE_SHUTDOWN_AFTER( SFX )
SFXNullProvider* mProvider;
MODULE_INIT
{
mProvider = new SFXNullProvider;
}
MODULE_SHUTDOWN
{
delete mProvider;
}
MODULE_END;
void SFXNullProvider::init()
{
regProvider( this );
addDeviceDesc( "Null", "SFX Null Device" );
}
SFXNullProvider::~SFXNullProvider()
{
}
void SFXNullProvider::addDeviceDesc( const String& name, const String& desc )
{
SFXDeviceInfo* info = new SFXDeviceInfo;
info->internalName = desc;
info->name = "Null Device";
info->driver = name;
info->hasHardware = false;
info->maxBuffers = 8;
mDeviceInfo.push_back( info );
}
SFXDevice* SFXNullProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
{
SFXDeviceInfo* info = _findDeviceInfo( deviceName );
// Do we find one to create?
if ( info )
return new SFXNullDevice( this, info->internalName, useHardware, maxBuffers );
return NULL;
}

View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2006, Creative Labs Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the distribution.
* * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// Based on Openal-soft router code.
#include "sfx/openal/LoadOAL.h"
#include "console/console.h"
#if defined(TORQUE_OS_WIN)
#include <windows.h>
#else
#include <dirent.h>
#include <sys/types.h>
#endif
LIB_HANDLE openaAlDll = NULL;
#define LOAD_REQUIRED(table, x) \
table->x = reinterpret_cast<decltype(table->x)>(reinterpret_cast<void*>( \
GET_PROC_ADDRESS(openaAlDll, #x))); \
if(!table->x) \
{ \
Con::warnf("Failed to find entry point :%s\n", #x); \
loadok = false; \
}
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE oal)
{
if (!oal)
return AL_FALSE;
if (szOALFullPathName)
openaAlDll = LOAD_LIBRARY(szOALFullPathName);
else
{
#if defined(TORQUE_OS_WIN)
openaAlDll = LOAD_LIBRARY("openal32.dll");
#elif defined(TORQUE_OS_LINUX)
openaAlDll = LOAD_LIBRARY("libopenal.so");
#elif defined(TORQUE_OS_MAC)
openaAlDll = LOAD_LIBRARY("@rpath/libopenal.1.24.3.dylib");
#endif
}
if (!openaAlDll)
return AL_FALSE;
bool loadok = true;
LOAD_REQUIRED(oal, alcCreateContext);
LOAD_REQUIRED(oal, alcMakeContextCurrent);
LOAD_REQUIRED(oal, alcProcessContext);
LOAD_REQUIRED(oal, alcSuspendContext);
LOAD_REQUIRED(oal, alcDestroyContext);
LOAD_REQUIRED(oal, alcGetCurrentContext);
LOAD_REQUIRED(oal, alcGetContextsDevice);
LOAD_REQUIRED(oal, alcOpenDevice);
LOAD_REQUIRED(oal, alcCloseDevice);
LOAD_REQUIRED(oal, alcGetError);
LOAD_REQUIRED(oal, alcIsExtensionPresent);
LOAD_REQUIRED(oal, alcGetProcAddress);
LOAD_REQUIRED(oal, alcGetEnumValue);
LOAD_REQUIRED(oal, alcGetString);
LOAD_REQUIRED(oal, alcGetIntegerv);
LOAD_REQUIRED(oal, alcCaptureOpenDevice);
LOAD_REQUIRED(oal, alcCaptureCloseDevice);
LOAD_REQUIRED(oal, alcCaptureStart);
LOAD_REQUIRED(oal, alcCaptureStop);
LOAD_REQUIRED(oal, alcCaptureSamples);
LOAD_REQUIRED(oal, alEnable);
LOAD_REQUIRED(oal, alDisable);
LOAD_REQUIRED(oal, alIsEnabled);
LOAD_REQUIRED(oal, alGetString);
LOAD_REQUIRED(oal, alGetBooleanv);
LOAD_REQUIRED(oal, alGetIntegerv);
LOAD_REQUIRED(oal, alGetFloatv);
LOAD_REQUIRED(oal, alGetDoublev);
LOAD_REQUIRED(oal, alGetBoolean);
LOAD_REQUIRED(oal, alGetInteger);
LOAD_REQUIRED(oal, alGetFloat);
LOAD_REQUIRED(oal, alGetDouble);
LOAD_REQUIRED(oal, alGetError);
LOAD_REQUIRED(oal, alIsExtensionPresent);
LOAD_REQUIRED(oal, alGetProcAddress);
LOAD_REQUIRED(oal, alGetEnumValue);
LOAD_REQUIRED(oal, alListenerf);
LOAD_REQUIRED(oal, alListener3f);
LOAD_REQUIRED(oal, alListenerfv);
LOAD_REQUIRED(oal, alListeneri);
LOAD_REQUIRED(oal, alListener3i);
LOAD_REQUIRED(oal, alListeneriv);
LOAD_REQUIRED(oal, alGetListenerf);
LOAD_REQUIRED(oal, alGetListener3f);
LOAD_REQUIRED(oal, alGetListenerfv);
LOAD_REQUIRED(oal, alGetListeneri);
LOAD_REQUIRED(oal, alGetListener3i);
LOAD_REQUIRED(oal, alGetListeneriv);
LOAD_REQUIRED(oal, alGenSources);
LOAD_REQUIRED(oal, alDeleteSources);
LOAD_REQUIRED(oal, alIsSource);
LOAD_REQUIRED(oal, alSourcef);
LOAD_REQUIRED(oal, alSource3f);
LOAD_REQUIRED(oal, alSourcefv);
LOAD_REQUIRED(oal, alSourcei);
LOAD_REQUIRED(oal, alSource3i);
LOAD_REQUIRED(oal, alSourceiv);
LOAD_REQUIRED(oal, alGetSourcef);
LOAD_REQUIRED(oal, alGetSource3f);
LOAD_REQUIRED(oal, alGetSourcefv);
LOAD_REQUIRED(oal, alGetSourcei);
LOAD_REQUIRED(oal, alGetSource3i);
LOAD_REQUIRED(oal, alGetSourceiv);
LOAD_REQUIRED(oal, alSourcePlayv);
LOAD_REQUIRED(oal, alSourceStopv);
LOAD_REQUIRED(oal, alSourceRewindv);
LOAD_REQUIRED(oal, alSourcePausev);
LOAD_REQUIRED(oal, alSourcePlay);
LOAD_REQUIRED(oal, alSourceStop);
LOAD_REQUIRED(oal, alSourceRewind);
LOAD_REQUIRED(oal, alSourcePause);
LOAD_REQUIRED(oal, alSourceQueueBuffers);
LOAD_REQUIRED(oal, alSourceUnqueueBuffers);
LOAD_REQUIRED(oal, alGenBuffers);
LOAD_REQUIRED(oal, alDeleteBuffers);
LOAD_REQUIRED(oal, alIsBuffer);
LOAD_REQUIRED(oal, alBufferData);
LOAD_REQUIRED(oal, alDopplerFactor);
LOAD_REQUIRED(oal, alDopplerVelocity);
LOAD_REQUIRED(oal, alSpeedOfSound);
LOAD_REQUIRED(oal, alDistanceModel);
// these are optional.
LOAD_REQUIRED(oal, alBufferf);
LOAD_REQUIRED(oal, alBuffer3f);
LOAD_REQUIRED(oal, alBufferfv);
LOAD_REQUIRED(oal, alBufferi);
LOAD_REQUIRED(oal, alBuffer3i);
LOAD_REQUIRED(oal, alBufferiv);
LOAD_REQUIRED(oal, alGetBufferf);
LOAD_REQUIRED(oal, alGetBuffer3f);
LOAD_REQUIRED(oal, alGetBufferfv);
LOAD_REQUIRED(oal, alGetBufferi);
LOAD_REQUIRED(oal, alGetBuffer3i);
LOAD_REQUIRED(oal, alGetBufferiv);
return AL_TRUE;
}
ALvoid UnloadOAL10Library()
{
// Unload the dll
if (openaAlDll)
CLOSE_LIBRARY(openaAlDll);
}

View file

@ -24,26 +24,52 @@
#define _LOADOAL_H_
#ifndef _PLATFORM_H_
# include "platform/platform.h"
#include "platform/platform.h"
#endif
#if defined(TORQUE_OS_MAC)
#undef AL_ALEXT_PROTOTYPES
# include <OpenAL/al.h>
# include <OpenAL/alc.h>
#elif defined(TORQUE_OS_LINUX)
# include <AL/al.h>
# include <AL/alc.h>
# include <AL/alext.h>
# include <AL/efx.h>
# include <AL/efx-presets.h>
#else
# include <al/al.h>
# include <al/alc.h>
# include <AL/alext.h>
# include <AL/efx-presets.h>
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _PATH_H_
#include "core/util/path.h"
#endif
// Since openal is deprecated and we pack the lib into the mac bundle, all
// platforms now support all of these.
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alext.h>
#include <AL/efx.h>
#include <AL/efx-presets.h>
#ifndef _OPENALFNTABLE
#define _OPENALFNTABLE
#if defined(TORQUE_OS_WIN)
#include <windows.h>
#define LIB_HANDLE HINSTANCE
#define LOAD_LIBRARY(path) LoadLibraryA(path)
#define GET_PROC_ADDRESS(lib, name) GetProcAddress(lib, name)
#define CLOSE_LIBRARY(lib) FreeLibrary(lib)
#define LIB_EXTENSION L".dll"
#else
#include <dlfcn.h>
#define LIB_HANDLE void*
#define LOAD_LIBRARY(path) dlopen(path, RTLD_LAZY)
#define GET_PROC_ADDRESS(lib, name) dlsym(lib, name)
#define CLOSE_LIBRARY(lib) dlclose(lib)
#ifdef __APPLE__
#define LIB_EXTENSION ".dylib"
#else
#define LIB_EXTENSION ".so"
#endif
#endif
constexpr auto MakeALCVer(int major, int minor) noexcept -> int {
return (major << 8) | minor;
}
#ifndef ALAPIENTRY
#define ALAPIENTRY
#endif
@ -52,11 +78,6 @@
#define ALCAPIENTRY
#endif
// Open AL Function table definition
#ifndef _OPENALFNTABLE
#define _OPENALFNTABLE
// AL 1.0 did not define the ALchar and ALCchar types, so define them here
// if they don't exist
@ -68,110 +89,148 @@
#define ALCchar char
#endif
typedef struct
struct OPENALFNTABLE
{
LPALENABLE alEnable;
LPALDISABLE alDisable;
LPALISENABLED alIsEnabled;
LPALGETBOOLEAN alGetBoolean;
LPALGETINTEGER alGetInteger;
LPALGETFLOAT alGetFloat;
LPALGETDOUBLE alGetDouble;
LPALGETBOOLEANV alGetBooleanv;
LPALGETINTEGERV alGetIntegerv;
LPALGETFLOATV alGetFloatv;
LPALGETDOUBLEV alGetDoublev;
LPALGETSTRING alGetString;
LPALGETERROR alGetError;
LPALISEXTENSIONPRESENT alIsExtensionPresent;
LPALGETPROCADDRESS alGetProcAddress;
LPALGETENUMVALUE alGetEnumValue;
LPALLISTENERI alListeneri;
LPALLISTENERF alListenerf;
LPALLISTENER3F alListener3f;
LPALLISTENERFV alListenerfv;
LPALGETLISTENERI alGetListeneri;
LPALGETLISTENERF alGetListenerf;
LPALGETLISTENER3F alGetListener3f;
LPALGETLISTENERFV alGetListenerfv;
LPALGENSOURCES alGenSources;
LPALDELETESOURCES alDeleteSources;
LPALISSOURCE alIsSource;
LPALSOURCEI alSourcei;
LPALSOURCEF alSourcef;
LPALSOURCE3I alSource3i;
LPALSOURCE3F alSource3f;
LPALSOURCEFV alSourcefv;
LPALGETSOURCEI alGetSourcei;
LPALGETSOURCEF alGetSourcef;
LPALGETSOURCEFV alGetSourcefv;
LPALSOURCEPLAYV alSourcePlayv;
LPALSOURCESTOPV alSourceStopv;
LPALSOURCEPLAY alSourcePlay;
LPALSOURCEPAUSE alSourcePause;
LPALSOURCESTOP alSourceStop;
LPALSOURCEREWIND alSourceRewind;
LPALGENBUFFERS alGenBuffers;
LPALDELETEBUFFERS alDeleteBuffers;
LPALISBUFFER alIsBuffer;
LPALBUFFERDATA alBufferData;
LPALGETBUFFERI alGetBufferi;
LPALGETBUFFERF alGetBufferf;
LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers;
LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers;
LPALDISTANCEMODEL alDistanceModel;
LPALDOPPLERFACTOR alDopplerFactor;
LPALDOPPLERVELOCITY alDopplerVelocity;
LPALCGETSTRING alcGetString;
LPALCGETINTEGERV alcGetIntegerv;
LPALCOPENDEVICE alcOpenDevice;
LPALCCLOSEDEVICE alcCloseDevice;
LPALCCREATECONTEXT alcCreateContext;
LPALCMAKECONTEXTCURRENT alcMakeContextCurrent;
LPALCPROCESSCONTEXT alcProcessContext;
LPALCGETCURRENTCONTEXT alcGetCurrentContext;
LPALCGETCONTEXTSDEVICE alcGetContextsDevice;
LPALCSUSPENDCONTEXT alcSuspendContext;
LPALCDESTROYCONTEXT alcDestroyContext;
LPALCGETERROR alcGetError;
LPALCISEXTENSIONPRESENT alcIsExtensionPresent;
LPALCGETPROCADDRESS alcGetProcAddress;
LPALCGETENUMVALUE alcGetEnumValue;
#if defined(AL_ALEXT_PROTOTYPES)
LPALGENEFFECTS alGenEffects;
LPALDELETEEFFECTS alDeleteEffects;
LPALISEFFECT alIsEffect;
LPALEFFECTI alEffecti;
LPALEFFECTIV alEffectiv;
LPALEFFECTF alEffectf;
LPALEFFECTFV alEffectfv;
LPALGETEFFECTI alGetEffecti;
LPALGETEFFECTIV alGetEffectiv;
LPALGETEFFECTF alGetEffectf;
LPALGETEFFECTFV alGetEffectfv;
LPALRELEASEALEFFECTS alReleaseEffects;
LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
LPALGENFILTERS alGenFilters;
LPALDELETEFILTERS alDeleteFilters;
LPALFILTERI alFilteri;
LPALCGETSTRINGISOFT alcGetStringiSOFT;
LPALCCREATECONTEXT alcCreateContext{ nullptr };
LPALCMAKECONTEXTCURRENT alcMakeContextCurrent{ nullptr };
LPALCPROCESSCONTEXT alcProcessContext{ nullptr };
LPALCSUSPENDCONTEXT alcSuspendContext{ nullptr };
LPALCDESTROYCONTEXT alcDestroyContext{ nullptr };
LPALCGETCURRENTCONTEXT alcGetCurrentContext{ nullptr };
LPALCGETCONTEXTSDEVICE alcGetContextsDevice{ nullptr };
LPALCOPENDEVICE alcOpenDevice{ nullptr };
LPALCCLOSEDEVICE alcCloseDevice{ nullptr };
LPALCGETERROR alcGetError{ nullptr };
LPALCISEXTENSIONPRESENT alcIsExtensionPresent{ nullptr };
LPALCGETPROCADDRESS alcGetProcAddress{ nullptr };
LPALCGETENUMVALUE alcGetEnumValue{ nullptr };
LPALCGETSTRING alcGetString{ nullptr };
LPALCGETINTEGERV alcGetIntegerv{ nullptr };
LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice{ nullptr };
LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice{ nullptr };
LPALCCAPTURESTART alcCaptureStart{ nullptr };
LPALCCAPTURESTOP alcCaptureStop{ nullptr };
LPALCCAPTURESAMPLES alcCaptureSamples{ nullptr };
PFNALCSETTHREADCONTEXTPROC alcSetThreadContext{ nullptr };
PFNALCGETTHREADCONTEXTPROC alcGetThreadContext{ nullptr };
LPALENABLE alEnable{ nullptr };
LPALDISABLE alDisable{ nullptr };
LPALISENABLED alIsEnabled{ nullptr };
LPALGETSTRING alGetString{ nullptr };
LPALGETBOOLEANV alGetBooleanv{ nullptr };
LPALGETINTEGERV alGetIntegerv{ nullptr };
LPALGETFLOATV alGetFloatv{ nullptr };
LPALGETDOUBLEV alGetDoublev{ nullptr };
LPALGETBOOLEAN alGetBoolean{ nullptr };
LPALGETINTEGER alGetInteger{ nullptr };
LPALGETFLOAT alGetFloat{ nullptr };
LPALGETDOUBLE alGetDouble{ nullptr };
LPALGETERROR alGetError{ nullptr };
LPALISEXTENSIONPRESENT alIsExtensionPresent{ nullptr };
LPALGETPROCADDRESS alGetProcAddress{ nullptr };
LPALGETENUMVALUE alGetEnumValue{ nullptr };
LPALLISTENERF alListenerf{ nullptr };
LPALLISTENER3F alListener3f{ nullptr };
LPALLISTENERFV alListenerfv{ nullptr };
LPALLISTENERI alListeneri{ nullptr };
LPALLISTENER3I alListener3i{ nullptr };
LPALLISTENERIV alListeneriv{ nullptr };
LPALGETLISTENERF alGetListenerf{ nullptr };
LPALGETLISTENER3F alGetListener3f{ nullptr };
LPALGETLISTENERFV alGetListenerfv{ nullptr };
LPALGETLISTENERI alGetListeneri{ nullptr };
LPALGETLISTENER3I alGetListener3i{ nullptr };
LPALGETLISTENERIV alGetListeneriv{ nullptr };
LPALGENSOURCES alGenSources{ nullptr };
LPALDELETESOURCES alDeleteSources{ nullptr };
LPALISSOURCE alIsSource{ nullptr };
LPALSOURCEF alSourcef{ nullptr };
LPALSOURCE3F alSource3f{ nullptr };
LPALSOURCEFV alSourcefv{ nullptr };
LPALSOURCEI alSourcei{ nullptr };
LPALSOURCE3I alSource3i{ nullptr };
LPALSOURCEIV alSourceiv{ nullptr };
LPALGETSOURCEF alGetSourcef{ nullptr };
LPALGETSOURCE3F alGetSource3f{ nullptr };
LPALGETSOURCEFV alGetSourcefv{ nullptr };
LPALGETSOURCEI alGetSourcei{ nullptr };
LPALGETSOURCE3I alGetSource3i{ nullptr };
LPALGETSOURCEIV alGetSourceiv{ nullptr };
LPALSOURCEPLAYV alSourcePlayv{ nullptr };
LPALSOURCESTOPV alSourceStopv{ nullptr };
LPALSOURCEREWINDV alSourceRewindv{ nullptr };
LPALSOURCEPAUSEV alSourcePausev{ nullptr };
LPALSOURCEPLAY alSourcePlay{ nullptr };
LPALSOURCESTOP alSourceStop{ nullptr };
LPALSOURCEREWIND alSourceRewind{ nullptr };
LPALSOURCEPAUSE alSourcePause{ nullptr };
LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers{ nullptr };
LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers{ nullptr };
LPALGENBUFFERS alGenBuffers{ nullptr };
LPALDELETEBUFFERS alDeleteBuffers{ nullptr };
LPALISBUFFER alIsBuffer{ nullptr };
LPALBUFFERF alBufferf{ nullptr };
LPALBUFFER3F alBuffer3f{ nullptr };
LPALBUFFERFV alBufferfv{ nullptr };
LPALBUFFERI alBufferi{ nullptr };
LPALBUFFER3I alBuffer3i{ nullptr };
LPALBUFFERIV alBufferiv{ nullptr };
LPALGETBUFFERF alGetBufferf{ nullptr };
LPALGETBUFFER3F alGetBuffer3f{ nullptr };
LPALGETBUFFERFV alGetBufferfv{ nullptr };
LPALGETBUFFERI alGetBufferi{ nullptr };
LPALGETBUFFER3I alGetBuffer3i{ nullptr };
LPALGETBUFFERIV alGetBufferiv{ nullptr };
LPALBUFFERDATA alBufferData{ nullptr };
LPALDOPPLERFACTOR alDopplerFactor{ nullptr };
LPALDOPPLERVELOCITY alDopplerVelocity{ nullptr };
LPALSPEEDOFSOUND alSpeedOfSound{ nullptr };
LPALDISTANCEMODEL alDistanceModel{ nullptr };
/* Functions to load after first context creation. */
LPALGENFILTERS alGenFilters{ nullptr };
LPALDELETEFILTERS alDeleteFilters{ nullptr };
LPALISFILTER alIsFilter{ nullptr };
LPALFILTERF alFilterf{ nullptr };
LPALFILTERFV alFilterfv{ nullptr };
LPALFILTERI alFilteri{ nullptr };
LPALFILTERIV alFilteriv{ nullptr };
LPALGETFILTERF alGetFilterf{ nullptr };
LPALGETFILTERFV alGetFilterfv{ nullptr };
LPALGETFILTERI alGetFilteri{ nullptr };
LPALGETFILTERIV alGetFilteriv{ nullptr };
LPALGENEFFECTS alGenEffects{ nullptr };
LPALDELETEEFFECTS alDeleteEffects{ nullptr };
LPALISEFFECT alIsEffect{ nullptr };
LPALEFFECTF alEffectf{ nullptr };
LPALEFFECTFV alEffectfv{ nullptr };
LPALEFFECTI alEffecti{ nullptr };
LPALEFFECTIV alEffectiv{ nullptr };
LPALGETEFFECTF alGetEffectf{ nullptr };
LPALGETEFFECTFV alGetEffectfv{ nullptr };
LPALGETEFFECTI alGetEffecti{ nullptr };
LPALGETEFFECTIV alGetEffectiv{ nullptr };
LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{ nullptr };
LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{ nullptr };
LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{ nullptr };
LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{ nullptr };
LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{ nullptr };
LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{ nullptr };
LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{ nullptr };
LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{ nullptr };
LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{ nullptr };
LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{ nullptr };
LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{ nullptr };
};
using LPOPENALFNTABLE = OPENALFNTABLE*;
#endif
} OPENALFNTABLE, *LPOPENALFNTABLE;
#endif
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable);
ALboolean LoadOAL10Library(char* szOALFullPathName, LPOPENALFNTABLE lpOALFnTable);
ALvoid UnloadOAL10Library();
#endif // _LOADOAL_H_

View file

@ -1,303 +0,0 @@
/*
* Copyright (c) 2006, Creative Labs Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the distribution.
* * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "core/strings/stringFunctions.h"
#include "aldlist.h"
#if defined(TORQUE_OS_MAC)
#include <OpenAL/alc.h>
#elif defined(TORQUE_OS_LINUX)
#include <AL/alc.h>
#else
#include <al/alc.h>
#endif
/*
* Init call
*/
ALDeviceList::ALDeviceList( const OPENALFNTABLE& oalft )
{
VECTOR_SET_ASSOCIATION( vDeviceInfo );
ALDEVICEINFO ALDeviceInfo;
char *devices;
int index;
const char *defaultDeviceName;
const char *actualDeviceName;
dMemcpy( &ALFunction, &oalft, sizeof(OPENALFNTABLE) );
// DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
vDeviceInfo.clear();
vDeviceInfo.reserve(10);
defaultDeviceIndex = 0;
// grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices
if (ALFunction.alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) {
devices = (char *)ALFunction.alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
defaultDeviceName = (char *)ALFunction.alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
}
else
{
devices = (char *)ALFunction.alcGetString(NULL, ALC_DEVICE_SPECIFIER);
defaultDeviceName = (char *)ALFunction.alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
}
index = 0;
// go through device list (each device terminated with a single NULL, list terminated with double NULL)
while (*devices != '\0') {
if (String::compare(defaultDeviceName, devices) == 0) {
defaultDeviceIndex = index;
}
ALCdevice* device = ALFunction.alcOpenDevice(devices);
if (device)
{
ALCcontext* ctx = ALFunction.alcCreateContext(device, nullptr);
if (ctx)
{
ALFunction.alcMakeContextCurrent(ctx);
actualDeviceName = ALFunction.alcGetString(device, ALC_DEVICE_SPECIFIER);
bool bNewName = true;
if (actualDeviceName)
{
for (int i = 0; i < GetNumDevices(); i++) {
if (String::compare(GetDeviceName(i), devices) == 0) {
bNewName = false;
}
}
}
if ((bNewName) && (actualDeviceName != NULL) && (dStrlen(actualDeviceName) > 0))
{
dMemset(&ALDeviceInfo, 0, sizeof(ALDEVICEINFO));
ALDeviceInfo.bSelected = true;
dStrncpy(ALDeviceInfo.strDeviceName, actualDeviceName, sizeof(ALDeviceInfo.strDeviceName));
char deviceExternal[256];
dStrcpy(deviceExternal, devices, 256);
vDeviceInfo.push_back(ALDeviceInfo);
}
ALFunction.alcMakeContextCurrent(nullptr);
ALFunction.alcDestroyContext(ctx);
}
ALFunction.alcCloseDevice(device);
}
devices += dStrlen(devices) + 1;
index += 1;
}
ResetFilters();
}
/*
* Exit call
*/
ALDeviceList::~ALDeviceList()
{
}
/*
* Returns the number of devices in the complete device list
*/
int ALDeviceList::GetNumDevices()
{
return (int)vDeviceInfo.size();
}
/*
* Returns the device name at an index in the complete device list
*/
const char* ALDeviceList::GetDeviceName(int index)
{
if (index < GetNumDevices())
return vDeviceInfo[index].strDeviceName;
else
return NULL;
}
/*
* Returns the major and minor version numbers for a device at a specified index in the complete list
*/
void ALDeviceList::GetDeviceVersion(int index, int *major, int *minor)
{
if (index < GetNumDevices()) {
if (major)
*major = vDeviceInfo[index].iMajorVersion;
if (minor)
*minor = vDeviceInfo[index].iMinorVersion;
}
return;
}
/*
* Returns the maximum number of Sources that can be generate on the given device
*/
U32 ALDeviceList::GetMaxNumSources(S32 index)
{
if (index < GetNumDevices())
return vDeviceInfo[index].uiSourceCount;
else
return 0;
}
/*
* Checks if the extension is supported on the given device
*/
bool ALDeviceList::IsExtensionSupported(int index, SFXALCaps cap)
{
bool bReturn = false;
if (index < GetNumDevices())
bReturn = vDeviceInfo[index].iCapsFlags & cap;
return bReturn;
}
/*
* returns the index of the default device in the complete device list
*/
int ALDeviceList::GetDefaultDevice()
{
return defaultDeviceIndex;
}
/*
* Deselects devices which don't have the specified minimum version
*/
void ALDeviceList::FilterDevicesMinVer(S32 major, S32 minor)
{
int dMajor, dMinor;
for (U32 i = 0; i < vDeviceInfo.size(); i++) {
GetDeviceVersion(i, &dMajor, &dMinor);
if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
vDeviceInfo[i].bSelected = false;
}
}
}
/*
* Deselects devices which don't have the specified maximum version
*/
void ALDeviceList::FilterDevicesMaxVer(S32 major, S32 minor)
{
S32 dMajor, dMinor;
for (U32 i = 0; i < vDeviceInfo.size(); i++) {
GetDeviceVersion(i, &dMajor, &dMinor);
if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
vDeviceInfo[i].bSelected = false;
}
}
}
/*
* Deselects device which don't support the given extension name
*/
void ALDeviceList::FilterDevicesExtension(SFXALCaps cap)
{
for (U32 i = 0; i < vDeviceInfo.size(); i++)
vDeviceInfo[i].bSelected = vDeviceInfo[i].iCapsFlags & cap;
}
/*
* Resets all filtering, such that all devices are in the list
*/
void ALDeviceList::ResetFilters()
{
for (S32 i = 0; i < GetNumDevices(); i++) {
vDeviceInfo[i].bSelected = true;
}
filterIndex = 0;
}
/*
* Gets index of first filtered device
*/
int ALDeviceList::GetFirstFilteredDevice()
{
int i;
for (i = 0; i < GetNumDevices(); i++) {
if (vDeviceInfo[i].bSelected == true) {
break;
}
}
filterIndex = i + 1;
return i;
}
/*
* Gets index of next filtered device
*/
int ALDeviceList::GetNextFilteredDevice()
{
int i;
for (i = filterIndex; i < GetNumDevices(); i++) {
if (vDeviceInfo[i].bSelected == true) {
break;
}
}
filterIndex = i + 1;
return i;
}
/*
* Internal function to detemine max number of Sources that can be generated
*/
unsigned int ALDeviceList::GetMaxNumSources()
{
ALuint uiSources[256];
U32 iSourceCount = 0;
// Clear AL Error Code
ALFunction.alGetError();
// Generate up to 256 Sources, checking for any errors
for (iSourceCount = 0; iSourceCount < 256; iSourceCount++)
{
ALFunction.alGenSources(1, &uiSources[iSourceCount]);
if (ALFunction.alGetError() != AL_NO_ERROR)
break;
}
// Release the Sources
ALFunction.alDeleteSources(iSourceCount, uiSources);
if (ALFunction.alGetError() != AL_NO_ERROR)
{
for (U32 i = 0; i < 256; i++)
{
ALFunction.alDeleteSources(1, &uiSources[i]);
}
}
return iSourceCount;
}

View file

@ -1,71 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef ALDEVICELIST_H
#define ALDEVICELIST_H
#pragma warning(disable: 4786) //disable warning "identifier was truncated to '255' characters in the browser information"
#include "core/util/tVector.h"
#include "core/stringTable.h"
#include "sfx/openal/sfxALCaps.h"
#include "LoadOAL.h"
typedef struct
{
char strDeviceName[256];
char strInternalDeviceName[256];
S32 iMajorVersion;
S32 iMinorVersion;
U32 uiSourceCount;
S32 iCapsFlags;
bool bSelected;
} ALDEVICEINFO, *LPALDEVICEINFO;
class ALDeviceList
{
private:
OPENALFNTABLE ALFunction;
Vector<ALDEVICEINFO> vDeviceInfo;
S32 defaultDeviceIndex;
S32 filterIndex;
public:
ALDeviceList ( const OPENALFNTABLE &oalft );
~ALDeviceList ();
S32 GetNumDevices();
const char *GetDeviceName(S32 index);
void GetDeviceVersion(S32 index, S32 *major, S32 *minor);
U32 GetMaxNumSources(S32 index);
bool IsExtensionSupported(S32 index, SFXALCaps caps);
S32 GetDefaultDevice();
void FilterDevicesMinVer(S32 major, S32 minor);
void FilterDevicesMaxVer(S32 major, S32 minor);
void FilterDevicesExtension(SFXALCaps caps);
void ResetFilters();
S32 GetFirstFilteredDevice();
S32 GetNextFilteredDevice();
private:
U32 GetMaxNumSources();
};
#endif // ALDEVICELIST_H

View file

@ -1,616 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// TODO: Implement OpenAL loading code which is currently stubbed out.
#if defined(__linux__) && !defined(TORQUE_OS_LINUX)
#define TORQUE_OS_LINUX
#endif
#include <dlfcn.h>
#include <err.h>
#include <string.h>
#include "sfx/openal/LoadOAL.h"
#include "console/console.h"
void* openal_library = NULL;
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable)
{
if (!lpOALFnTable)
return AL_FALSE;
if (szOALFullPathName)
openal_library = dlopen(szOALFullPathName, RTLD_NOW);
else
{
#ifdef TORQUE_DEBUG
openal_library = dlopen("libopenald.so.1", RTLD_NOW);
// If the .1 library is not found, try the normal filename
if (openal_library == NULL)
{
openal_library = dlopen("libopenald.so", RTLD_NOW);
}
#else
openal_library = dlopen("libopenal.so.1", RTLD_NOW);
// If the .1 library is not found, try the normal filename
if (openal_library == NULL)
{
openal_library = dlopen("libopenal.so", RTLD_NOW);
}
#endif
}
if (openal_library == NULL) {
Con::errorf("Failed to load OpenAL shared library. Sound will not be available");
return AL_FALSE;
}
memset(lpOALFnTable, 0, sizeof(OPENALFNTABLE));
lpOALFnTable->alEnable = (LPALENABLE)dlsym(openal_library,"alEnable");
if (lpOALFnTable->alEnable == NULL)
{
warn("Failed to retrieve 'alEnable' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDisable = (LPALDISABLE)dlsym(openal_library,"alDisable");
if (lpOALFnTable->alDisable == NULL)
{
warn("Failed to retrieve 'alDisable' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsEnabled = (LPALISENABLED)dlsym(openal_library,"alIsEnabled");
if (lpOALFnTable->alIsEnabled == NULL)
{
warn("Failed to retrieve 'alIsEnabled' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBoolean = (LPALGETBOOLEAN)dlsym(openal_library,"alGetBoolean");
if (lpOALFnTable->alGetBoolean == NULL)
{
warn("Failed to retrieve 'alGetBoolean' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetInteger = (LPALGETINTEGER)dlsym(openal_library,"alGetInteger");
if (lpOALFnTable->alGetInteger == NULL)
{
warn("Failed to retrieve 'alGetInteger' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetFloat = (LPALGETFLOAT)dlsym(openal_library,"alGetFloat");
if (lpOALFnTable->alGetFloat == NULL)
{
warn("Failed to retrieve 'alGetFloat' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetDouble = (LPALGETDOUBLE)dlsym(openal_library,"alGetDouble");
if (lpOALFnTable->alGetDouble == NULL)
{
warn("Failed to retrieve 'alGetDouble' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBooleanv = (LPALGETBOOLEANV)dlsym(openal_library,"alGetBooleanv");
if (lpOALFnTable->alGetBooleanv == NULL)
{
warn("Failed to retrieve 'alGetBooleanv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetIntegerv = (LPALGETINTEGERV)dlsym(openal_library,"alGetIntegerv");
if (lpOALFnTable->alGetIntegerv == NULL)
{
warn("Failed to retrieve 'alGetIntegerv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetFloatv = (LPALGETFLOATV)dlsym(openal_library,"alGetFloatv");
if (lpOALFnTable->alGetFloatv == NULL)
{
warn("Failed to retrieve 'alGetFloatv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetDoublev = (LPALGETDOUBLEV)dlsym(openal_library,"alGetDoublev");
if (lpOALFnTable->alGetDoublev == NULL)
{
warn("Failed to retrieve 'alGetDoublev' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetString = (LPALGETSTRING)dlsym(openal_library,"alGetString");
if (lpOALFnTable->alGetString == NULL)
{
warn("Failed to retrieve 'alGetString' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetError = (LPALGETERROR)dlsym(openal_library,"alGetError");
if (lpOALFnTable->alGetError == NULL)
{
warn("Failed to retrieve 'alGetError' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsExtensionPresent = (LPALISEXTENSIONPRESENT)dlsym(openal_library,"alIsExtensionPresent");
if (lpOALFnTable->alIsExtensionPresent == NULL)
{
warn("Failed to retrieve 'alIsExtensionPresent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetProcAddress = (LPALGETPROCADDRESS)dlsym(openal_library,"alGetProcAddress");
if (lpOALFnTable->alGetProcAddress == NULL)
{
warn("Failed to retrieve 'alGetProcAddress' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEnumValue = (LPALGETENUMVALUE)dlsym(openal_library,"alGetEnumValue");
if (lpOALFnTable->alGetEnumValue == NULL)
{
warn("Failed to retrieve 'alGetEnumValue' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListeneri = (LPALLISTENERI)dlsym(openal_library,"alListeneri");
if (lpOALFnTable->alListeneri == NULL)
{
warn("Failed to retrieve 'alListeneri' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListenerf = (LPALLISTENERF)dlsym(openal_library,"alListenerf");
if (lpOALFnTable->alListenerf == NULL)
{
warn("Failed to retrieve 'alListenerf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListener3f = (LPALLISTENER3F)dlsym(openal_library,"alListener3f");
if (lpOALFnTable->alListener3f == NULL)
{
warn("Failed to retrieve 'alListener3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListenerfv = (LPALLISTENERFV)dlsym(openal_library,"alListenerfv");
if (lpOALFnTable->alListenerfv == NULL)
{
warn("Failed to retrieve 'alListenerfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListeneri = (LPALGETLISTENERI)dlsym(openal_library,"alGetListeneri");
if (lpOALFnTable->alGetListeneri == NULL)
{
warn("Failed to retrieve 'alGetListeneri' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListenerf =(LPALGETLISTENERF)dlsym(openal_library,"alGetListenerf");
if (lpOALFnTable->alGetListenerf == NULL)
{
warn("Failed to retrieve 'alGetListenerf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListener3f = (LPALGETLISTENER3F)dlsym(openal_library,"alGetListener3f");
if (lpOALFnTable->alGetListener3f == NULL)
{
warn("Failed to retrieve 'alGetListener3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListenerfv = (LPALGETLISTENERFV)dlsym(openal_library,"alGetListenerfv");
if (lpOALFnTable->alGetListenerfv == NULL)
{
warn("Failed to retrieve 'alGetListenerfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenSources = (LPALGENSOURCES)dlsym(openal_library,"alGenSources");
if (lpOALFnTable->alGenSources == NULL)
{
warn("Failed to retrieve 'alGenSources' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteSources = (LPALDELETESOURCES)dlsym(openal_library,"alDeleteSources");
if (lpOALFnTable->alDeleteSources == NULL)
{
warn("Failed to retrieve 'alDeleteSources' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsSource = (LPALISSOURCE)dlsym(openal_library,"alIsSource");
if (lpOALFnTable->alIsSource == NULL)
{
warn("Failed to retrieve 'alIsSource' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcei = (LPALSOURCEI)dlsym(openal_library,"alSourcei");
if (lpOALFnTable->alSourcei == NULL)
{
warn("Failed to retrieve 'alSourcei' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcef = (LPALSOURCEF)dlsym(openal_library,"alSourcef");
if (lpOALFnTable->alSourcef == NULL)
{
warn("Failed to retrieve 'alSourcef' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSource3f = (LPALSOURCE3F)dlsym(openal_library,"alSource3f");
if (lpOALFnTable->alSource3f == NULL)
{
warn("Failed to retrieve 'alSource3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcefv = (LPALSOURCEFV)dlsym(openal_library,"alSourcefv");
if (lpOALFnTable->alSourcefv == NULL)
{
warn("Failed to retrieve 'alSourcefv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcei = (LPALGETSOURCEI)dlsym(openal_library,"alGetSourcei");
if (lpOALFnTable->alGetSourcei == NULL)
{
warn("Failed to retrieve 'alGetSourcei' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcef = (LPALGETSOURCEF)dlsym(openal_library,"alGetSourcef");
if (lpOALFnTable->alGetSourcef == NULL)
{
warn("Failed to retrieve 'alGetSourcef' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcefv = (LPALGETSOURCEFV)dlsym(openal_library,"alGetSourcefv");
if (lpOALFnTable->alGetSourcefv == NULL)
{
warn("Failed to retrieve 'alGetSourcefv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePlayv = (LPALSOURCEPLAYV)dlsym(openal_library,"alSourcePlayv");
if (lpOALFnTable->alSourcePlayv == NULL)
{
warn("Failed to retrieve 'alSourcePlayv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceStopv = (LPALSOURCESTOPV)dlsym(openal_library,"alSourceStopv");
if (lpOALFnTable->alSourceStopv == NULL)
{
warn("Failed to retrieve 'alSourceStopv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePlay = (LPALSOURCEPLAY)dlsym(openal_library,"alSourcePlay");
if (lpOALFnTable->alSourcePlay == NULL)
{
warn("Failed to retrieve 'alSourcePlay' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePause = (LPALSOURCEPAUSE)dlsym(openal_library,"alSourcePause");
if (lpOALFnTable->alSourcePause == NULL)
{
warn("Failed to retrieve 'alSourcePause' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceStop = (LPALSOURCESTOP)dlsym(openal_library,"alSourceStop");
if (lpOALFnTable->alSourceStop == NULL)
{
warn("Failed to retrieve 'alSourceStop' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceRewind = (LPALSOURCEREWIND)dlsym(openal_library,"alSourceRewind");
if (lpOALFnTable->alSourceRewind == NULL)
{
warn("Failed to retrieve 'alSourceRewind' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenBuffers = (LPALGENBUFFERS)dlsym(openal_library,"alGenBuffers");
if (lpOALFnTable->alGenBuffers == NULL)
{
warn("Failed to retrieve 'alGenBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteBuffers = (LPALDELETEBUFFERS)dlsym(openal_library,"alDeleteBuffers");
if (lpOALFnTable->alDeleteBuffers == NULL)
{
warn("Failed to retrieve 'alDeleteBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsBuffer = (LPALISBUFFER)dlsym(openal_library,"alIsBuffer");
if (lpOALFnTable->alIsBuffer == NULL)
{
warn("Failed to retrieve 'alIsBuffer' function address\n");
return AL_FALSE;
}
lpOALFnTable->alBufferData = (LPALBUFFERDATA)dlsym(openal_library,"alBufferData");
if (lpOALFnTable->alBufferData == NULL)
{
warn("Failed to retrieve 'alBufferData' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBufferi = (LPALGETBUFFERI)dlsym(openal_library,"alGetBufferi");
if (lpOALFnTable->alGetBufferi == NULL)
{
warn("Failed to retrieve 'alGetBufferi' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBufferf = (LPALGETBUFFERF)dlsym(openal_library,"alGetBufferf");
if (lpOALFnTable->alGetBufferf == NULL)
{
warn("Failed to retrieve 'alGetBufferf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceQueueBuffers = (LPALSOURCEQUEUEBUFFERS)dlsym(openal_library,"alSourceQueueBuffers");
if (lpOALFnTable->alSourceQueueBuffers == NULL)
{
warn("Failed to retrieve 'alSourceQueueBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceUnqueueBuffers = (LPALSOURCEUNQUEUEBUFFERS)dlsym(openal_library,"alSourceUnqueueBuffers");
if (lpOALFnTable->alSourceUnqueueBuffers == NULL)
{
warn("Failed to retrieve 'alSourceUnqueueBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDistanceModel = (LPALDISTANCEMODEL)dlsym(openal_library,"alDistanceModel");
if (lpOALFnTable->alDistanceModel == NULL)
{
warn("Failed to retrieve 'alDistanceModel' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDopplerFactor = (LPALDOPPLERFACTOR)dlsym(openal_library,"alDopplerFactor");
if (lpOALFnTable->alDopplerFactor == NULL)
{
warn("Failed to retrieve 'alDopplerFactor' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDopplerVelocity = (LPALDOPPLERVELOCITY)dlsym(openal_library,"alDopplerVelocity");
if (lpOALFnTable->alDopplerVelocity == NULL)
{
warn("Failed to retrieve 'alDopplerVelocity' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetString = (LPALCGETSTRING)dlsym(openal_library,"alcGetString");
if (lpOALFnTable->alcGetString == NULL)
{
warn("Failed to retrieve 'alcGetString' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetIntegerv = (LPALCGETINTEGERV)dlsym(openal_library,"alcGetIntegerv");
if (lpOALFnTable->alcGetIntegerv == NULL)
{
warn("Failed to retrieve 'alcGetIntegerv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcOpenDevice = (LPALCOPENDEVICE)dlsym(openal_library,"alcOpenDevice");
if (lpOALFnTable->alcOpenDevice == NULL)
{
warn("Failed to retrieve 'alcOpenDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcCloseDevice = (LPALCCLOSEDEVICE)dlsym(openal_library,"alcCloseDevice");
if (lpOALFnTable->alcCloseDevice == NULL)
{
warn("Failed to retrieve 'alcCloseDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcCreateContext = (LPALCCREATECONTEXT)dlsym(openal_library,"alcCreateContext");
if (lpOALFnTable->alcCreateContext == NULL)
{
warn("Failed to retrieve 'alcCreateContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcMakeContextCurrent = (LPALCMAKECONTEXTCURRENT)dlsym(openal_library,"alcMakeContextCurrent");
if (lpOALFnTable->alcMakeContextCurrent == NULL)
{
warn("Failed to retrieve 'alcMakeContextCurrent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcProcessContext = (LPALCPROCESSCONTEXT)dlsym(openal_library,"alcProcessContext");
if (lpOALFnTable->alcProcessContext == NULL)
{
warn("Failed to retrieve 'alcProcessContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetCurrentContext = (LPALCGETCURRENTCONTEXT)dlsym(openal_library,"alcGetCurrentContext");
if (lpOALFnTable->alcGetCurrentContext == NULL)
{
warn("Failed to retrieve 'alcGetCurrentContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetContextsDevice = (LPALCGETCONTEXTSDEVICE)dlsym(openal_library,"alcGetContextsDevice");
if (lpOALFnTable->alcGetContextsDevice == NULL)
{
warn("Failed to retrieve 'alcGetContextsDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcSuspendContext = (LPALCSUSPENDCONTEXT)dlsym(openal_library,"alcSuspendContext");
if (lpOALFnTable->alcSuspendContext == NULL)
{
warn("Failed to retrieve 'alcSuspendContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcDestroyContext = (LPALCDESTROYCONTEXT)dlsym(openal_library,"alcDestroyContext");
if (lpOALFnTable->alcDestroyContext == NULL)
{
warn("Failed to retrieve 'alcDestroyContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetError = (LPALCGETERROR)dlsym(openal_library,"alcGetError");
if (lpOALFnTable->alcGetError == NULL)
{
warn("Failed to retrieve 'alcGetError' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcIsExtensionPresent = (LPALCISEXTENSIONPRESENT)dlsym(openal_library,"alcIsExtensionPresent");
if (lpOALFnTable->alcIsExtensionPresent == NULL)
{
warn("Failed to retrieve 'alcIsExtensionPresent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetProcAddress = (LPALCGETPROCADDRESS)dlsym(openal_library,"alcGetProcAddress");
if (lpOALFnTable->alcGetProcAddress == NULL)
{
warn("Failed to retrieve 'alcGetProcAddress' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetEnumValue = (LPALCGETENUMVALUE)dlsym(openal_library,"alcGetEnumValue");
if (lpOALFnTable->alcGetEnumValue == NULL)
{
warn("Failed to retrieve 'alcGetEnumValue' function address\n");
return AL_FALSE;
}
#if defined(AL_ALEXT_PROTOTYPES)
//efx
lpOALFnTable->alGenEffects = (LPALGENEFFECTS)dlsym(openal_library, "alGenEffects");
if (lpOALFnTable->alGenEffects == NULL)
{
warn("Failed to retrieve 'alGenEffects' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffecti = (LPALEFFECTI)dlsym(openal_library, "alEffecti");
if (lpOALFnTable->alEffecti == NULL)
{
warn("Failed to retrieve 'alEffecti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffectiv = (LPALEFFECTIV)dlsym(openal_library, "alEffectiv");
if (lpOALFnTable->alEffectiv == NULL)
{
warn("Failed to retrieve 'alEffectiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffectf = (LPALEFFECTF)dlsym(openal_library, "alEffectf");
if (lpOALFnTable->alEffectf == NULL)
{
warn("Failed to retrieve 'alEffectf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffectfv = (LPALEFFECTFV)dlsym(openal_library, "alEffectfv");
if (lpOALFnTable->alEffectfv == NULL)
{
warn("Failed to retrieve 'alEffectfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffecti = (LPALGETEFFECTI)dlsym(openal_library, "alGetEffecti");
if (lpOALFnTable->alGetEffecti == NULL)
{
warn("Failed to retrieve 'alGetEffecti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffectiv = (LPALGETEFFECTIV)dlsym(openal_library, "alGetEffectiv");
if (lpOALFnTable->alGetEffectiv == NULL)
{
warn("Failed to retrieve 'alGetEffectiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffectf = (LPALGETEFFECTF)dlsym(openal_library, "alGetEffectf");
if (lpOALFnTable->alGetEffectf == NULL)
{
warn("Failed to retrieve 'alGetEffectf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffectfv = (LPALGETEFFECTFV)dlsym(openal_library, "alGetEffectfv");
if (lpOALFnTable->alGetEffectfv == NULL)
{
warn("Failed to retrieve 'alGetEffectfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteEffects = (LPALDELETEEFFECTS)dlsym(openal_library, "alDeleteEffects");
if (lpOALFnTable->alDeleteEffects == NULL)
{
warn("Failed to retrieve 'alDeleteEffects' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsEffect = (LPALISEFFECT)dlsym(openal_library, "alIsEffect");
if (lpOALFnTable->alIsEffect == NULL)
{
warn("Failed to retrieve 'alIsEffect' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alAuxiliaryEffectSlotf");
if (lpOALFnTable->alAuxiliaryEffectSlotf == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSlotf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alAuxiliaryEffectSlotfv");
if (lpOALFnTable->alAuxiliaryEffectSlotfv == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSlotfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alAuxiliaryEffectSloti");
if (lpOALFnTable->alAuxiliaryEffectSloti == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSloti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alAuxiliaryEffectSlotiv");
if (lpOALFnTable->alAuxiliaryEffectSlotiv == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSlotiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)dlsym(openal_library, "alIsAuxiliaryEffectSlot");
if (lpOALFnTable->alIsAuxiliaryEffectSlot == NULL)
{
warn("Failed to retrieve 'alIsAuxiliaryEffectSlot' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alGenAuxiliaryEffectSlots");
if (lpOALFnTable->alGenAuxiliaryEffectSlots == NULL)
{
warn("Failed to retrieve 'alGenAuxiliaryEffectSlots' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alDeleteAuxiliaryEffectSlots");
if (lpOALFnTable->alDeleteAuxiliaryEffectSlots == NULL)
{
warn("Failed to retrieve 'alDeleteAuxiliaryEffectSlots' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alGetAuxiliaryEffectSlotf");
if (lpOALFnTable->alGetAuxiliaryEffectSlotf == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alGetAuxiliaryEffectSlotfv");
if (lpOALFnTable->alGetAuxiliaryEffectSlotfv == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alGetAuxiliaryEffectSloti");
if (lpOALFnTable->alGetAuxiliaryEffectSloti == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSloti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alGetAuxiliaryEffectSlotiv");
if (lpOALFnTable->alGetAuxiliaryEffectSlotiv == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSource3i = (LPALSOURCE3I)dlsym(openal_library, "alSource3i");
if (lpOALFnTable->alSource3i == NULL)
{
warn("Failed to retrieve 'alSource3i' function address\n");
return AL_FALSE;
}
#endif
return AL_TRUE;
}
ALvoid UnloadOAL10Library()
{
if (openal_library != NULL)
dlclose(openal_library);
}

View file

@ -1,618 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// TODO: Implement OpenAL loading code which is currently stubbed out.
#if defined(__MACOSX__) && !defined(TORQUE_OS_MAC)
#define TORQUE_OS_MAC
#endif
#include "console/console.h"
#include <err.h>
#include <string.h>
#include <dlfcn.h>
#include "sfx/openal/LoadOAL.h"
void* openal_library = NULL;
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable)
{
// TODO: Implement this.
if (!lpOALFnTable)
return AL_FALSE;
if (szOALFullPathName)
openal_library = dlopen(szOALFullPathName, RTLD_NOW);
else
{
#ifdef TORQUE_DEBUG
openal_library = dlopen("@rpath/libopenald.1.23.1.dylib", RTLD_NOW);
if (openal_library == NULL)
{
openal_library = dlopen("@rpath/libopenald.1.dylib", RTLD_NOW);
}
#else
openal_library = dlopen("@rpath/libopenal.1.23.1.dylib", RTLD_NOW);
if (openal_library == NULL)
{
openal_library = dlopen("@rpath/libopenal .1.dylib", RTLD_NOW);
}
#endif
}
if (openal_library == NULL)
{
Con::errorf("Failed to load OpenAL shared library. Sound will not be available");
return AL_FALSE;
}
memset(lpOALFnTable, 0, sizeof(OPENALFNTABLE));
lpOALFnTable->alEnable = (LPALENABLE)dlsym(openal_library,"alEnable");
if (lpOALFnTable->alEnable == NULL)
{
warn("Failed to retrieve 'alEnable' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDisable = (LPALDISABLE)dlsym(openal_library,"alDisable");
if (lpOALFnTable->alDisable == NULL)
{
warn("Failed to retrieve 'alDisable' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsEnabled = (LPALISENABLED)dlsym(openal_library,"alIsEnabled");
if (lpOALFnTable->alIsEnabled == NULL)
{
warn("Failed to retrieve 'alIsEnabled' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBoolean = (LPALGETBOOLEAN)dlsym(openal_library,"alGetBoolean");
if (lpOALFnTable->alGetBoolean == NULL)
{
warn("Failed to retrieve 'alGetBoolean' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetInteger = (LPALGETINTEGER)dlsym(openal_library,"alGetInteger");
if (lpOALFnTable->alGetInteger == NULL)
{
warn("Failed to retrieve 'alGetInteger' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetFloat = (LPALGETFLOAT)dlsym(openal_library,"alGetFloat");
if (lpOALFnTable->alGetFloat == NULL)
{
warn("Failed to retrieve 'alGetFloat' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetDouble = (LPALGETDOUBLE)dlsym(openal_library,"alGetDouble");
if (lpOALFnTable->alGetDouble == NULL)
{
warn("Failed to retrieve 'alGetDouble' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBooleanv = (LPALGETBOOLEANV)dlsym(openal_library,"alGetBooleanv");
if (lpOALFnTable->alGetBooleanv == NULL)
{
warn("Failed to retrieve 'alGetBooleanv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetIntegerv = (LPALGETINTEGERV)dlsym(openal_library,"alGetIntegerv");
if (lpOALFnTable->alGetIntegerv == NULL)
{
warn("Failed to retrieve 'alGetIntegerv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetFloatv = (LPALGETFLOATV)dlsym(openal_library,"alGetFloatv");
if (lpOALFnTable->alGetFloatv == NULL)
{
warn("Failed to retrieve 'alGetFloatv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetDoublev = (LPALGETDOUBLEV)dlsym(openal_library,"alGetDoublev");
if (lpOALFnTable->alGetDoublev == NULL)
{
warn("Failed to retrieve 'alGetDoublev' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetString = (LPALGETSTRING)dlsym(openal_library,"alGetString");
if (lpOALFnTable->alGetString == NULL)
{
warn("Failed to retrieve 'alGetString' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetError = (LPALGETERROR)dlsym(openal_library,"alGetError");
if (lpOALFnTable->alGetError == NULL)
{
warn("Failed to retrieve 'alGetError' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsExtensionPresent = (LPALISEXTENSIONPRESENT)dlsym(openal_library,"alIsExtensionPresent");
if (lpOALFnTable->alIsExtensionPresent == NULL)
{
warn("Failed to retrieve 'alIsExtensionPresent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetProcAddress = (LPALGETPROCADDRESS)dlsym(openal_library,"alGetProcAddress");
if (lpOALFnTable->alGetProcAddress == NULL)
{
warn("Failed to retrieve 'alGetProcAddress' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEnumValue = (LPALGETENUMVALUE)dlsym(openal_library,"alGetEnumValue");
if (lpOALFnTable->alGetEnumValue == NULL)
{
warn("Failed to retrieve 'alGetEnumValue' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListeneri = (LPALLISTENERI)dlsym(openal_library,"alListeneri");
if (lpOALFnTable->alListeneri == NULL)
{
warn("Failed to retrieve 'alListeneri' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListenerf = (LPALLISTENERF)dlsym(openal_library,"alListenerf");
if (lpOALFnTable->alListenerf == NULL)
{
warn("Failed to retrieve 'alListenerf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListener3f = (LPALLISTENER3F)dlsym(openal_library,"alListener3f");
if (lpOALFnTable->alListener3f == NULL)
{
warn("Failed to retrieve 'alListener3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListenerfv = (LPALLISTENERFV)dlsym(openal_library,"alListenerfv");
if (lpOALFnTable->alListenerfv == NULL)
{
warn("Failed to retrieve 'alListenerfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListeneri = (LPALGETLISTENERI)dlsym(openal_library,"alGetListeneri");
if (lpOALFnTable->alGetListeneri == NULL)
{
warn("Failed to retrieve 'alGetListeneri' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListenerf =(LPALGETLISTENERF)dlsym(openal_library,"alGetListenerf");
if (lpOALFnTable->alGetListenerf == NULL)
{
warn("Failed to retrieve 'alGetListenerf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListener3f = (LPALGETLISTENER3F)dlsym(openal_library,"alGetListener3f");
if (lpOALFnTable->alGetListener3f == NULL)
{
warn("Failed to retrieve 'alGetListener3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListenerfv = (LPALGETLISTENERFV)dlsym(openal_library,"alGetListenerfv");
if (lpOALFnTable->alGetListenerfv == NULL)
{
warn("Failed to retrieve 'alGetListenerfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenSources = (LPALGENSOURCES)dlsym(openal_library,"alGenSources");
if (lpOALFnTable->alGenSources == NULL)
{
warn("Failed to retrieve 'alGenSources' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteSources = (LPALDELETESOURCES)dlsym(openal_library,"alDeleteSources");
if (lpOALFnTable->alDeleteSources == NULL)
{
warn("Failed to retrieve 'alDeleteSources' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsSource = (LPALISSOURCE)dlsym(openal_library,"alIsSource");
if (lpOALFnTable->alIsSource == NULL)
{
warn("Failed to retrieve 'alIsSource' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcei = (LPALSOURCEI)dlsym(openal_library,"alSourcei");
if (lpOALFnTable->alSourcei == NULL)
{
warn("Failed to retrieve 'alSourcei' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcef = (LPALSOURCEF)dlsym(openal_library,"alSourcef");
if (lpOALFnTable->alSourcef == NULL)
{
warn("Failed to retrieve 'alSourcef' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSource3f = (LPALSOURCE3F)dlsym(openal_library,"alSource3f");
if (lpOALFnTable->alSource3f == NULL)
{
warn("Failed to retrieve 'alSource3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcefv = (LPALSOURCEFV)dlsym(openal_library,"alSourcefv");
if (lpOALFnTable->alSourcefv == NULL)
{
warn("Failed to retrieve 'alSourcefv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcei = (LPALGETSOURCEI)dlsym(openal_library,"alGetSourcei");
if (lpOALFnTable->alGetSourcei == NULL)
{
warn("Failed to retrieve 'alGetSourcei' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcef = (LPALGETSOURCEF)dlsym(openal_library,"alGetSourcef");
if (lpOALFnTable->alGetSourcef == NULL)
{
warn("Failed to retrieve 'alGetSourcef' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcefv = (LPALGETSOURCEFV)dlsym(openal_library,"alGetSourcefv");
if (lpOALFnTable->alGetSourcefv == NULL)
{
warn("Failed to retrieve 'alGetSourcefv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePlayv = (LPALSOURCEPLAYV)dlsym(openal_library,"alSourcePlayv");
if (lpOALFnTable->alSourcePlayv == NULL)
{
warn("Failed to retrieve 'alSourcePlayv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceStopv = (LPALSOURCESTOPV)dlsym(openal_library,"alSourceStopv");
if (lpOALFnTable->alSourceStopv == NULL)
{
warn("Failed to retrieve 'alSourceStopv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePlay = (LPALSOURCEPLAY)dlsym(openal_library,"alSourcePlay");
if (lpOALFnTable->alSourcePlay == NULL)
{
warn("Failed to retrieve 'alSourcePlay' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePause = (LPALSOURCEPAUSE)dlsym(openal_library,"alSourcePause");
if (lpOALFnTable->alSourcePause == NULL)
{
warn("Failed to retrieve 'alSourcePause' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceStop = (LPALSOURCESTOP)dlsym(openal_library,"alSourceStop");
if (lpOALFnTable->alSourceStop == NULL)
{
warn("Failed to retrieve 'alSourceStop' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceRewind = (LPALSOURCEREWIND)dlsym(openal_library,"alSourceRewind");
if (lpOALFnTable->alSourceRewind == NULL)
{
warn("Failed to retrieve 'alSourceRewind' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenBuffers = (LPALGENBUFFERS)dlsym(openal_library,"alGenBuffers");
if (lpOALFnTable->alGenBuffers == NULL)
{
warn("Failed to retrieve 'alGenBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteBuffers = (LPALDELETEBUFFERS)dlsym(openal_library,"alDeleteBuffers");
if (lpOALFnTable->alDeleteBuffers == NULL)
{
warn("Failed to retrieve 'alDeleteBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsBuffer = (LPALISBUFFER)dlsym(openal_library,"alIsBuffer");
if (lpOALFnTable->alIsBuffer == NULL)
{
warn("Failed to retrieve 'alIsBuffer' function address\n");
return AL_FALSE;
}
lpOALFnTable->alBufferData = (LPALBUFFERDATA)dlsym(openal_library,"alBufferData");
if (lpOALFnTable->alBufferData == NULL)
{
warn("Failed to retrieve 'alBufferData' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBufferi = (LPALGETBUFFERI)dlsym(openal_library,"alGetBufferi");
if (lpOALFnTable->alGetBufferi == NULL)
{
warn("Failed to retrieve 'alGetBufferi' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBufferf = (LPALGETBUFFERF)dlsym(openal_library,"alGetBufferf");
if (lpOALFnTable->alGetBufferf == NULL)
{
warn("Failed to retrieve 'alGetBufferf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceQueueBuffers = (LPALSOURCEQUEUEBUFFERS)dlsym(openal_library,"alSourceQueueBuffers");
if (lpOALFnTable->alSourceQueueBuffers == NULL)
{
warn("Failed to retrieve 'alSourceQueueBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceUnqueueBuffers = (LPALSOURCEUNQUEUEBUFFERS)dlsym(openal_library,"alSourceUnqueueBuffers");
if (lpOALFnTable->alSourceUnqueueBuffers == NULL)
{
warn("Failed to retrieve 'alSourceUnqueueBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDistanceModel = (LPALDISTANCEMODEL)dlsym(openal_library,"alDistanceModel");
if (lpOALFnTable->alDistanceModel == NULL)
{
warn("Failed to retrieve 'alDistanceModel' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDopplerFactor = (LPALDOPPLERFACTOR)dlsym(openal_library,"alDopplerFactor");
if (lpOALFnTable->alDopplerFactor == NULL)
{
warn("Failed to retrieve 'alDopplerFactor' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDopplerVelocity = (LPALDOPPLERVELOCITY)dlsym(openal_library,"alDopplerVelocity");
if (lpOALFnTable->alDopplerVelocity == NULL)
{
warn("Failed to retrieve 'alDopplerVelocity' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetString = (LPALCGETSTRING)dlsym(openal_library,"alcGetString");
if (lpOALFnTable->alcGetString == NULL)
{
warn("Failed to retrieve 'alcGetString' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetIntegerv = (LPALCGETINTEGERV)dlsym(openal_library,"alcGetIntegerv");
if (lpOALFnTable->alcGetIntegerv == NULL)
{
warn("Failed to retrieve 'alcGetIntegerv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcOpenDevice = (LPALCOPENDEVICE)dlsym(openal_library,"alcOpenDevice");
if (lpOALFnTable->alcOpenDevice == NULL)
{
warn("Failed to retrieve 'alcOpenDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcCloseDevice = (LPALCCLOSEDEVICE)dlsym(openal_library,"alcCloseDevice");
if (lpOALFnTable->alcCloseDevice == NULL)
{
warn("Failed to retrieve 'alcCloseDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcCreateContext = (LPALCCREATECONTEXT)dlsym(openal_library,"alcCreateContext");
if (lpOALFnTable->alcCreateContext == NULL)
{
warn("Failed to retrieve 'alcCreateContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcMakeContextCurrent = (LPALCMAKECONTEXTCURRENT)dlsym(openal_library,"alcMakeContextCurrent");
if (lpOALFnTable->alcMakeContextCurrent == NULL)
{
warn("Failed to retrieve 'alcMakeContextCurrent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcProcessContext = (LPALCPROCESSCONTEXT)dlsym(openal_library,"alcProcessContext");
if (lpOALFnTable->alcProcessContext == NULL)
{
warn("Failed to retrieve 'alcProcessContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetCurrentContext = (LPALCGETCURRENTCONTEXT)dlsym(openal_library,"alcGetCurrentContext");
if (lpOALFnTable->alcGetCurrentContext == NULL)
{
warn("Failed to retrieve 'alcGetCurrentContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetContextsDevice = (LPALCGETCONTEXTSDEVICE)dlsym(openal_library,"alcGetContextsDevice");
if (lpOALFnTable->alcGetContextsDevice == NULL)
{
warn("Failed to retrieve 'alcGetContextsDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcSuspendContext = (LPALCSUSPENDCONTEXT)dlsym(openal_library,"alcSuspendContext");
if (lpOALFnTable->alcSuspendContext == NULL)
{
warn("Failed to retrieve 'alcSuspendContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcDestroyContext = (LPALCDESTROYCONTEXT)dlsym(openal_library,"alcDestroyContext");
if (lpOALFnTable->alcDestroyContext == NULL)
{
warn("Failed to retrieve 'alcDestroyContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetError = (LPALCGETERROR)dlsym(openal_library,"alcGetError");
if (lpOALFnTable->alcGetError == NULL)
{
warn("Failed to retrieve 'alcGetError' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcIsExtensionPresent = (LPALCISEXTENSIONPRESENT)dlsym(openal_library,"alcIsExtensionPresent");
if (lpOALFnTable->alcIsExtensionPresent == NULL)
{
warn("Failed to retrieve 'alcIsExtensionPresent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetProcAddress = (LPALCGETPROCADDRESS)dlsym(openal_library,"alcGetProcAddress");
if (lpOALFnTable->alcGetProcAddress == NULL)
{
warn("Failed to retrieve 'alcGetProcAddress' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetEnumValue = (LPALCGETENUMVALUE)dlsym(openal_library,"alcGetEnumValue");
if (lpOALFnTable->alcGetEnumValue == NULL)
{
warn("Failed to retrieve 'alcGetEnumValue' function address\n");
return AL_FALSE;
}
#if defined(AL_ALEXT_PROTOTYPES)
//efx
lpOALFnTable->alGenEffects = (LPALGENEFFECTS)dlsym(openal_library, "alGenEffects");
if (lpOALFnTable->alGenEffects == NULL)
{
warn("Failed to retrieve 'alGenEffects' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffecti = (LPALEFFECTI)dlsym(openal_library, "alEffecti");
if (lpOALFnTable->alEffecti == NULL)
{
warn("Failed to retrieve 'alEffecti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffectiv = (LPALEFFECTIV)dlsym(openal_library, "alEffectiv");
if (lpOALFnTable->alEffectiv == NULL)
{
warn("Failed to retrieve 'alEffectiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffectf = (LPALEFFECTF)dlsym(openal_library, "alEffectf");
if (lpOALFnTable->alEffectf == NULL)
{
warn("Failed to retrieve 'alEffectf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alEffectfv = (LPALEFFECTFV)dlsym(openal_library, "alEffectfv");
if (lpOALFnTable->alEffectfv == NULL)
{
warn("Failed to retrieve 'alEffectfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffecti = (LPALGETEFFECTI)dlsym(openal_library, "alGetEffecti");
if (lpOALFnTable->alGetEffecti == NULL)
{
warn("Failed to retrieve 'alGetEffecti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffectiv = (LPALGETEFFECTIV)dlsym(openal_library, "alGetEffectiv");
if (lpOALFnTable->alGetEffectiv == NULL)
{
warn("Failed to retrieve 'alGetEffectiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffectf = (LPALGETEFFECTF)dlsym(openal_library, "alGetEffectf");
if (lpOALFnTable->alGetEffectf == NULL)
{
warn("Failed to retrieve 'alGetEffectf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEffectfv = (LPALGETEFFECTFV)dlsym(openal_library, "alGetEffectfv");
if (lpOALFnTable->alGetEffectfv == NULL)
{
warn("Failed to retrieve 'alGetEffectfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteEffects = (LPALDELETEEFFECTS)dlsym(openal_library, "alDeleteEffects");
if (lpOALFnTable->alDeleteEffects == NULL)
{
warn("Failed to retrieve 'alDeleteEffects' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsEffect = (LPALISEFFECT)dlsym(openal_library, "alIsEffect");
if (lpOALFnTable->alIsEffect == NULL)
{
warn("Failed to retrieve 'alIsEffect' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alAuxiliaryEffectSlotf");
if (lpOALFnTable->alAuxiliaryEffectSlotf == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSlotf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alAuxiliaryEffectSlotfv");
if (lpOALFnTable->alAuxiliaryEffectSlotfv == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSlotfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alAuxiliaryEffectSloti");
if (lpOALFnTable->alAuxiliaryEffectSloti == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSloti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alAuxiliaryEffectSlotiv");
if (lpOALFnTable->alAuxiliaryEffectSlotiv == NULL)
{
warn("Failed to retrieve 'alAuxiliaryEffectSlotiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)dlsym(openal_library, "alIsAuxiliaryEffectSlot");
if (lpOALFnTable->alIsAuxiliaryEffectSlot == NULL)
{
warn("Failed to retrieve 'alIsAuxiliaryEffectSlot' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alGenAuxiliaryEffectSlots");
if (lpOALFnTable->alGenAuxiliaryEffectSlots == NULL)
{
warn("Failed to retrieve 'alGenAuxiliaryEffectSlots' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alDeleteAuxiliaryEffectSlots");
if (lpOALFnTable->alDeleteAuxiliaryEffectSlots == NULL)
{
warn("Failed to retrieve 'alDeleteAuxiliaryEffectSlots' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alGetAuxiliaryEffectSlotf");
if (lpOALFnTable->alGetAuxiliaryEffectSlotf == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alGetAuxiliaryEffectSlotfv");
if (lpOALFnTable->alGetAuxiliaryEffectSlotfv == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alGetAuxiliaryEffectSloti");
if (lpOALFnTable->alGetAuxiliaryEffectSloti == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSloti' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alGetAuxiliaryEffectSlotiv");
if (lpOALFnTable->alGetAuxiliaryEffectSlotiv == NULL)
{
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotiv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSource3i = (LPALSOURCE3I)dlsym(openal_library, "alSource3i");
if (lpOALFnTable->alSource3i == NULL)
{
warn("Failed to retrieve 'alSource3i' function address\n");
return AL_FALSE;
}
#endif
return AL_TRUE;
}
ALvoid UnloadOAL10Library()
{
if (openal_library != NULL)
dlclose(openal_library);
}

View file

@ -30,8 +30,7 @@
//#define DEBUG_SPEW
SFXALBuffer* SFXALBuffer::create( const OPENALFNTABLE &oalft,
const ThreadSafeRef< SFXStream >& stream,
SFXALBuffer* SFXALBuffer::create( const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware )
{
@ -41,27 +40,24 @@ SFXALBuffer* SFXALBuffer::create( const OPENALFNTABLE &oalft,
return NULL;
}
SFXALBuffer *buffer = new SFXALBuffer( oalft,
stream,
SFXALBuffer *buffer = new SFXALBuffer( stream,
description,
useHardware );
return buffer;
}
SFXALBuffer::SFXALBuffer( const OPENALFNTABLE &oalft,
const ThreadSafeRef< SFXStream >& stream,
SFXALBuffer::SFXALBuffer( const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware )
: Parent( stream, description ),
mIs3d( description->mIs3D ),
mUseHardware( useHardware ),
mOpenAL( oalft )
mUseHardware( useHardware )
{
// Set up device buffers.
if( !isStreaming() )
mOpenAL.alGenBuffers( 1, &mALBuffer );
alGenBuffers( 1, &mALBuffer );
}
SFXALBuffer::~SFXALBuffer()
@ -70,13 +66,13 @@ SFXALBuffer::~SFXALBuffer()
_getUniqueVoice()->stop();
// Release buffers.
if ( mOpenAL.alIsBuffer( mALBuffer ))
mOpenAL.alDeleteBuffers( 1, &mALBuffer );
if ( alIsBuffer( mALBuffer ))
alDeleteBuffers( 1, &mALBuffer );
while( mFreeBuffers.size() )
{
ALuint buffer = mFreeBuffers.last();
mOpenAL.alDeleteBuffers( 1, &buffer );
alDeleteBuffers( 1, &buffer );
mFreeBuffers.pop_back();
}
}
@ -98,7 +94,7 @@ void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
ALenum alFormat = _sfxFormatToALFormat( getFormat() );
AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
mOpenAL.alBufferData( mALBuffer, alFormat,
alBufferData( mALBuffer, alFormat,
packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
destructSingle( packet );
@ -112,19 +108,19 @@ void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
ALuint source = _getUniqueVoice()->mSourceName;
ALint numProcessed;
mOpenAL.alGetSourcei( source, AL_BUFFERS_PROCESSED, &numProcessed );
alGetSourcei( source, AL_BUFFERS_PROCESSED, &numProcessed );
for( U32 i = 0; i < numProcessed; ++ i )
{
// Unqueue the buffer.
ALuint buffer;
mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
alSourceUnqueueBuffers( source, 1, &buffer );
// Update the sample offset on the voice.
ALint size;
mOpenAL.alGetBufferi( buffer, AL_SIZE, &size );
alGetBufferi( buffer, AL_SIZE, &size );
_getUniqueVoice()->mSampleOffset += size / getFormat().getBytesPerSample();
// Push the buffer onto the freelist.
@ -147,22 +143,22 @@ void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
mFreeBuffers.pop_back();
}
else
mOpenAL.alGenBuffers( 1, &buffer );
alGenBuffers( 1, &buffer );
// Upload the data.
ALenum alFormat = _sfxFormatToALFormat( getFormat() );
AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
AssertFatal( mOpenAL.alIsBuffer( buffer ), "SFXALBuffer::write() - buffer invalid" );
AssertFatal( alIsBuffer( buffer ), "SFXALBuffer::write() - buffer invalid" );
mOpenAL.alBufferData( buffer, alFormat,
alBufferData( buffer, alFormat,
packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
destructSingle( packet );
// Queue the buffer.
mOpenAL.alSourceQueueBuffers( source, 1, &buffer );
alSourceQueueBuffers( source, 1, &buffer );
}
}
@ -183,12 +179,12 @@ void SFXALBuffer::_flush()
ALuint source = _getUniqueVoice()->mSourceName;
ALint numQueued;
mOpenAL.alGetSourcei( source, AL_BUFFERS_QUEUED, &numQueued );
alGetSourcei( source, AL_BUFFERS_QUEUED, &numQueued );
for( U32 i = 0; i < numQueued; ++ i )
{
ALuint buffer;
mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
alSourceUnqueueBuffers( source, 1, &buffer );
mFreeBuffers.push_back( buffer );
}
@ -203,20 +199,20 @@ void SFXALBuffer::_flush()
// issues any concurrent state changes on the voice resulting in us losing state here.
ALuint newSource;
mOpenAL.alGenSources( 1, &newSource );
alGenSources( 1, &newSource );
#define COPY_F( name ) \
{ \
F32 val; \
mOpenAL.alGetSourcef( source, name, &val ); \
mOpenAL.alSourcef( source, name, val ); \
alGetSourcef( source, name, &val ); \
alSourcef( source, name, val ); \
}
#define COPY_FV( name ) \
{ \
VectorF val; \
mOpenAL.alGetSourcefv( source, name, val ); \
mOpenAL.alSourcefv( source, name, val ); \
alGetSourcefv( source, name, val ); \
alSourcefv( source, name, val ); \
}
COPY_F( AL_REFERENCE_DISTANCE );
@ -232,7 +228,7 @@ void SFXALBuffer::_flush()
COPY_FV( AL_DIRECTION );
_getUniqueVoice()->mSourceName = newSource;
mOpenAL.alDeleteSources( 1, &source );
alDeleteSources( 1, &source );
#endif
}

View file

@ -24,13 +24,13 @@
#define _SFXALBUFFER_H_
#ifndef _LOADOAL_H
#include "sfx/openal/LoadOAL.h"
#include "sfx/openal/LoadOAL.h"
#endif
#ifndef _SFXINTERNAL_H_
#include "sfx/sfxInternal.h"
#include "sfx/sfxInternal.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#include "core/util/tVector.h"
#endif
@ -39,81 +39,95 @@ class SFXALVoice;
class SFXALBuffer : public SFXBuffer
{
public:
public:
typedef SFXBuffer Parent;
typedef SFXBuffer Parent;
friend class SFXALDevice;
friend class SFXALVoice;
friend class SFXALDevice;
friend class SFXALVoice;
protected:
/// AL buffer in case this is a static, non-streaming buffer.
ALuint mALBuffer;
/// Free buffers for use in queuing in case this is a streaming buffer.
Vector< ALuint > mFreeBuffers;
protected:
///
SFXALBuffer( const OPENALFNTABLE &oalft,
const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware );
/// AL buffer in case this is a static, non-streaming buffer.
ALuint mALBuffer;
///
bool mIs3d;
/// Free buffers for use in queuing in case this is a streaming buffer.
Vector< ALuint > mFreeBuffers;
///
bool mUseHardware;
///
SFXALBuffer(const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware);
const OPENALFNTABLE &mOpenAL;
///
bool mIs3d;
///
ALenum _getALFormat() const
///
bool mUseHardware;
///
ALenum _getALFormat() const
{
return _sfxFormatToALFormat(getFormat());
}
///
static ALenum _sfxFormatToALFormat(const SFXFormat& format)
{
const U32 channels = format.getChannels();
const SFXSampleType type = format.getSampleType();
switch (type)
{
return _sfxFormatToALFormat( getFormat() );
case Sample_Int8:
if (channels == 1) return AL_FORMAT_MONO8;
if (channels == 2) return AL_FORMAT_STEREO8;
break;
case Sample_Int16:
if (channels == 1) return AL_FORMAT_MONO16;
if (channels == 2) return AL_FORMAT_STEREO16;
break;
case Sample_Float:
if (channels == 1) return AL_FORMAT_MONO_FLOAT32;
if (channels == 2) return AL_FORMAT_STEREO_FLOAT32;
break;
case Sample_IMA4:
if (channels == 1) return AL_FORMAT_MONO_IMA4;
if (channels == 2) return AL_FORMAT_STEREO_IMA4;
break;
case Sample_MSADPCM:
// Requires OpenAL Soft MSADPCM extension
if (channels == 1) return AL_FORMAT_MONO_MSADPCM_SOFT;
if (channels == 2) return AL_FORMAT_STEREO_MSADPCM_SOFT;
break;
}
///
static ALenum _sfxFormatToALFormat( const SFXFormat& format )
{
if( format.getChannels() == 2 )
{
const U32 bps = format.getBitsPerSample();
if( bps == 16 )
return AL_FORMAT_STEREO8;
else if( bps == 32 )
return AL_FORMAT_STEREO16;
}
else if( format.getChannels() == 1 )
{
const U32 bps = format.getBitsPerSample();
if( bps == 8 )
return AL_FORMAT_MONO8;
else if( bps == 16 )
return AL_FORMAT_MONO16;
}
return 0;
}
// Unsupported channel count or layout
Con::errorf("_sfxFormatToALFormat - Unsupported format: channels=%d, type=%d",
channels, type);
return 0;
}
///
SFXALVoice* _getUniqueVoice() const
{
return ( SFXALVoice* ) mUniqueVoice.getPointer();
}
///
SFXALVoice* _getUniqueVoice() const
{
return (SFXALVoice*)mUniqueVoice.getPointer();
}
// SFXBuffer.
void write( SFXInternal::SFXStreamPacket* const* packets, U32 num ) override;
void _flush() override;
// SFXBuffer.
void write(SFXInternal::SFXStreamPacket* const* packets, U32 num) override;
void _flush() override;
public:
public:
static SFXALBuffer* create( const OPENALFNTABLE &oalft,
const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware );
static SFXALBuffer* create(const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description,
bool useHardware);
virtual ~SFXALBuffer();
virtual ~SFXALBuffer();
};
#endif // _SFXALBUFFER_H_
#endif // _SFXALBUFFER_H_

View file

@ -24,50 +24,411 @@
#include "sfx/openal/sfxALBuffer.h"
#include "platform/async/asyncUpdate.h"
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/efx.h"
#include "AL/alext.h"
#ifndef ALC_CONNECTED
#define ALC_CONNECTED 0x313
#endif
#ifndef ALC_DEVICE_CLOCK_SOFT
#define ALC_DEVICE_CLOCK_SOFT 0x1600
#endif
#ifndef ALC_DEVICE_LATENCY_SOFT
#define ALC_DEVICE_LATENCY_SOFT 0x1601
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define FUNCTION_CAST(T, ptr) (union{void *p; T f;}){ptr}.f
#elif defined(__cplusplus)
#define FUNCTION_CAST(T, ptr) reinterpret_cast<T>(ptr)
#else
#define FUNCTION_CAST(T, ptr) (T)(ptr)
#endif
#define SFX_LOAD_AL_PROC(T, x) \
(x) = FUNCTION_CAST(T, alGetProcAddress(#x)); \
if (!(x)) Con::warnf("SFXALDevice - Failed to load " #x);
#define SFX_LOAD_ALC_PROC(T, x) \
(x) = FUNCTION_CAST(T, alcGetProcAddress(mDevice, #x)); \
if (!(x)) Con::warnf("SFXALDevice - Failed to load " #x);
/* Effect object functions */
static LPALGENFILTERS alGenFilters{ nullptr };
static LPALDELETEFILTERS alDeleteFilters{ nullptr };
static LPALISFILTER alIsFilter{ nullptr };
static LPALFILTERF alFilterf{ nullptr };
static LPALFILTERFV alFilterfv{ nullptr };
static LPALFILTERI alFilteri{ nullptr };
static LPALFILTERIV alFilteriv{ nullptr };
static LPALGETFILTERF alGetFilterf{ nullptr };
static LPALGETFILTERFV alGetFilterfv{ nullptr };
static LPALGETFILTERI alGetFilteri{ nullptr };
static LPALGETFILTERIV alGetFilteriv{ nullptr };
static LPALGENEFFECTS alGenEffects{ nullptr };
static LPALDELETEEFFECTS alDeleteEffects{ nullptr };
static LPALISEFFECT alIsEffect{ nullptr };
static LPALEFFECTF alEffectf{ nullptr };
static LPALEFFECTFV alEffectfv{ nullptr };
static LPALEFFECTI alEffecti{ nullptr };
static LPALEFFECTIV alEffectiv{ nullptr };
static LPALGETEFFECTF alGetEffectf{ nullptr };
static LPALGETEFFECTFV alGetEffectfv{ nullptr };
static LPALGETEFFECTI alGetEffecti{ nullptr };
static LPALGETEFFECTIV alGetEffectiv{ nullptr };
static LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{ nullptr };
static LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{ nullptr };
static LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{ nullptr };
static LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{ nullptr };
static LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{ nullptr };
static LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{ nullptr };
static LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{ nullptr };
static LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{ nullptr };
static LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{ nullptr };
static LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{ nullptr };
static LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{ nullptr };
static LPALCGETSTRINGISOFT alcGetStringiSOFT{ nullptr };
static LPALCRESETDEVICESOFT alcResetDeviceSOFT{ nullptr };
static LPALCREOPENDEVICESOFT alcReopenDeviceSOFT{ nullptr };
static LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT{ nullptr };
class SFXALRegisterProvider
{
public:
SFXALRegisterProvider()
{
SFXSystem::getRegisterProviderSignal().notify(&SFXALDevice::enumerateProviders);
}
};
static SFXALRegisterProvider pSFXALRegisterProvider;
SFXProvider::CreateProviderInstanceDelegate SFXALDevice::mCreateDeviceInstance(SFXALDevice::createInstance);
SFXDevice* SFXALDevice::createInstance(U32 providerIndex)
{
SFXALDevice* dev = new SFXALDevice(providerIndex);
return dev;
}
void SFXALDevice::_initExtensions()
{
// Device-level soft extensions — must be loaded before context creation
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_reopen_device"))
{
SFX_LOAD_ALC_PROC(LPALCREOPENDEVICESOFT, alcReopenDeviceSOFT);
SFX_LOAD_ALC_PROC(LPALCRESETDEVICESOFT, alcResetDeviceSOFT);
if (alcReopenDeviceSOFT && alcResetDeviceSOFT)
{
mHasSoftReopen = true;
mCaps |= CAPS_HotReconnect;
}
}
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"))
{
SFX_LOAD_ALC_PROC(LPALCGETSTRINGISOFT, alcGetStringiSOFT);
if (alcGetStringiSOFT)
{
mHasSoftHRTF = true;
mCaps |= CAPS_HRTF;
}
}
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_device_clock"))
{
SFX_LOAD_ALC_PROC(LPALCGETINTEGER64VSOFT, alcGetInteger64vSOFT);
if (alcGetInteger64vSOFT)
mCaps |= CAPS_DeviceClock;
}
if (alcIsExtensionPresent(mDevice, "ALC_EXT_disconnect"))
mCaps |= CAPS_DisconnectDetect;
// Context-level AL extensions — loaded after context is current
if (alIsExtensionPresent("AL_EXT_float32"))
mCaps |= CAPS_Float32;
if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
mCaps |= CAPS_MonoStereo;
if (alIsExtensionPresent("AL_SOFT_source_spatialize"))
mCaps |= CAPS_SourceSpatialize;
}
void SFXALDevice::_initEFX()
{
if (alcIsExtensionPresent(mDevice, "ALC_EXT_EFX") != AL_TRUE)
return;
// Load all EFX procs
SFX_LOAD_AL_PROC(LPALGENEFFECTS, alGenEffects);
SFX_LOAD_AL_PROC(LPALDELETEEFFECTS, alDeleteEffects);
SFX_LOAD_AL_PROC(LPALISEFFECT, alIsEffect);
SFX_LOAD_AL_PROC(LPALEFFECTI, alEffecti);
SFX_LOAD_AL_PROC(LPALEFFECTIV, alEffectiv);
SFX_LOAD_AL_PROC(LPALEFFECTF, alEffectf);
SFX_LOAD_AL_PROC(LPALEFFECTFV, alEffectfv);
SFX_LOAD_AL_PROC(LPALGETEFFECTI, alGetEffecti);
SFX_LOAD_AL_PROC(LPALGETEFFECTIV, alGetEffectiv);
SFX_LOAD_AL_PROC(LPALGETEFFECTF, alGetEffectf);
SFX_LOAD_AL_PROC(LPALGETEFFECTFV, alGetEffectfv);
SFX_LOAD_AL_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots);
SFX_LOAD_AL_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots);
SFX_LOAD_AL_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot);
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti);
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv);
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf);
SFX_LOAD_AL_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv);
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti);
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv);
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf);
SFX_LOAD_AL_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv);
SFX_LOAD_AL_PROC(LPALGENFILTERS, alGenFilters);
SFX_LOAD_AL_PROC(LPALDELETEFILTERS, alDeleteFilters);
SFX_LOAD_AL_PROC(LPALISFILTER, alIsFilter);
SFX_LOAD_AL_PROC(LPALFILTERI, alFilteri);
SFX_LOAD_AL_PROC(LPALFILTERIV, alFilteriv);
SFX_LOAD_AL_PROC(LPALFILTERF, alFilterf);
SFX_LOAD_AL_PROC(LPALFILTERFV, alFilterfv);
SFX_LOAD_AL_PROC(LPALGETFILTERI, alGetFilteri);
SFX_LOAD_AL_PROC(LPALGETFILTERIV, alGetFilteriv);
SFX_LOAD_AL_PROC(LPALGETFILTERF, alGetFilterf);
SFX_LOAD_AL_PROC(LPALGETFILTERFV, alGetFilterfv);
// Verify the minimum set we can't live without
if (!alGenEffects || !alDeleteEffects ||
!alGenAuxiliaryEffectSlots || !alDeleteAuxiliaryEffectSlots ||
!alAuxiliaryEffectSloti)
{
Con::warnf("SFXALDevice - EFX proc loading incomplete, disabling reverb");
return;
}
mCaps |= CAPS_Reverb | CAPS_Occlusion;
// Filters require their own procs
if (alGenFilters && alDeleteFilters && alFilteri && alFilterf)
mCaps |= CAPS_SourceFilters;
// Probe individual effect type support and slot count
_probeEFXEffectCaps();
}
void SFXALDevice::_probeEFXEffectCaps()
{
// Probe which effect types this driver actually supports
// by attempting to set each type on a temporary effect object.
// Some drivers report ALC_EXT_EFX but don't implement all types.
struct EffectProbe { ALenum alType; U32 cap; const char* name; };
static const EffectProbe probes[] =
{
{ AL_EFFECT_EAXREVERB, CAPS_Reverb | CAPS_EXTReverb, "EAX Reverb" },
{ AL_EFFECT_REVERB, CAPS_Reverb, "EAXReverb" },
{ AL_EFFECT_EQUALIZER, CAPS_EFX_EQ, "Equalizer" },
{ AL_EFFECT_COMPRESSOR, CAPS_EFX_Compressor,"Compressor" },
{ AL_EFFECT_ECHO, CAPS_EFX_Echo, "Echo" },
{ AL_EFFECT_CHORUS, CAPS_EFX_Chorus, "Chorus" },
{ AL_EFFECT_DISTORTION, CAPS_EFX_Distortion,"Distortion" },
{ AL_EFFECT_FLANGER, CAPS_EFX_Flanger, "Flanger" },
};
ALuint testEffect = 0;
alGenEffects(1, &testEffect);
for (const EffectProbe& probe : probes)
{
alGetError();
alEffecti(testEffect, AL_EFFECT_TYPE, probe.alType);
if (alGetError() == AL_NO_ERROR)
mCaps |= probe.cap;
}
alDeleteEffects(1, &testEffect);
alGetError();
// Probe aux slot count
Vector<ALuint> slots;
alGetError();
while (slots.size() < 64)
{
ALuint slot = 0;
alGenAuxiliaryEffectSlots(1, &slot);
if (alGetError() != AL_NO_ERROR)
break;
slots.push_back(slot);
}
Con::setIntVariable("$pref::SFX::maxEffectSlots", (S32)slots.size());
ALCint sends = 0;
alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
Con::setIntVariable("$pref::SFX::maxSendsPerSource", (S32)sends);
for (ALuint slot : slots)
alDeleteAuxiliaryEffectSlots(1, &slot);
alGetError();
// Allocate the device-level global reverb slot
alGenAuxiliaryEffectSlots(1, &mAuxSlot);
if (alGetError() != AL_NO_ERROR)
{
Con::warnf("SFXALDevice - Failed to create primary EFX slot");
mCaps &= ~(CAPS_Reverb | CAPS_Occlusion);
mAuxSlot = 0;
}
}
//----------------------------------------------------------------------------
// STATIC OPENAL FUNCTIONS
//----------------------------------------------------------------------------
void SFXALDevice::printALInfo(ALCdevice* device)
{
if (!device)
return;
Con::printBlankLine();
Con::printf("SFX Device Info:");
Con::printf("|------------------------------------------------");
// --- Device name ---
const ALCchar* devname = alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT")
? alcGetString(device, ALC_ALL_DEVICES_SPECIFIER)
: alcGetString(device, ALC_DEVICE_SPECIFIER);
Con::printf("| Device: %s", devname);
// --- OpenAL version ---
ALCint major, minor;
if (device)
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
Con::printf("| OpenAL: %d.%d", major, minor);
// --- Audio format ---
ALCint freq = 0;
alcGetIntegerv(device, ALC_FREQUENCY, 1, &freq);
Con::printf("| Sample Rate: %d Hz", freq > 0 ? freq : 44100);
Con::printf("| Bit Depth: %d-bit", (mCaps & CAPS_Float32) ? 32 : 16);
Con::printf("| Max Voices: %d", mMaxBuffers);
Con::printf("|------------------------------------------------");
Con::printf("| Capabilities:");
// --- Hot reconnect ---
Con::printf("| Hot Reconnect: %s", (mCaps & CAPS_HotReconnect) ? "Yes" : "No");
Con::printf("| Disconnect Detect: %s", (mCaps & CAPS_DisconnectDetect) ? "Yes" : "No");
Con::printf("| Device Clock: %s", (mCaps & CAPS_DeviceClock) ? "Yes" : "No");
Con::printf("| Multi-Listener: %s", (mCaps & CAPS_MultiListener) ? "Yes" : "No");
Con::printf("| Float32 Playback: %s", (mCaps & CAPS_Float32) ? "Yes" : "No");
Con::printf("| Multi-Channel: %s", (mCaps & CAPS_MonoStereo) ? "Yes" : "No");
Con::printf("| Spatialize: %s", (mCaps & CAPS_SourceSpatialize) ? "Yes" : "No");
// --- HRTF ---
Con::printf("| HRTF: %s", (mCaps & CAPS_HRTF) ? "Yes" : "No");
if (mCaps & CAPS_HRTF)
{
const ALCchar* devname = NULL;
Con::printBlankLine();
ALCint hrtfStatus = 0;
alcGetIntegerv(device, ALC_HRTF_STATUS_SOFT, 1, &hrtfStatus);
if (mOpenAL.alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
const char* statusStr = "Unknown";
switch (hrtfStatus)
{
devname = mOpenAL.alcGetString(device, ALC_ALL_DEVICES_SPECIFIER);
}
else
{
devname = mOpenAL.alcGetString(device, ALC_DEVICE_SPECIFIER);
case ALC_HRTF_DISABLED_SOFT: statusStr = "Disabled"; break;
case ALC_HRTF_ENABLED_SOFT: statusStr = "Enabled"; break;
case ALC_HRTF_DENIED_SOFT: statusStr = "Denied by device"; break;
case ALC_HRTF_REQUIRED_SOFT: statusStr = "Required by device"; break;
case ALC_HRTF_HEADPHONES_DETECTED_SOFT: statusStr = "Headphones detected"; break;
case ALC_HRTF_UNSUPPORTED_FORMAT_SOFT: statusStr = "Unsupported format"; break;
}
Con::printf("| Status: %s", statusStr);
Con::printf("| Device info for: %s ", devname);
ALCint profileCount = 0;
alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &profileCount);
Con::printf("| Profiles: %d", profileCount);
if (alcGetStringiSOFT && profileCount > 0)
for (ALCint i = 0; i < profileCount; i++)
Con::printf("| [%d] %s", i,
alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i));
bool use_hrtf = Con::getBoolVariable("$pref::SFX::useHRTF");
if (use_hrtf && (mCaps & CAPS_HotReconnect))
{
ALCint attr[5];
ALCint index = Con::getIntVariable("$pref::SFX::hrtfProfile");
ALCint i;
i = 0;
attr[i++] = ALC_HRTF_SOFT;
attr[i++] = ALC_TRUE;
// load the default device hrtf.
if (index >= 0 && index < profileCount)
{
attr[i++] = ALC_HRTF_ID_SOFT;
attr[i++] = index;
}
attr[i] = 0;
if (!alcResetDeviceSOFT(mDevice, attr))
{
Con::printf("Failed to reset device: %s", alcGetString(mDevice, alcGetError(mDevice)));
}
}
}
mOpenAL.alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
mOpenAL.alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
Con::printf("| OpenAL Version: %d.%d", major, minor);
if (device)
// --- EFX ---
Con::printf("| EFX Reverb: %s", (mCaps & CAPS_Reverb) ? "Yes" : "No");
if (mCaps & CAPS_Reverb)
{
Con::printf("%s", mOpenAL.alcGetString(device, ALC_EXTENSIONS));
Con::printf("| EQ: %s", (mCaps & CAPS_EFX_EQ) ? "Yes" : "No");
Con::printf("| Compressor: %s", (mCaps & CAPS_EFX_Compressor) ? "Yes" : "No");
Con::printf("| Echo: %s", (mCaps & CAPS_EFX_Echo) ? "Yes" : "No");
Con::printf("| Chorus: %s", (mCaps & CAPS_EFX_Chorus) ? "Yes" : "No");
Con::printf("| Distortion: %s", (mCaps & CAPS_EFX_Distortion) ? "Yes" : "No");
Con::printf("| Flanger: %s", (mCaps & CAPS_EFX_Flanger) ? "Yes" : "No");
Con::printf("| Filters: %s", (mCaps & CAPS_SourceFilters) ? "Yes" : "No");
U32 err = mOpenAL.alcGetError(device);
if (err != ALC_NO_ERROR)
Con::errorf("SFXALDevice - Error Retrieving ALC Extensions: %s", mOpenAL.alcGetString(device, err));
Con::printf("| Effect Slots: %d",
Con::getIntVariable("$pref::SFX::maxEffectSlots"));
Con::printf("| Sends/Source: %d",
Con::getIntVariable("$pref::SFX::maxSendsPerSource"));
}
Con::printf("|------------------------------------------------");
// --- Full extension list last so it doesn't bury the important info ---
const ALchar* extStr = alcGetString(device, ALC_EXTENSIONS);
if (extStr)
{
Con::printf("| ALC Extensions:");
char* extCopy = dStrdup(extStr);
char* token = dStrtok(extCopy, " ");
while (token)
{
Con::printf("| %s", token);
token = dStrtok(NULL, " ");
}
dFree(extCopy);
}
Con::printf("|------------------------------------------------");
Con::printBlankLine();
U32 err = alcGetError(device);
if (err != ALC_NO_ERROR)
Con::errorf("SFXALDevice - ALC error after info query: %s",
alcGetString(device, err));
}
S32 SFXALDevice::getMaxSources()
{
mOpenAL.alGetError();
alGetError();
ALCint nummono;
mOpenAL.alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &nummono);
alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &nummono);
if(nummono == 0)
nummono = getMaxSourcesOld();
@ -81,21 +442,21 @@ S32 SFXALDevice::getMaxSourcesOld()
S32 sourceCount = 0;
// clear errors.
mOpenAL.alGetError();
alGetError();
for(sourceCount = 0; sourceCount < 256; sourceCount++)
{
mOpenAL.alGenSources(1,&uiSource[sourceCount]);
if(mOpenAL.alGetError() != AL_NO_ERROR)
alGenSources(1,&uiSource[sourceCount]);
if(alGetError() != AL_NO_ERROR)
break;
}
mOpenAL.alDeleteSources(sourceCount, uiSource);
if(mOpenAL.alGetError() != AL_NO_ERROR)
alDeleteSources(sourceCount, uiSource);
if(alGetError() != AL_NO_ERROR)
{
for(U32 i = 0; i < 256; i++)
{
mOpenAL.alDeleteSources(1,&uiSource[i]);
alDeleteSources(1,&uiSource[i]);
}
}
@ -103,85 +464,69 @@ S32 SFXALDevice::getMaxSourcesOld()
}
//-----------------------------------------------------------------------------
SFXALDevice::SFXALDevice( SFXProvider *provider,
const OPENALFNTABLE &openal,
String name,
bool useHardware,
S32 maxBuffers )
: Parent( name, provider, useHardware, maxBuffers ),
mOpenAL( openal ),
mContext( NULL ),
mDevice( NULL ),
SFXALDevice::SFXALDevice(U32 providerIndex)
: mContext(NULL),
mDevice(NULL),
mDistanceModel(SFXDistanceModelLinear),
mDistanceFactor(1.0f),
mRolloffFactor( 1.0f ),
mUserRolloffFactor(1.0f)
mRolloffFactor(1.0f),
mUserRolloffFactor(1.0f),
mHasEFX(false),
mHasSoftReopen(false),
mHasSoftHRTF(false),
mEffect(0),
mAuxSlot(0)
{
mMaxBuffers = getMax( maxBuffers, 8 );
SFXProvider* p = SFXSystem::getProvider(providerIndex);
// TODO: The OpenAL device doesn't set the primary buffer
// $pref::SFX::frequency or $pref::SFX::bitrate!
//check auxiliary device sends 4 and add them to the device
ALint attribs[4] = { 0 };
#if defined(AL_ALEXT_PROTOTYPES)
ALCint iSends = 0;
attribs[0] = ALC_MAX_AUXILIARY_SENDS;
#endif
attribs[1] = 4;
printALInfo(NULL);
mDevice = mOpenAL.alcOpenDevice( name );
U32 err = mOpenAL.alcGetError(mDevice);
if (err != ALC_NO_ERROR)
Con::errorf("SFXALDevice - Device Initialization Error: %s", mOpenAL.alcGetString(mDevice, err));
if( mDevice )
mDevice = alcOpenDevice(p->getName());
if (!mDevice)
{
mContext = mOpenAL.alcCreateContext( mDevice, attribs );
if( mContext )
mOpenAL.alcMakeContextCurrent( mContext );
#if defined(AL_ALEXT_PROTOTYPES)
mOpenAL.alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &iSends);
#endif
err = mOpenAL.alcGetError( mDevice );
if( err != ALC_NO_ERROR )
Con::errorf( "SFXALDevice - Context Initialization Error: %s", mOpenAL.alcGetString( mDevice, err ) );
Con::errorf("SFXALDevice - Failed to open '%s'", p->getName());
return;
}
AssertFatal( mDevice != NULL && mContext != NULL, "Failed to create OpenAL device and/or context!" );
// Extensions that must be loaded before context creation
_initExtensions();
// Start the update thread.
// TODO AsyncPeriodicUpdateThread support for Linux/Mac
#ifdef TORQUE_OS_WIN
if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
mContext = alcCreateContext(mDevice, NULL);
if (!mContext)
{
SFXInternal::gUpdateThread = new AsyncPeriodicUpdateThread
( "OpenAL Update Thread", SFXInternal::gBufferUpdateList,
Con::getIntVariable( "$pref::SFX::updateInterval", SFXInternal::DEFAULT_UPDATE_INTERVAL ) );
Con::errorf("SFXALDevice - Failed to create context (error %d)",
alcGetError(mDevice));
alcCloseDevice(mDevice);
mDevice = NULL;
return;
}
alcMakeContextCurrent(mContext);
#ifdef TORQUE_OS_WIN
if (!Con::getBoolVariable("$_forceAllMainThread"))
{
SFXInternal::gUpdateThread = new AsyncPeriodicUpdateThread(
"OpenAL Update Thread", SFXInternal::gBufferUpdateList,
Con::getIntVariable("$pref::SFX::updateInterval",
SFXInternal::DEFAULT_UPDATE_INTERVAL));
SFXInternal::gUpdateThread->start();
}
#endif
#if defined(AL_ALEXT_PROTOTYPES)
dMemset(effectSlot, 0, sizeof(effectSlot));
dMemset(effect, 0, sizeof(effect));
uLoop = 0;
#endif
// Context is current — load context-level extensions and EFX
_initExtensions(); // second pass picks up AL_* extensions now context is current
_initEFX();
// Read back what the device actually settled on
ALCint freq = 0;
alcGetIntegerv(mDevice, ALC_FREQUENCY, 1, &freq);
Con::setIntVariable("$pref::SFX::frequency", freq > 0 ? freq : 44100);
Con::setIntVariable("$pref::SFX::bitrate", (mCaps & CAPS_Float32) ? 32 : 16);
printALInfo(mDevice);
mMaxBuffers = getMaxSources();
// this should be max sources.
Con::printf("| Max Sources: %d", mMaxBuffers);
Con::setIntVariable("$pref::SFX::maxSoftwareBuffers", mMaxBuffers);
}
//-----------------------------------------------------------------------------
@ -189,26 +534,66 @@ SFXALDevice::SFXALDevice( SFXProvider *provider,
SFXALDevice::~SFXALDevice()
{
_releaseAllResources();
///cleanup our effects
#if defined(AL_ALEXT_PROTOTYPES)
mOpenAL.alDeleteAuxiliaryEffectSlots(4, effectSlot);
mOpenAL.alDeleteEffects(2, effect);
#endif
if (alIsEffect(mEffect))
{
alDeleteAuxiliaryEffectSlots(1, &mAuxSlot);
alDeleteEffects(1, &mEffect);
}
///cleanup of effects ends
mOpenAL.alcMakeContextCurrent( NULL );
mOpenAL.alcDestroyContext( mContext );
mOpenAL.alcCloseDevice( mDevice );
alcMakeContextCurrent( NULL );
alcDestroyContext( mContext );
alcCloseDevice( mDevice );
}
//-----------------------------------------------------------------------------
void SFXALDevice::enumerateProviders(Vector<SFXProvider*>& providerList)
{
const ALCchar* devices;
U32 index = providerList.size();
const ALCchar* defaultDeviceName;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") == AL_TRUE)
{
devices = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
defaultDeviceName = alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
}
else
{
devices = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
defaultDeviceName = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
}
const ALCchar* currentDevice = devices;
while (*currentDevice != '\0')
{
SFXProvider* toAdd = new SFXProvider;
toAdd->mName = String::ToString(currentDevice);
toAdd->mIndex = index;
toAdd->mDeviceType = Output;
toAdd->mType = OpenAL;
toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance;
if (String::compare(currentDevice, defaultDeviceName) == 0)
toAdd->mDefault = true;
currentDevice += dStrlen(currentDevice) + 1;
index++;
providerList.push_back(toAdd);
}
}
SFXBuffer* SFXALDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
{
AssertFatal( stream, "SFXALDevice::createBuffer() - Got null stream!" );
AssertFatal( description, "SFXALDevice::createBuffer() - Got null description!" );
SFXALBuffer* buffer = SFXALBuffer::create( mOpenAL,
stream,
SFXALBuffer* buffer = SFXALBuffer::create( stream,
description,
mUseHardware );
if ( !buffer )
@ -258,14 +643,9 @@ void SFXALDevice::setListener( U32 index, const SFXListenerProperties& listener
const VectorF &velocity = listener.getVelocity();
mOpenAL.alListenerfv( AL_POSITION, pos );
mOpenAL.alListenerfv( AL_VELOCITY, velocity );
mOpenAL.alListenerfv( AL_ORIENTATION, (const F32 *)&tupple[0] );
///Pass a unit size to openal, 1.0 assumes 1 meter to 1 game unit.
///Crucial for air absorbtion calculations.
#if defined(AL_ALEXT_PROTOTYPES)
mOpenAL.alListenerf(AL_METERS_PER_UNIT, 1.0f);
#endif
alListenerfv( AL_POSITION, pos );
alListenerfv( AL_VELOCITY, velocity );
alListenerfv( AL_ORIENTATION, (const F32 *)&tupple[0] );
}
//-----------------------------------------------------------------------------
@ -275,19 +655,19 @@ void SFXALDevice::setDistanceModel( SFXDistanceModel model )
switch( model )
{
case SFXDistanceModelLinear:
mOpenAL.alDistanceModel( AL_LINEAR_DISTANCE_CLAMPED );
alDistanceModel( AL_LINEAR_DISTANCE_CLAMPED );
if( mRolloffFactor != 1.0f )
_setRolloffFactor( 1.0f ); // No rolloff on linear.
break;
case SFXDistanceModelLogarithmic:
mOpenAL.alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
if( mUserRolloffFactor != mRolloffFactor )
_setRolloffFactor( mUserRolloffFactor );
break;
/// create a case for our exponential distance model
case SFXDistanceModelExponent:
mOpenAL.alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
if (mUserRolloffFactor != mRolloffFactor)
_setRolloffFactor(mUserRolloffFactor);
break;
@ -301,19 +681,103 @@ void SFXALDevice::setDistanceModel( SFXDistanceModel model )
//-----------------------------------------------------------------------------
void SFXALDevice::setDopplerFactor( F32 factor )
void SFXALDevice::setReverb(const SFXReverbProperties& r)
{
mOpenAL.alDopplerFactor( factor );
if (!(mCaps & CAPS_Reverb))
return;
/* Clear error state. */
alGetError();
if (alIsEffect(mEffect))
alDeleteEffects(1, &mEffect);
/* Create the effect object and check if we can do EAX reverb. */
alGenEffects(1, &mEffect);
// Map your engine's properties to EFX parameters.
// Using EAX Reverb as an example:
if (mCaps & CAPS_EXTReverb)
{
// Full EAX parameter set — panning vectors, LF params, modulation etc.
alEffecti(mEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
if (alGetError() == AL_NO_ERROR)
{
alEffectf(mEffect, AL_EAXREVERB_DENSITY, r.flDensity);
alEffectf(mEffect, AL_EAXREVERB_DIFFUSION, r.flDiffusion);
alEffectf(mEffect, AL_EAXREVERB_GAIN, r.flGain);
alEffectf(mEffect, AL_EAXREVERB_GAINHF, r.flGainHF);
alEffectf(mEffect, AL_EAXREVERB_GAINLF, r.flGainLF);
alEffectf(mEffect, AL_EAXREVERB_DECAY_TIME, r.flDecayTime);
alEffectf(mEffect, AL_EAXREVERB_DECAY_HFRATIO, r.flDecayHFRatio);
alEffectf(mEffect, AL_EAXREVERB_DECAY_LFRATIO, r.flDecayLFRatio);
alEffectf(mEffect, AL_EAXREVERB_REFLECTIONS_GAIN, r.flReflectionsGain);
alEffectf(mEffect, AL_EAXREVERB_REFLECTIONS_DELAY, r.flReflectionsDelay);
alEffectfv(mEffect, AL_EAXREVERB_REFLECTIONS_PAN, r.flReflectionsPan);
alEffectf(mEffect, AL_EAXREVERB_LATE_REVERB_GAIN, r.flLateReverbGain);
alEffectf(mEffect, AL_EAXREVERB_LATE_REVERB_DELAY, r.flLateReverbDelay);
alEffectfv(mEffect, AL_EAXREVERB_LATE_REVERB_PAN, r.flLateReverbPan);
alEffectf(mEffect, AL_EAXREVERB_ECHO_TIME, r.flEchoTime);
alEffectf(mEffect, AL_EAXREVERB_ECHO_DEPTH, r.flEchoDepth);
alEffectf(mEffect, AL_EAXREVERB_MODULATION_TIME, r.flModulationTime);
alEffectf(mEffect, AL_EAXREVERB_MODULATION_DEPTH, r.flModulationDepth);
alEffectf(mEffect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, r.flAirAbsorptionGainHF);
alEffectf(mEffect, AL_EAXREVERB_HFREFERENCE, r.flHFReference);
alEffectf(mEffect, AL_EAXREVERB_LFREFERENCE, r.flLFReference);
alEffectf(mEffect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, r.flRoomRolloffFactor);
alEffecti(mEffect, AL_EAXREVERB_DECAY_HFLIMIT, r.iDecayHFLimit);
}
}
else
{
// Standard reverb — subset of EAX, no panning/LF/modulation params
alEffecti(mEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
if (alGetError() == AL_NO_ERROR)
{
alEffectf(mEffect, AL_REVERB_DENSITY, r.flDensity);
alEffectf(mEffect, AL_REVERB_DIFFUSION, r.flDiffusion);
alEffectf(mEffect, AL_REVERB_GAIN, r.flGain);
alEffectf(mEffect, AL_REVERB_GAINHF, r.flGainHF);
alEffectf(mEffect, AL_REVERB_DECAY_TIME, r.flDecayTime);
alEffectf(mEffect, AL_REVERB_DECAY_HFRATIO, r.flDecayHFRatio);
alEffectf(mEffect, AL_REVERB_REFLECTIONS_GAIN, r.flReflectionsGain);
alEffectf(mEffect, AL_REVERB_REFLECTIONS_DELAY, r.flReflectionsDelay);
alEffectf(mEffect, AL_REVERB_LATE_REVERB_GAIN, r.flLateReverbGain);
alEffectf(mEffect, AL_REVERB_LATE_REVERB_DELAY, r.flLateReverbDelay);
alEffectf(mEffect, AL_REVERB_AIR_ABSORPTION_GAINHF, r.flAirAbsorptionGainHF);
alEffectf(mEffect, AL_REVERB_ROOM_ROLLOFF_FACTOR, r.flRoomRolloffFactor);
alEffecti(mEffect, AL_REVERB_DECAY_HFLIMIT, r.iDecayHFLimit);
}
}
if (alGetError() == AL_NO_ERROR)
alAuxiliaryEffectSloti(mAuxSlot, AL_EFFECTSLOT_EFFECT, (ALint)mEffect);
else
{
Con::warnf("SFXALDevice::setReverb - failed applying reverb parameters");
if (alIsEffect(mEffect))
alDeleteEffects(1, &mEffect);
mEffect = 0;
}
}
//-----------------------------------------------------------------------------
void SFXALDevice::setDopplerFactor( F32 factor )
{
alDopplerFactor( factor );
}
void SFXALDevice::_setRolloffFactor( F32 factor )
{
mRolloffFactor = factor;
for( U32 i = 0, num = mVoices.size(); i < num; ++ i )
mOpenAL.alSourcef( ( ( SFXALVoice* ) mVoices[ i ] )->mSourceName, AL_ROLLOFF_FACTOR, factor );
alSourcef( ( ( SFXALVoice* ) mVoices[ i ] )->mSourceName, AL_ROLLOFF_FACTOR, factor );
}
//-----------------------------------------------------------------------------
@ -328,110 +792,83 @@ void SFXALDevice::setRolloffFactor( F32 factor )
mUserRolloffFactor = factor;
}
#if defined(AL_ALEXT_PROTOTYPES)
void SFXALDevice::openSlots()
void SFXALDevice::setSpeedOfSound(F32 speedOfSound)
{
for (uLoop = 0; uLoop < 4; uLoop++)
{
mOpenAL.alGenAuxiliaryEffectSlots(1, &effectSlot[uLoop]);
}
for (uLoop = 0; uLoop < 2; uLoop++)
{
mOpenAL.alGenEffects(1, &effect[uLoop]);
}
///debug string output so we know our slots are open
Platform::outputDebugString("Slots Open");
alSpeedOfSound(speedOfSound);
}
///create reverb effect
void SFXALDevice::setReverb(const SFXReverbProperties& reverb)
bool SFXALDevice::isDeviceConnected()
{
///output a debug string so we know each time the reverb changes
Platform::outputDebugString("Updated");
if (!mDevice)
return false;
///load an efxeaxreverb default and add our values from
///sfxreverbproperties to it
EFXEAXREVERBPROPERTIES prop = EFX_REVERB_PRESET_GENERIC;
prop.flDensity = reverb.flDensity;
prop.flDiffusion = reverb.flDiffusion;
prop.flGain = reverb.flGain;
prop.flGainHF = reverb.flGainHF;
prop.flGainLF = reverb.flGainLF;
prop.flDecayTime = reverb.flDecayTime;
prop.flDecayHFRatio = reverb.flDecayHFRatio;
prop.flDecayLFRatio = reverb.flDecayLFRatio;
prop.flReflectionsGain = reverb.flReflectionsGain;
prop.flReflectionsDelay = reverb.flReflectionsDelay;
prop.flLateReverbGain = reverb.flLateReverbGain;
prop.flLateReverbDelay = reverb.flLateReverbDelay;
prop.flEchoTime = reverb.flEchoTime;
prop.flEchoDepth = reverb.flEchoDepth;
prop.flModulationTime = reverb.flModulationTime;
prop.flModulationDepth = reverb.flModulationDepth;
prop.flAirAbsorptionGainHF = reverb.flAirAbsorptionGainHF;
prop.flHFReference = reverb.flHFReference;
prop.flLFReference = reverb.flLFReference;
prop.flRoomRolloffFactor = reverb.flRoomRolloffFactor;
prop.iDecayHFLimit = reverb.iDecayHFLimit;
if (mOpenAL.alGetEnumValue("AL_EFFECT_EAXREVERB") != 0)
// ALC_CONNECTED is a standard-ish extension, check it first
if (alcIsExtensionPresent(mDevice, "ALC_EXT_disconnect") == AL_TRUE)
{
ALCint connected = ALC_FALSE;
alcGetIntegerv(mDevice, ALC_CONNECTED, 1, &connected);
/// EAX Reverb is available. Set the EAX effect type
mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
///add our values to the setup of the reverb
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DENSITY, prop.flDensity);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DIFFUSION, prop.flDiffusion);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAIN, prop.flGain);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINHF, prop.flGainHF);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINLF, prop.flGainLF);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_TIME, prop.flDecayTime);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_HFRATIO, prop.flDecayHFRatio);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_LFRATIO, prop.flDecayLFRatio);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_GAIN, prop.flReflectionsGain);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_GAIN, prop.flLateReverbGain);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_TIME, prop.flEchoTime);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_DEPTH, prop.flEchoDepth);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_TIME, prop.flModulationTime);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_DEPTH, prop.flModulationDepth);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_HFREFERENCE, prop.flHFReference);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LFREFERENCE, prop.flLFReference);
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor);
mOpenAL.alEffecti(effect[0], AL_EAXREVERB_DECAY_HFLIMIT, prop.iDecayHFLimit);
mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]);
Platform::outputDebugString("eax reverb properties set");
}
else
{
/// No EAX Reverb. Set the standard reverb effect
mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB);
mOpenAL.alEffectf(effect[0], AL_REVERB_DENSITY, prop.flDensity);
mOpenAL.alEffectf(effect[0], AL_REVERB_DIFFUSION, prop.flDiffusion);
mOpenAL.alEffectf(effect[0], AL_REVERB_GAIN, prop.flGain);
mOpenAL.alEffectf(effect[0], AL_REVERB_GAINHF, prop.flGainHF);
mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_TIME, prop.flDecayTime);
mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_HFRATIO, prop.flDecayHFRatio);
mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_GAIN, prop.flReflectionsGain);
mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay);
mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_GAIN, prop.flLateReverbGain);
mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay);
mOpenAL.alEffectf(effect[0], AL_REVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF);
mOpenAL.alEffectf(effect[0], AL_REVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor);
mOpenAL.alEffecti(effect[0], AL_REVERB_DECAY_HFLIMIT, prop.iDecayHFLimit);
mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]);
if (connected == ALC_FALSE)
{
//SFXSystem::removeProvider(mDevice->getProvider());
}
return (connected == ALC_TRUE);
}
// If the extension isn't available, assume connected
return true;
}
bool SFXALDevice::reconnectDevice(U32 providerIndex)
{
if (!mDevice || !mContext)
{
Con::errorf("SFXALDevice::reconnectDevice - no active device/context to reconnect");
return false;
}
SFXProvider* p = SFXSystem::getProvider(providerIndex);
// If no new name given, reuse the current device name (i.e. reconnect same device)
if (!p->getName() || p->getName()[0] == '\0')
{
Con::errorf("SFXALDevice::reconnectDevice - unsupported provider given.");
return false;
}
Con::printf("SFXALDevice::reconnectDevice - reconnecting to '%s'", p->getName());
// Fast path: use ALC_SOFT_reopen_device to swap device without losing context.
// All sources/buffers remain valid, playback resumes automatically.
if (mHasSoftReopen && alcReopenDeviceSOFT)
{
// Build attribute list matching current device settings
ALCint attribs[] =
{
ALC_FREQUENCY, smDeviceFrequency,
ALC_MONO_SOURCES, mMaxBuffers,
0
};
if (alcReopenDeviceSOFT(mDevice, p->getName(), attribs) == ALC_TRUE)
{
Con::printf("SFXALDevice::reconnectDevice - soft reopen succeeded");
return true;
}
Con::warnf("SFXALDevice::reconnectDevice - soft reopen failed (error %d), "
"falling back to full recreate", alcGetError(mDevice));
}
// Slow path: destroy context and reopen device from scratch.
// SFXSystem::createDevice will handle transitioning sounds to virtual playback.
Con::printf("SFXALDevice::reconnectDevice - performing full device recreate");
alcMakeContextCurrent(NULL);
alcDestroyContext(mContext);
mContext = NULL;
alcCloseDevice(mDevice);
mDevice = NULL;
return false;
}
#endif

View file

@ -23,8 +23,6 @@
#ifndef _SFXALDEVICE_H_
#define _SFXALDEVICE_H_
class SFXProvider;
#ifndef _SFXDEVICE_H_
# include "sfx/sfxDevice.h"
#endif
@ -45,65 +43,70 @@ class SFXProvider;
# include "sfx/openal/LoadOAL.h"
#endif
#ifndef _SFXSYSTEM_H_
#include "sfx/sfxSystem.h"
#endif
class SFXALDevice : public SFXDevice
{
public:
private:
void _initExtensions();
void _initEFX();
void _probeEFXEffectCaps();
public:
typedef SFXDevice Parent;
friend class SFXALVoice; // mDistanceFactor, mRolloffFactor
typedef SFXDevice Parent;
friend class SFXALVoice; // mDistanceFactor, mRolloffFactor
void printALInfo(ALCdevice* device);
void printHRTFInfo(ALCdevice* device);
void getEFXInfo(ALCdevice* device);
S32 getMaxSources();
static SFXDevice* createInstance(U32 adapterIndex);
void printALInfo(ALCdevice* device);
S32 getMaxSources();
// Compatibility with pre openal 1.2
S32 getMaxSourcesOld();
// Compatibility with pre openal 1.2
S32 getMaxSourcesOld();
SFXALDevice( SFXProvider *provider,
const OPENALFNTABLE &openal,
String name,
bool useHardware,
S32 maxBuffers );
SFXALDevice(U32 providerIndex);
virtual ~SFXALDevice();
virtual ~SFXALDevice();
protected:
protected:
static SFXProvider::CreateProviderInstanceDelegate mCreateDeviceInstance;
OPENALFNTABLE mOpenAL;
OPENALFNTABLE mOpenAL;
ALCcontext *mContext;
ALCcontext *mContext;
ALCdevice *mDevice;
ALCdevice *mDevice;
SFXDistanceModel mDistanceModel;
F32 mDistanceFactor;
F32 mRolloffFactor;
F32 mUserRolloffFactor;
void _setRolloffFactor( F32 factor );
SFXDistanceModel mDistanceModel;
F32 mDistanceFactor;
F32 mRolloffFactor;
F32 mUserRolloffFactor;
public:
ALuint mEffect;
ALuint mAuxSlot;
bool mHasEFX;
bool mHasSoftHRTF;
bool mHasSoftReopen;
// SFXDevice.
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
void setListener( U32 index, const SFXListenerProperties& listener ) override;
void setDistanceModel( SFXDistanceModel model ) override;
void setDopplerFactor( F32 factor ) override;
void setRolloffFactor( F32 factor ) override;
#if defined(AL_ALEXT_PROTOTYPES)
//function for openAL to open slots
virtual void openSlots();
//slots
ALuint effectSlot[4] = { 0 };
ALuint effect[2] = { 0 };
ALuint uLoop;
//get values from sfxreverbproperties and pass it to openal device
virtual void setReverb(const SFXReverbProperties& reverb);
#endif
void resetReverb() override {}
void _setRolloffFactor( F32 factor );
public:
static void enumerateProviders(Vector<SFXProvider*>& providerList);
// SFXDevice.
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
void setListener( U32 index, const SFXListenerProperties& listener ) override;
void setDistanceModel( SFXDistanceModel model ) override;
void setDopplerFactor( F32 factor ) override;
void setReverb(const SFXReverbProperties& reverb) override;
void setRolloffFactor( F32 factor ) override;
void resetReverb() override {}
void setSpeedOfSound(F32 speedOfSound) override;
bool isDeviceConnected() override;
bool reconnectDevice(U32 providerIndex) override;
ALuint getDeviceAuxSlot() { return mAuxSlot; }
};
#endif // _SFXALDEVICE_H_

View file

@ -1,127 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "sfx/sfxProvider.h"
#include "sfx/openal/sfxALDevice.h"
#include "sfx/openal/aldlist.h"
#include "sfx/openal/LoadOAL.h"
#include "core/strings/stringFunctions.h"
#include "console/console.h"
#include "core/module.h"
class SFXALProvider : public SFXProvider
{
public:
SFXALProvider()
: SFXProvider( "OpenAL" ) { dMemset(&mOpenAL,0,sizeof(mOpenAL)); mALDL = NULL; }
virtual ~SFXALProvider();
protected:
OPENALFNTABLE mOpenAL;
ALDeviceList *mALDL;
struct ALDeviceInfo : SFXDeviceInfo
{
};
void init() override;
public:
SFXDevice *createDevice( const String& deviceName, bool useHardware, S32 maxBuffers ) override;
};
MODULE_BEGIN( OpenAL )
MODULE_INIT_BEFORE( SFX )
MODULE_SHUTDOWN_AFTER( SFX )
SFXALProvider* mProvider = NULL;
MODULE_INIT
{
mProvider = new SFXALProvider;
}
MODULE_SHUTDOWN
{
delete mProvider;
}
MODULE_END;
void SFXALProvider::init()
{
if( LoadOAL10Library( NULL, &mOpenAL ) != AL_TRUE )
{
Con::printf( "SFXALProvider - OpenAL not available." );
return;
}
mALDL = new ALDeviceList( mOpenAL );
// Did we get any devices?
if ( mALDL->GetNumDevices() < 1 )
{
Con::printf( "SFXALProvider - No valid devices found!" );
return;
}
// Cool, loop through them, and caps em
//const char *deviceFormat = "OpenAL v%d.%d %s";
for( S32 i = 0; i < mALDL->GetNumDevices(); i++ )
{
ALDeviceInfo* info = new ALDeviceInfo;
//info->internalName = String( mALDL->GetInternalDeviceName( i ) );
info->name = String( mALDL->GetDeviceName( i ) );
mDeviceInfo.push_back( info );
}
regProvider( this );
}
SFXALProvider::~SFXALProvider()
{
UnloadOAL10Library();
if (mALDL)
delete mALDL;
}
SFXDevice* SFXALProvider::createDevice(const String& deviceName, bool useHardware, S32 maxBuffers)
{
ALDeviceInfo* info = dynamic_cast<ALDeviceInfo*>
(_findDeviceInfo(deviceName));
// Do we find one to create?
if (info)
return new SFXALDevice(this, mOpenAL, info->name, useHardware, maxBuffers);
return NULL;
}

View file

@ -28,7 +28,7 @@
#ifdef TORQUE_DEBUG
# define AL_SANITY_CHECK() \
AssertFatal( mOpenAL.alIsSource( mSourceName ), "AL Source Sanity Check Failed!" );
AssertFatal( alIsSource( mSourceName ), "AL Source Sanity Check Failed!" );
#else
# define AL_SANITY_CHECK()
#endif
@ -42,8 +42,8 @@ SFXALVoice* SFXALVoice::create( SFXALDevice* device, SFXALBuffer *buffer )
AssertFatal( buffer, "SFXALVoice::create() - Got null buffer!" );
ALuint sourceName;
device->mOpenAL.alGenSources( 1, &sourceName );
AssertFatal( device->mOpenAL.alIsSource( sourceName ), "AL Source Sanity Check Failed!" );
alGenSources( 1, &sourceName );
AssertFatal( alIsSource( sourceName ), "AL Source Sanity Check Failed!" );
// Is this 3d?
// Okay, this looks odd, but bear with me for a moment. AL_SOURCE_RELATIVE does NOT indicate
@ -52,34 +52,41 @@ SFXALVoice* SFXALVoice::create( SFXALDevice* device, SFXALBuffer *buffer )
// does do is dictate if the position of THIS SOURCE is relative to the listener. If AL_SOURCE_RELATIVE is AL_TRUE
// and the source's position is 0, 0, 0, then the source is directly on top of the listener at all times, which is what
// we want for non-3d sounds.
device->mOpenAL.alSourcei( sourceName, AL_SOURCE_RELATIVE, ( buffer->mIs3d ? AL_FALSE : AL_TRUE ) );
alSourcei( sourceName, AL_SOURCE_RELATIVE, ( buffer->mIs3d ? AL_FALSE : AL_TRUE ) );
if( buffer->mIs3d )
device->mOpenAL.alSourcef( sourceName, AL_ROLLOFF_FACTOR, device->mRolloffFactor );
alSourcef( sourceName, AL_ROLLOFF_FACTOR, device->mRolloffFactor );
SFXALVoice *voice = new SFXALVoice( device->mOpenAL,
buffer,
SFXALVoice *voice = new SFXALVoice( buffer,
sourceName );
// does our device support reverb
if (device->mCaps & SFXDevice::ECaps::CAPS_Reverb)
{
voice->mDeviceAuxSlot = (ALint)device->getDeviceAuxSlot();
alSource3i(sourceName, AL_AUXILIARY_SEND_FILTER, voice->mDeviceAuxSlot, 0, AL_FILTER_NULL);
}
return voice;
}
SFXALVoice::SFXALVoice( const OPENALFNTABLE &oalft,
SFXALBuffer *buffer,
SFXALVoice::SFXALVoice( SFXALBuffer *buffer,
ALuint sourceName )
: Parent( buffer ),
mSourceName( sourceName ),
mResumeAtSampleOffset( -1.0f ),
mDeviceAuxSlot(0),
mSampleOffset( 0 ),
mOpenAL( oalft )
mUseReverb(false)
{
AL_SANITY_CHECK();
}
SFXALVoice::~SFXALVoice()
{
mOpenAL.alDeleteSources( 1, &mSourceName );
alSourcei(mSourceName, AL_BUFFER, 0);
alDeleteSources( 1, &mSourceName );
}
void SFXALVoice::_lateBindStaticBufferIfNecessary()
@ -87,9 +94,9 @@ void SFXALVoice::_lateBindStaticBufferIfNecessary()
if( !mBuffer->isStreaming() )
{
ALint bufferId;
mOpenAL.alGetSourcei( mSourceName, AL_BUFFER, &bufferId );
alGetSourcei( mSourceName, AL_BUFFER, &bufferId );
if( !bufferId )
mOpenAL.alSourcei( mSourceName, AL_BUFFER, _getBuffer()->mALBuffer );
alSourcei( mSourceName, AL_BUFFER, _getBuffer()->mALBuffer );
}
}
@ -99,7 +106,7 @@ SFXStatus SFXALVoice::_status() const
AL_SANITY_CHECK();
ALint state;
mOpenAL.alGetSourcei( mSourceName, AL_SOURCE_STATE, &state );
alGetSourcei( mSourceName, AL_SOURCE_STATE, &state );
switch( state )
{
@ -118,18 +125,15 @@ void SFXALVoice::_play()
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXALVoice] Starting playback" );
#endif
#if defined(AL_ALEXT_PROTOTYPES)
//send every voice that plays to the alauxiliary slot that has the reverb
mOpenAL.alSource3i(mSourceName, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL);
#endif
mOpenAL.alSourcePlay( mSourceName );
alSourcePlay( mSourceName );
//WORKAROUND: Adjust play cursor for buggy OAL when resuming playback. Do this after alSourcePlay
// as it is the play function that will cause the cursor to jump.
if( mResumeAtSampleOffset != -1.0f )
{
mOpenAL.alSourcef( mSourceName, AL_SAMPLE_OFFSET, mResumeAtSampleOffset );
alSourcef( mSourceName, AL_SAMPLE_OFFSET, mResumeAtSampleOffset );
mResumeAtSampleOffset = -1.0f;
}
}
@ -142,12 +146,12 @@ void SFXALVoice::_pause()
Platform::outputDebugString( "[SFXALVoice] Pausing playback" );
#endif
mOpenAL.alSourcePause( mSourceName );
alSourcePause( mSourceName );
//WORKAROUND: Another workaround for buggy OAL. Resuming playback of a paused source will cause the
// play cursor to jump. Save the cursor so we can manually move it into position in _play(). Sigh.
mOpenAL.alGetSourcef( mSourceName, AL_SAMPLE_OFFSET, &mResumeAtSampleOffset );
alGetSourcef( mSourceName, AL_SAMPLE_OFFSET, &mResumeAtSampleOffset );
}
void SFXALVoice::_stop()
@ -158,7 +162,7 @@ void SFXALVoice::_stop()
Platform::outputDebugString( "[SFXALVoice] Stopping playback" );
#endif
mOpenAL.alSourceStop( mSourceName );
alSourceStop( mSourceName );
mSampleOffset = 0;
mResumeAtSampleOffset = -1.0f;
@ -169,7 +173,7 @@ void SFXALVoice::_seek( U32 sample )
AL_SANITY_CHECK();
_lateBindStaticBufferIfNecessary();
mOpenAL.alSourcei( mSourceName, AL_SAMPLE_OFFSET, sample );
alSourcei( mSourceName, AL_SAMPLE_OFFSET, sample );
mResumeAtSampleOffset = -1.0f;
}
@ -183,7 +187,7 @@ U32 SFXALVoice::_tell() const
mBuffer->write( NULL, 0 );
ALint pos;
mOpenAL.alGetSourcei( mSourceName, AL_SAMPLE_OFFSET, &pos );
alGetSourcei( mSourceName, AL_SAMPLE_OFFSET, &pos );
return ( pos + mSampleOffset );
}
@ -191,17 +195,17 @@ void SFXALVoice::setMinMaxDistance( F32 min, F32 max )
{
AL_SANITY_CHECK();
mOpenAL.alSourcef( mSourceName, AL_REFERENCE_DISTANCE, min );
mOpenAL.alSourcef( mSourceName, AL_MAX_DISTANCE, max );
alSourcef( mSourceName, AL_REFERENCE_DISTANCE, min );
alSourcef( mSourceName, AL_MAX_DISTANCE, max );
}
void SFXALVoice::play( bool looping )
{
AL_SANITY_CHECK();
mOpenAL.alSourceStop( mSourceName );
alSourceStop( mSourceName );
if( !mBuffer->isStreaming() )
mOpenAL.alSourcei( mSourceName, AL_LOOPING, ( looping ? AL_TRUE : AL_FALSE ) );
alSourcei( mSourceName, AL_LOOPING, ( looping ? AL_TRUE : AL_FALSE ) );
Parent::play( looping );
}
@ -213,7 +217,7 @@ void SFXALVoice::setVelocity( const VectorF& velocity )
// Torque and OpenAL are both right handed
// systems, so no coordinate flipping is needed.
mOpenAL.alSourcefv( mSourceName, AL_VELOCITY, velocity );
alSourcefv( mSourceName, AL_VELOCITY, velocity );
}
void SFXALVoice::setTransform( const MatrixF& transform )
@ -227,34 +231,47 @@ void SFXALVoice::setTransform( const MatrixF& transform )
transform.getColumn( 3, &pos );
transform.getColumn( 1, &dir );
mOpenAL.alSourcefv( mSourceName, AL_POSITION, pos );
mOpenAL.alSourcefv( mSourceName, AL_DIRECTION, dir );
alSourcefv( mSourceName, AL_POSITION, pos );
alSourcefv( mSourceName, AL_DIRECTION, dir );
}
void SFXALVoice::setReverb(bool useReverb)
{
if (useReverb == mUseReverb)
return;
if (!useReverb)
alSource3i(mSourceName, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
else
alSource3i(mSourceName, AL_AUXILIARY_SEND_FILTER, mDeviceAuxSlot, 0, AL_FILTER_NULL);
mUseReverb = useReverb;
}
void SFXALVoice::setVolume( F32 volume )
{
AL_SANITY_CHECK();
mOpenAL.alSourcef( mSourceName, AL_GAIN, volume );
alSourcef( mSourceName, AL_GAIN, volume );
}
void SFXALVoice::setPitch( F32 pitch )
{
AL_SANITY_CHECK();
mOpenAL.alSourcef( mSourceName, AL_PITCH, pitch );
alSourcef( mSourceName, AL_PITCH, pitch );
}
void SFXALVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
{
AL_SANITY_CHECK();
mOpenAL.alSourcef( mSourceName, AL_CONE_INNER_ANGLE, innerAngle );
mOpenAL.alSourcef( mSourceName, AL_CONE_OUTER_ANGLE, outerAngle );
mOpenAL.alSourcef( mSourceName, AL_CONE_OUTER_GAIN, outerVolume );
alSourcef( mSourceName, AL_CONE_INNER_ANGLE, innerAngle );
alSourcef( mSourceName, AL_CONE_OUTER_ANGLE, outerAngle );
alSourcef( mSourceName, AL_CONE_OUTER_GAIN, outerVolume );
}
void SFXALVoice::setRolloffFactor( F32 factor )
{
mOpenAL.alSourcef( mSourceName, AL_ROLLOFF_FACTOR, factor );
alSourcef( mSourceName, AL_ROLLOFF_FACTOR, factor );
}

View file

@ -47,14 +47,15 @@ class SFXALVoice : public SFXVoice
protected:
SFXALVoice( const OPENALFNTABLE &oalft,
SFXALBuffer *buffer,
SFXALVoice( SFXALBuffer *buffer,
ALuint sourceName );
ALuint mSourceName;
/// Buggy OAL jumps around when pausing. Save playback cursor here.
F32 mResumeAtSampleOffset;
bool mUseReverb;
/// Amount by which OAL's reported sample position is offset.
///
@ -63,9 +64,9 @@ class SFXALVoice : public SFXVoice
/// queue we are.
U32 mSampleOffset;
Mutex mMutex;
ALint mDeviceAuxSlot;
const OPENALFNTABLE &mOpenAL;
Mutex mMutex;
///
SFXALBuffer* _getBuffer() const
@ -98,10 +99,11 @@ class SFXALVoice : public SFXVoice
void play( bool looping ) override;
void setVelocity( const VectorF& velocity ) override;
void setTransform( const MatrixF& transform ) override;
void setReverb(bool useReverb) override;
void setVolume( F32 volume ) override;
void setPitch( F32 pitch ) override;
void setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume ) override;
void setRolloffFactor( F32 factor ) override;
};
#endif // _SFXALVOICE_H_
#endif // _SFXALVOICE_H_

View file

@ -1,601 +0,0 @@
/*
* Copyright (c) 2006, Creative Labs Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the distribution.
* * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#include "sfx/openal/LoadOAL.h"
HINSTANCE g_hOpenALDLL = NULL;
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable)
{
if (!lpOALFnTable)
return AL_FALSE;
if (szOALFullPathName)
g_hOpenALDLL = LoadLibraryA(szOALFullPathName);
else
{
#ifdef TORQUE_DEBUG
g_hOpenALDLL = LoadLibraryA("openal32d.dll");
#else
g_hOpenALDLL = LoadLibraryA("openal32.dll");
#endif
}
if (!g_hOpenALDLL)
return AL_FALSE;
memset(lpOALFnTable, 0, sizeof(OPENALFNTABLE));
// Get function pointers
lpOALFnTable->alEnable = (LPALENABLE)GetProcAddress(g_hOpenALDLL, "alEnable");
if (lpOALFnTable->alEnable == NULL)
{
OutputDebugStringA("Failed to retrieve 'alEnable' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDisable = (LPALDISABLE)GetProcAddress(g_hOpenALDLL, "alDisable");
if (lpOALFnTable->alDisable == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDisable' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsEnabled = (LPALISENABLED)GetProcAddress(g_hOpenALDLL, "alIsEnabled");
if (lpOALFnTable->alIsEnabled == NULL)
{
OutputDebugStringA("Failed to retrieve 'alIsEnabled' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBoolean = (LPALGETBOOLEAN)GetProcAddress(g_hOpenALDLL, "alGetBoolean");
if (lpOALFnTable->alGetBoolean == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetBoolean' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetInteger = (LPALGETINTEGER)GetProcAddress(g_hOpenALDLL, "alGetInteger");
if (lpOALFnTable->alGetInteger == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetInteger' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetFloat = (LPALGETFLOAT)GetProcAddress(g_hOpenALDLL, "alGetFloat");
if (lpOALFnTable->alGetFloat == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetFloat' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetDouble = (LPALGETDOUBLE)GetProcAddress(g_hOpenALDLL, "alGetDouble");
if (lpOALFnTable->alGetDouble == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetDouble' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBooleanv = (LPALGETBOOLEANV)GetProcAddress(g_hOpenALDLL, "alGetBooleanv");
if (lpOALFnTable->alGetBooleanv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetBooleanv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetIntegerv = (LPALGETINTEGERV)GetProcAddress(g_hOpenALDLL, "alGetIntegerv");
if (lpOALFnTable->alGetIntegerv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetIntegerv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetFloatv = (LPALGETFLOATV)GetProcAddress(g_hOpenALDLL, "alGetFloatv");
if (lpOALFnTable->alGetFloatv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetFloatv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetDoublev = (LPALGETDOUBLEV)GetProcAddress(g_hOpenALDLL, "alGetDoublev");
if (lpOALFnTable->alGetDoublev == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetDoublev' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetString = (LPALGETSTRING)GetProcAddress(g_hOpenALDLL, "alGetString");
if (lpOALFnTable->alGetString == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetString' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetError = (LPALGETERROR)GetProcAddress(g_hOpenALDLL, "alGetError");
if (lpOALFnTable->alGetError == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetError' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsExtensionPresent = (LPALISEXTENSIONPRESENT)GetProcAddress(g_hOpenALDLL, "alIsExtensionPresent");
if (lpOALFnTable->alIsExtensionPresent == NULL)
{
OutputDebugStringA("Failed to retrieve 'alIsExtensionPresent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetProcAddress = (LPALGETPROCADDRESS)GetProcAddress(g_hOpenALDLL, "alGetProcAddress");
if (lpOALFnTable->alGetProcAddress == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetProcAddress' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetEnumValue = (LPALGETENUMVALUE)GetProcAddress(g_hOpenALDLL, "alGetEnumValue");
if (lpOALFnTable->alGetEnumValue == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetEnumValue' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListeneri = (LPALLISTENERI)GetProcAddress(g_hOpenALDLL, "alListeneri");
if (lpOALFnTable->alListeneri == NULL)
{
OutputDebugStringA("Failed to retrieve 'alListeneri' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListenerf = (LPALLISTENERF)GetProcAddress(g_hOpenALDLL, "alListenerf");
if (lpOALFnTable->alListenerf == NULL)
{
OutputDebugStringA("Failed to retrieve 'alListenerf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListener3f = (LPALLISTENER3F)GetProcAddress(g_hOpenALDLL, "alListener3f");
if (lpOALFnTable->alListener3f == NULL)
{
OutputDebugStringA("Failed to retrieve 'alListener3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alListenerfv = (LPALLISTENERFV)GetProcAddress(g_hOpenALDLL, "alListenerfv");
if (lpOALFnTable->alListenerfv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alListenerfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListeneri = (LPALGETLISTENERI)GetProcAddress(g_hOpenALDLL, "alGetListeneri");
if (lpOALFnTable->alGetListeneri == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetListeneri' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListenerf =(LPALGETLISTENERF)GetProcAddress(g_hOpenALDLL, "alGetListenerf");
if (lpOALFnTable->alGetListenerf == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetListenerf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListener3f = (LPALGETLISTENER3F)GetProcAddress(g_hOpenALDLL, "alGetListener3f");
if (lpOALFnTable->alGetListener3f == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetListener3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetListenerfv = (LPALGETLISTENERFV)GetProcAddress(g_hOpenALDLL, "alGetListenerfv");
if (lpOALFnTable->alGetListenerfv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetListenerfv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenSources = (LPALGENSOURCES)GetProcAddress(g_hOpenALDLL, "alGenSources");
if (lpOALFnTable->alGenSources == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGenSources' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteSources = (LPALDELETESOURCES)GetProcAddress(g_hOpenALDLL, "alDeleteSources");
if (lpOALFnTable->alDeleteSources == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDeleteSources' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsSource = (LPALISSOURCE)GetProcAddress(g_hOpenALDLL, "alIsSource");
if (lpOALFnTable->alIsSource == NULL)
{
OutputDebugStringA("Failed to retrieve 'alIsSource' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcei = (LPALSOURCEI)GetProcAddress(g_hOpenALDLL, "alSourcei");
if (lpOALFnTable->alSourcei == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourcei' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcef = (LPALSOURCEF)GetProcAddress(g_hOpenALDLL, "alSourcef");
if (lpOALFnTable->alSourcef == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourcef' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSource3f = (LPALSOURCE3F)GetProcAddress(g_hOpenALDLL, "alSource3f");
if (lpOALFnTable->alSource3f == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSource3f' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcefv = (LPALSOURCEFV)GetProcAddress(g_hOpenALDLL, "alSourcefv");
if (lpOALFnTable->alSourcefv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourcefv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcei = (LPALGETSOURCEI)GetProcAddress(g_hOpenALDLL, "alGetSourcei");
if (lpOALFnTable->alGetSourcei == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetSourcei' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcef = (LPALGETSOURCEF)GetProcAddress(g_hOpenALDLL, "alGetSourcef");
if (lpOALFnTable->alGetSourcef == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetSourcef' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetSourcefv = (LPALGETSOURCEFV)GetProcAddress(g_hOpenALDLL, "alGetSourcefv");
if (lpOALFnTable->alGetSourcefv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetSourcefv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePlayv = (LPALSOURCEPLAYV)GetProcAddress(g_hOpenALDLL, "alSourcePlayv");
if (lpOALFnTable->alSourcePlayv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourcePlayv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceStopv = (LPALSOURCESTOPV)GetProcAddress(g_hOpenALDLL, "alSourceStopv");
if (lpOALFnTable->alSourceStopv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourceStopv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePlay = (LPALSOURCEPLAY)GetProcAddress(g_hOpenALDLL, "alSourcePlay");
if (lpOALFnTable->alSourcePlay == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourcePlay' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourcePause = (LPALSOURCEPAUSE)GetProcAddress(g_hOpenALDLL, "alSourcePause");
if (lpOALFnTable->alSourcePause == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourcePause' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceStop = (LPALSOURCESTOP)GetProcAddress(g_hOpenALDLL, "alSourceStop");
if (lpOALFnTable->alSourceStop == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourceStop' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceRewind = (LPALSOURCEREWIND)GetProcAddress(g_hOpenALDLL, "alSourceRewind");
if (lpOALFnTable->alSourceRewind == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourceRewind' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGenBuffers = (LPALGENBUFFERS)GetProcAddress(g_hOpenALDLL, "alGenBuffers");
if (lpOALFnTable->alGenBuffers == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGenBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteBuffers = (LPALDELETEBUFFERS)GetProcAddress(g_hOpenALDLL, "alDeleteBuffers");
if (lpOALFnTable->alDeleteBuffers == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDeleteBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alIsBuffer = (LPALISBUFFER)GetProcAddress(g_hOpenALDLL, "alIsBuffer");
if (lpOALFnTable->alIsBuffer == NULL)
{
OutputDebugStringA("Failed to retrieve 'alIsBuffer' function address\n");
return AL_FALSE;
}
lpOALFnTable->alBufferData = (LPALBUFFERDATA)GetProcAddress(g_hOpenALDLL, "alBufferData");
if (lpOALFnTable->alBufferData == NULL)
{
OutputDebugStringA("Failed to retrieve 'alBufferData' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBufferi = (LPALGETBUFFERI)GetProcAddress(g_hOpenALDLL, "alGetBufferi");
if (lpOALFnTable->alGetBufferi == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetBufferi' function address\n");
return AL_FALSE;
}
lpOALFnTable->alGetBufferf = (LPALGETBUFFERF)GetProcAddress(g_hOpenALDLL, "alGetBufferf");
if (lpOALFnTable->alGetBufferf == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetBufferf' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceQueueBuffers = (LPALSOURCEQUEUEBUFFERS)GetProcAddress(g_hOpenALDLL, "alSourceQueueBuffers");
if (lpOALFnTable->alSourceQueueBuffers == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourceQueueBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alSourceUnqueueBuffers = (LPALSOURCEUNQUEUEBUFFERS)GetProcAddress(g_hOpenALDLL, "alSourceUnqueueBuffers");
if (lpOALFnTable->alSourceUnqueueBuffers == NULL)
{
OutputDebugStringA("Failed to retrieve 'alSourceUnqueueBuffers' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDistanceModel = (LPALDISTANCEMODEL)GetProcAddress(g_hOpenALDLL, "alDistanceModel");
if (lpOALFnTable->alDistanceModel == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDistanceModel' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDopplerFactor = (LPALDOPPLERFACTOR)GetProcAddress(g_hOpenALDLL, "alDopplerFactor");
if (lpOALFnTable->alDopplerFactor == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDopplerFactor' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDopplerVelocity = (LPALDOPPLERVELOCITY)GetProcAddress(g_hOpenALDLL, "alDopplerVelocity");
if (lpOALFnTable->alDopplerVelocity == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDopplerVelocity' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetString = (LPALCGETSTRING)GetProcAddress(g_hOpenALDLL, "alcGetString");
if (lpOALFnTable->alcGetString == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetString' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetIntegerv = (LPALCGETINTEGERV)GetProcAddress(g_hOpenALDLL, "alcGetIntegerv");
if (lpOALFnTable->alcGetIntegerv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetIntegerv' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcOpenDevice = (LPALCOPENDEVICE)GetProcAddress(g_hOpenALDLL, "alcOpenDevice");
if (lpOALFnTable->alcOpenDevice == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcOpenDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcCloseDevice = (LPALCCLOSEDEVICE)GetProcAddress(g_hOpenALDLL, "alcCloseDevice");
if (lpOALFnTable->alcCloseDevice == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcCloseDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcCreateContext = (LPALCCREATECONTEXT)GetProcAddress(g_hOpenALDLL, "alcCreateContext");
if (lpOALFnTable->alcCreateContext == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcCreateContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcMakeContextCurrent = (LPALCMAKECONTEXTCURRENT)GetProcAddress(g_hOpenALDLL, "alcMakeContextCurrent");
if (lpOALFnTable->alcMakeContextCurrent == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcMakeContextCurrent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcProcessContext = (LPALCPROCESSCONTEXT)GetProcAddress(g_hOpenALDLL, "alcProcessContext");
if (lpOALFnTable->alcProcessContext == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcProcessContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetCurrentContext = (LPALCGETCURRENTCONTEXT)GetProcAddress(g_hOpenALDLL, "alcGetCurrentContext");
if (lpOALFnTable->alcGetCurrentContext == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetCurrentContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetContextsDevice = (LPALCGETCONTEXTSDEVICE)GetProcAddress(g_hOpenALDLL, "alcGetContextsDevice");
if (lpOALFnTable->alcGetContextsDevice == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetContextsDevice' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcSuspendContext = (LPALCSUSPENDCONTEXT)GetProcAddress(g_hOpenALDLL, "alcSuspendContext");
if (lpOALFnTable->alcSuspendContext == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcSuspendContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcDestroyContext = (LPALCDESTROYCONTEXT)GetProcAddress(g_hOpenALDLL, "alcDestroyContext");
if (lpOALFnTable->alcDestroyContext == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcDestroyContext' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetError = (LPALCGETERROR)GetProcAddress(g_hOpenALDLL, "alcGetError");
if (lpOALFnTable->alcGetError == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetError' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcIsExtensionPresent = (LPALCISEXTENSIONPRESENT)GetProcAddress(g_hOpenALDLL, "alcIsExtensionPresent");
if (lpOALFnTable->alcIsExtensionPresent == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcIsExtensionPresent' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetProcAddress = (LPALCGETPROCADDRESS)GetProcAddress(g_hOpenALDLL, "alcGetProcAddress");
if (lpOALFnTable->alcGetProcAddress == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetProcAddress' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetEnumValue = (LPALCGETENUMVALUE)GetProcAddress(g_hOpenALDLL, "alcGetEnumValue");
if (lpOALFnTable->alcGetEnumValue == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetEnumValue' function address\n");
return AL_FALSE;
}
#if defined(AL_ALEXT_PROTOTYPES)
lpOALFnTable->alGenEffects = (LPALGENEFFECTS)GetProcAddress(g_hOpenALDLL, "alGenEffects");
if (lpOALFnTable->alGenEffects == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGenEffects' function address\n");
}
lpOALFnTable->alEffecti = (LPALEFFECTI)GetProcAddress(g_hOpenALDLL, "alEffecti");
if (lpOALFnTable->alEffecti == NULL)
{
OutputDebugStringA("Failed to retrieve 'alEffecti' function address\n");
}
lpOALFnTable->alEffectiv = (LPALEFFECTIV)GetProcAddress(g_hOpenALDLL, "alEffectiv");
if (lpOALFnTable->alEffectiv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alEffectiv' function address\n");
}
lpOALFnTable->alEffectf = (LPALEFFECTF)GetProcAddress(g_hOpenALDLL, "alEffectf");
if (lpOALFnTable->alEffectf == NULL)
{
OutputDebugStringA("Failed to retrieve 'alEffectf' function address\n");
}
lpOALFnTable->alEffectfv = (LPALEFFECTFV)GetProcAddress(g_hOpenALDLL, "alEffectfv");
if (lpOALFnTable->alEffectfv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alEffectfv' function address\n");
}
lpOALFnTable->alGetEffecti = (LPALGETEFFECTI)GetProcAddress(g_hOpenALDLL, "alGetEffecti");
if (lpOALFnTable->alGetEffecti == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetEffecti' function address\n");
}
lpOALFnTable->alGetEffectiv = (LPALGETEFFECTIV)GetProcAddress(g_hOpenALDLL, "alGetEffectiv");
if (lpOALFnTable->alGetEffectiv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetEffectiv' function address\n");
}
lpOALFnTable->alGetEffectf = (LPALGETEFFECTF)GetProcAddress(g_hOpenALDLL, "alGetEffectf");
if (lpOALFnTable->alGetEffectf == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetEffectf' function address\n");
}
lpOALFnTable->alGetEffectfv = (LPALGETEFFECTFV)GetProcAddress(g_hOpenALDLL, "alGetEffectfv");
if (lpOALFnTable->alGetEffectfv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetEffectfv' function address\n");
}
lpOALFnTable->alDeleteEffects = (LPALDELETEEFFECTS)GetProcAddress(g_hOpenALDLL, "alDeleteEffects");
if (lpOALFnTable->alDeleteEffects == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDeleteEffects' function address\n");
}
lpOALFnTable->alIsEffect = (LPALISEFFECT)GetProcAddress(g_hOpenALDLL, "alIsEffect");
if (lpOALFnTable->alIsEffect == NULL)
{
OutputDebugStringA("Failed to retrieve 'alIsEffect' function address\n");
}
lpOALFnTable->alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotf");
if (lpOALFnTable->alAuxiliaryEffectSlotf == NULL)
{
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotf' function address\n");
}
lpOALFnTable->alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotfv");
if (lpOALFnTable->alAuxiliaryEffectSlotfv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotfv' function address\n");
}
lpOALFnTable->alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSloti");
if (lpOALFnTable->alAuxiliaryEffectSloti == NULL)
{
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSloti' function address\n");
}
lpOALFnTable->alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotiv");
if (lpOALFnTable->alAuxiliaryEffectSlotiv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotiv' function address\n");
}
lpOALFnTable->alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)GetProcAddress(g_hOpenALDLL, "alIsAuxiliaryEffectSlot");
if (lpOALFnTable->alIsAuxiliaryEffectSlot == NULL)
{
OutputDebugStringA("Failed to retrieve 'alIsAuxiliaryEffectSlot' function address\n");
}
lpOALFnTable->alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)GetProcAddress(g_hOpenALDLL, "alGenAuxiliaryEffectSlots");
if (lpOALFnTable->alGenAuxiliaryEffectSlots == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGenAuxiliaryEffectSlots' function address\n");
}
lpOALFnTable->alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)GetProcAddress(g_hOpenALDLL, "alDeleteAuxiliaryEffectSlots");
if (lpOALFnTable->alDeleteAuxiliaryEffectSlots == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDeleteAuxiliaryEffectSlots' function address\n");
}
lpOALFnTable->alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotf");
if (lpOALFnTable->alGetAuxiliaryEffectSlotf == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotf' function address\n");
}
lpOALFnTable->alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotfv");
if (lpOALFnTable->alGetAuxiliaryEffectSlotfv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotfv' function address\n");
}
lpOALFnTable->alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSloti");
if (lpOALFnTable->alGetAuxiliaryEffectSloti == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSloti' function address\n");
}
lpOALFnTable->alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotiv");
if (lpOALFnTable->alGetAuxiliaryEffectSlotiv == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotiv' function address\n");
}
lpOALFnTable->alSource3i = (LPALSOURCE3I)GetProcAddress(g_hOpenALDLL, "alSource3i");
lpOALFnTable->alGenFilters = (LPALGENFILTERS)GetProcAddress(g_hOpenALDLL, "alGenFilters");
if (lpOALFnTable->alGenFilters == NULL)
{
OutputDebugStringA("Failed to retrieve 'alGenFilters' function address\n");
return AL_FALSE;
}
lpOALFnTable->alDeleteFilters = (LPALDELETEFILTERS)GetProcAddress(g_hOpenALDLL, "alDeleteFilters");
if (lpOALFnTable->alGenFilters == NULL)
{
OutputDebugStringA("Failed to retrieve 'alDeleteFilters' function address\n");
return AL_FALSE;
}
lpOALFnTable->alFilteri = (LPALFILTERI)GetProcAddress(g_hOpenALDLL, "alFilteri");
if (lpOALFnTable->alGenFilters == NULL)
{
OutputDebugStringA("Failed to retrieve 'alFilteri' function address\n");
return AL_FALSE;
}
lpOALFnTable->alcGetStringiSOFT = (LPALCGETSTRINGISOFT)GetProcAddress(g_hOpenALDLL, "alcGetStringiSOFT");
if (lpOALFnTable->alcGetStringiSOFT == NULL)
{
OutputDebugStringA("Failed to retrieve 'alcGetStringiSOFT' function address\n");
return AL_FALSE;
}
#endif
return AL_TRUE;
}
ALvoid UnloadOAL10Library()
{
// Unload the dll
if (g_hOpenALDLL)
{
FreeLibrary(g_hOpenALDLL);
g_hOpenALDLL = NULL;
}
}

View file

@ -85,6 +85,7 @@ SFXAmbience::ChangeSignal SFXAmbience::smChangeSignal;
SFXAmbience::SFXAmbience()
: mDopplerFactor( 0.5f ),
mRolloffFactor( 1.f ),
mSpeedOfSound(343.3f),
mEnvironment( NULL )
{
dMemset( mState, 0, sizeof( mState ) );
@ -112,6 +113,10 @@ void SFXAmbience::initPersistFields()
"The factor to apply to the doppler affect in this space.\n"
"Defaults to 0.5.\n\n"
"@ref SFXSource_doppler" );
addFieldV("speedOfSound", TypeRangedF32, Offset(mSpeedOfSound, SFXAmbience), &CommonValidators::PositiveFloat,
"The speed of sound in this space.\n"
"Defaults to 343.3.\n\n"
"@ref SFXSource_speedofsound");
addField( "states", TypeSFXStateName, Offset( mState, SFXAmbience ),
MaxStates,
"States to activate when the ambient zone is entered.\n"
@ -177,6 +182,7 @@ void SFXAmbience::packData( BitStream* stream )
stream->write( mRolloffFactor );
stream->write( mDopplerFactor );
stream->write(mSpeedOfSound);
for( U32 i = 0; i < MaxStates; ++ i )
sfxWrite( stream, mState[ i ] );
@ -193,6 +199,7 @@ void SFXAmbience::unpackData( BitStream* stream )
stream->read( &mRolloffFactor );
stream->read( &mDopplerFactor );
stream->read(&mSpeedOfSound);
for( U32 i = 0; i < MaxStates; ++ i )
sfxRead( stream, &mState[ i ] );

View file

@ -61,6 +61,9 @@ class SFXAmbience : public SimDataBlock
/// Doppler shift factor for this space.
F32 mDopplerFactor;
/// Speed of sound for this space.
F32 mSpeedOfSound;
/// Rolloff factor for this space. Only applies to logarithmic distance model.
F32 mRolloffFactor;
@ -90,6 +93,8 @@ class SFXAmbience : public SimDataBlock
/// Return the doppler shift factor to apply in this space.
F32 getDopplerFactor() const { return mDopplerFactor; }
F32 getSpeedOfSound() const { return mSpeedOfSound; }
/// Return the reverb environment of the ambient space.
SFXEnvironment* getEnvironment() const { return mEnvironment; }

View file

@ -24,25 +24,25 @@
#define _SFXCOMMON_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#include "platform/platform.h"
#endif
#ifndef _MMATHFN_H_
#include "math/mMathFn.h"
#include "math/mMathFn.h"
#endif
#ifndef _MRANDOM_H_
#include "math/mRandom.h"
#include "math/mRandom.h"
#endif
#ifndef _MMATRIX_H_
#include "math/mMatrix.h"
#include "math/mMatrix.h"
#endif
#ifndef _MPOINT3_H_
#include "math/mPoint3.h"
#include "math/mPoint3.h"
#endif
#ifndef _TYPETRAITS_H_
#include "platform/typetraits.h"
#include "platform/typetraits.h"
#endif
#ifndef _DYNAMIC_CONSOLETYPES_H_
#include "console/dynamicTypes.h"
#include "console/dynamicTypes.h"
#endif
@ -51,13 +51,37 @@ class SFXEnvironment;
class SFXPlayList;
//-----------------------------------------------------------------------------
// SFXProviderType.
//-----------------------------------------------------------------------------
enum SFXProviderType
{
OpenAL,
XAudio,
DirectSound,
NullProvider,
SFXProviderType_Count
};
DefineEnumType(SFXProviderType);
//-----------------------------------------------------------------------------
// SFXDeviceType.
//-----------------------------------------------------------------------------
enum SFXDeviceType
{
Output,
Input,
SFXDeviceType_Count
};
DefineEnumType(SFXDeviceType);
//-----------------------------------------------------------------------------
// SFXStatus.
//-----------------------------------------------------------------------------
/// The sound playback state.
enum SFXStatus
enum SFXStatus
{
/// Initial state; no operation yet performed on sound.
SFXStatusNull,
@ -83,23 +107,23 @@ enum SFXStatus
SFXStatusTransition,
};
DefineEnumType( SFXStatus );
DefineEnumType(SFXStatus);
inline const char* SFXStatusToString( SFXStatus status )
inline const char* SFXStatusToString(SFXStatus status)
{
switch ( status )
switch (status)
{
case SFXStatusPlaying: return "playing";
case SFXStatusStopped: return "stopped";
case SFXStatusPaused: return "paused";
case SFXStatusBlocked: return "blocked";
case SFXStatusTransition: return "transition";
case SFXStatusNull:
default: ;
case SFXStatusPlaying: return "playing";
case SFXStatusStopped: return "stopped";
case SFXStatusPaused: return "paused";
case SFXStatusBlocked: return "blocked";
case SFXStatusTransition: return "transition";
case SFXStatusNull:
default:;
}
return "null";
}
@ -135,12 +159,12 @@ enum SFXChannel
SFXChannelUser1,
SFXChannelUser2,
SFXChannelUser3,
/// Total number of animatable channels.
SFX_NUM_CHANNELS
};
DefineEnumType( SFXChannel );
DefineEnumType(SFXChannel);
//-----------------------------------------------------------------------------
@ -156,7 +180,7 @@ enum SFXDistanceModel
SFXDistanceModelExponent, /// exponential falloff for distance attenuation.
};
DefineEnumType( SFXDistanceModel );
DefineEnumType(SFXDistanceModel);
/// Compute the distance attenuation based on the given distance model.
///
@ -167,46 +191,52 @@ DefineEnumType( SFXDistanceModel );
/// @param rolloffFactor Rolloff curve scale factor.
///
/// @return The attenuated volume.
inline F32 SFXDistanceAttenuation( SFXDistanceModel model, F32 minDistance, F32 maxDistance, F32 distance, F32 volume, F32 rolloffFactor )
inline F32 SFXDistanceAttenuation(SFXDistanceModel model, F32 minDistance, F32 maxDistance, F32 distance, F32 volume, F32 rolloffFactor)
{
F32 gain = 1.0f;
switch( model )
switch (model)
{
case SFXDistanceModelLinear:
distance = getMax( distance, minDistance );
distance = getMin( distance, maxDistance );
gain = ( 1 - ( distance - minDistance ) / ( maxDistance - minDistance ) );
break;
case SFXDistanceModelLogarithmic:
distance = getMax( distance, minDistance );
distance = getMin( distance, maxDistance );
gain = minDistance / ( minDistance + rolloffFactor * ( distance - minDistance ) );
break;
case SFXDistanceModelLinear:
///create exponential distance model
case SFXDistanceModelExponent:
distance = getMax(distance, minDistance);
distance = getMin(distance, maxDistance);
distance = getMax(distance, minDistance);
distance = getMin(distance, maxDistance);
gain = (1 - rolloffFactor * (distance - minDistance) / (maxDistance - minDistance));
break;
case SFXDistanceModelLogarithmic:
distance = getMax(distance, minDistance);
distance = getMin(distance, maxDistance);
gain = minDistance / (minDistance + rolloffFactor * (distance - minDistance));
break;
///create exponential distance model
case SFXDistanceModelExponent:
distance = getMax(distance, minDistance);
distance = getMin(distance, maxDistance);
gain = pow((distance / minDistance), (-rolloffFactor));
break;
gain = pow((distance / minDistance), (-rolloffFactor));
break;
}
return ( volume * gain );
return (volume * gain);
}
//-----------------------------------------------------------------------------
// SFXFormat.
//-----------------------------------------------------------------------------
enum SFXSampleType {
Sample_Int8,
Sample_Int16,
Sample_Float,
Sample_IMA4,
Sample_MSADPCM
};
/// This class defines the various types of sound data that may be
/// used in the sound system.
@ -216,101 +246,111 @@ inline F32 SFXDistanceAttenuation( SFXDistanceModel model, F32 minDistance, F32
/// channel.
class SFXFormat
{
protected:
protected:
/// The number of sound channels in the data.
U8 mChannels;
/// The number of sound channels in the data.
U8 mChannels;
/// The number of bits per sound sample.
U8 mBitsPerSample;
/// The number of bits per sound sample.
U8 mBitsPerSample;
/// The frequency in samples per second.
U32 mSamplesPerSecond;
/// The frequency in samples per second.
U32 mSamplesPerSecond;
public:
SFXSampleType mSampleType;
public:
SFXFormat( U8 channels = 0,
U8 bitsPerSample = 0,
U32 samplesPerSecond = 0 )
: mChannels( channels ),
mBitsPerSample( bitsPerSample ),
mSamplesPerSecond( samplesPerSecond )
{}
SFXFormat(U8 channels = 0,
U8 bitsPerSample = 0,
U32 samplesPerSecond = 0)
: mChannels(channels),
mBitsPerSample(bitsPerSample),
mSamplesPerSecond(samplesPerSecond),
mSampleType(SFXSampleType::Sample_Int16)
{
}
/// Copy constructor.
SFXFormat( const SFXFormat &format )
: mChannels( format.mChannels ),
mBitsPerSample( format.mBitsPerSample ),
mSamplesPerSecond( format.mSamplesPerSecond )
{}
/// Copy constructor.
SFXFormat(const SFXFormat& format)
: mChannels(format.mChannels),
mBitsPerSample(format.mBitsPerSample),
mSamplesPerSecond(format.mSamplesPerSecond),
mSampleType(format.mSampleType)
{
}
public:
public:
/// Sets the format.
void set( U8 channels,
U8 bitsPerSample,
U32 samplesPerSecond )
{
mChannels = channels;
mBitsPerSample = bitsPerSample;
mSamplesPerSecond = samplesPerSecond;
}
/// Sets the format.
void set(U8 channels,
U8 bitsPerSample,
U32 samplesPerSecond,
SFXSampleType sampleType = Sample_Int16)
{
mChannels = channels;
mBitsPerSample = bitsPerSample;
mSamplesPerSecond = samplesPerSecond;
mSampleType = sampleType;
}
/// Comparision between formats.
bool operator == ( const SFXFormat& format ) const
{
return mChannels == format.mChannels &&
mBitsPerSample == format.mBitsPerSample &&
mSamplesPerSecond == format.mSamplesPerSecond;
}
/// Comparision between formats.
bool operator == (const SFXFormat& format) const
{
return mChannels == format.mChannels &&
mBitsPerSample == format.mBitsPerSample &&
mSamplesPerSecond == format.mSamplesPerSecond &&
mSampleType == format.mSampleType;
}
/// Returns the number of sound channels.
U8 getChannels() const { return mChannels; }
/// Returns the number of sound channels.
U8 getChannels() const { return mChannels; }
/// Returns true if there is a single sound channel.
bool isMono() const { return mChannels == 1; }
/// Returns true if there is a single sound channel.
bool isMono() const { return mChannels == 1; }
/// Is true if there are two sound channels.
bool isStereo() const { return mChannels == 2; }
/// Is true if there are two sound channels.
bool isStereo() const { return mChannels == 2; }
/// Is true if there are more than two sound channels.
bool isMultiChannel() const { return mChannels > 2; }
/// Is true if there are more than two sound channels.
bool isMultiChannel() const { return mChannels > 2; }
///
U32 getSamplesPerSecond() const { return mSamplesPerSecond; }
///
U32 getSamplesPerSecond() const { return mSamplesPerSecond; }
/// The bits of data per channel.
U8 getBitsPerChannel() const { return mBitsPerSample / mChannels; }
/// The bits of data per channel.
U8 getBitsPerChannel() const { return mBitsPerSample / mChannels; }
/// The number of bytes of data per channel.
U8 getBytesPerChannel() const { return getBitsPerChannel() / 8; }
/// The number of bytes of data per channel.
U8 getBytesPerChannel() const { return getBitsPerChannel() / 8; }
/// The number of bits per sound sample.
U8 getBitsPerSample() const { return mBitsPerSample; }
/// The number of bits per sound sample.
U8 getBitsPerSample() const { return mBitsPerSample; }
/// The number of bytes of data per sample.
/// @note Be aware that this comprises all channels.
U8 getBytesPerSample() const { return mBitsPerSample / 8; }
SFXSampleType getSampleType() const { return mSampleType; }
/// Returns the duration from the sample count.
U32 getDuration( U32 samples ) const
{
// Use 64bit types to avoid overflow during division.
return ( (U64)samples * (U64)1000 ) / (U64)mSamplesPerSecond;
}
/// The number of bytes of data per sample.
/// @note Be aware that this comprises all channels.
U8 getBytesPerSample() const { return mBitsPerSample / 8; }
///
U32 getSampleCount( U32 ms ) const
{
return U64( mSamplesPerSecond ) * U64( ms ) / U64( 1000 );
}
/// Returns the duration from the sample count.
U32 getDuration(U32 samples) const
{
// Use 64bit types to avoid overflow during division.
return ((U64)samples * (U64)1000) / (U64)mSamplesPerSecond;
}
/// Returns the data length in bytes.
U32 getDataLength( U32 ms ) const
{
U32 bytes = ( ( (U64)ms * (U64)mSamplesPerSecond ) * (U64)getBytesPerSample() ) / (U64)1000;
return bytes;
}
///
U32 getSampleCount(U32 ms) const
{
return U64(mSamplesPerSecond) * U64(ms) / U64(1000);
}
/// Returns the data length in bytes.
U32 getDataLength(U32 ms) const
{
U32 bytes = (((U64)ms * (U64)mSamplesPerSecond) * (U64)getBytesPerSample()) / (U64)1000;
return bytes;
}
};
@ -363,8 +403,8 @@ public:
flGain = 0.0f;
flGainHF = 0.0f;
flGainLF = 0.0000f;
flDecayTime = 0.0f;
flDecayHFRatio = 0.0f;
flDecayTime = 0.1f;
flDecayHFRatio = 0.1f;
flDecayLFRatio = 0.0f;
flReflectionsGain = 0.0f;
flReflectionsDelay = 0.0f;
@ -372,15 +412,17 @@ public:
flLateReverbGain = 0.0f;
flLateReverbDelay = 0.0f;
dMemset(flLateReverbPan, 0, sizeof(flLateReverbPan));
flEchoTime = 0.0f;
flEchoTime = 0.075f;
flEchoDepth = 0.0f;
flModulationTime = 0.0f;
flModulationTime = 0.04f;
flModulationDepth = 0.0f;
flAirAbsorptionGainHF = 0.0f;
flAirAbsorptionGainHF = 0.892f;
flHFReference = 0.0f;
flLFReference = 0.0f;
flRoomRolloffFactor = 0.0f;
iDecayHFLimit = 0;
validate();
}
void validate()
@ -528,31 +570,33 @@ public:
///
class SFXListenerProperties
{
public:
typedef void Parent;
/// Position and orientation of the listener.
MatrixF mTransform;
///
Point3F mVelocity;
public:
SFXListenerProperties()
: mTransform( true ),
mVelocity( 0.0f, 0.0f, 0.0f ) {}
SFXListenerProperties( const MatrixF& transform, const Point3F& velocity )
: mTransform( transform ),
mVelocity( velocity ) {}
///
const MatrixF& getTransform() const { return mTransform; }
MatrixF& getTransform() { return mTransform; }
///
const Point3F& getVelocity() const { return mVelocity; }
Point3F& getVelocity() { return mVelocity; }
typedef void Parent;
/// Position and orientation of the listener.
MatrixF mTransform;
///
Point3F mVelocity;
SFXListenerProperties()
: mTransform(true),
mVelocity(0.0f, 0.0f, 0.0f) {
}
SFXListenerProperties(const MatrixF& transform, const Point3F& velocity)
: mTransform(transform),
mVelocity(velocity) {
}
///
const MatrixF& getTransform() const { return mTransform; }
MatrixF& getTransform() { return mTransform; }
///
const Point3F& getVelocity() const { return mVelocity; }
Point3F& getVelocity() { return mVelocity; }
};
@ -564,29 +608,30 @@ class SFXListenerProperties
///
class SFXMaterialProperties
{
public:
typedef void Parent;
///
bool mDoubleSided;
///
F32 mDirectOcclusion;
///
F32 mReverbOcclusion;
SFXMaterialProperties()
: mDoubleSided( false ),
mDirectOcclusion( 0.5f ),
mReverbOcclusion( 0.5f ) {}
void validate()
{
mDirectOcclusion = mClampF( mDirectOcclusion, 0.0f, 1.0f );
mReverbOcclusion = mClampF( mReverbOcclusion, 0.0f, 1.0f );
}
public:
typedef void Parent;
///
bool mDoubleSided;
///
F32 mDirectOcclusion;
///
F32 mReverbOcclusion;
SFXMaterialProperties()
: mDoubleSided(false),
mDirectOcclusion(0.5f),
mReverbOcclusion(0.5f) {
}
void validate()
{
mDirectOcclusion = mClampF(mDirectOcclusion, 0.0f, 1.0f);
mReverbOcclusion = mClampF(mReverbOcclusion, 0.0f, 1.0f);
}
};
@ -600,28 +645,28 @@ template< S32 NUM_VALUES >
struct SFXVariantFloat
{
/// Base value.
F32 mValue[ NUM_VALUES ];
F32 mValue[NUM_VALUES];
/// Variance of value. Final value will be
///
/// mClampF( randF( mValue + mVariance[ 0 ], mValue + mVariance[ 1 ] ), min, max )
///
/// with min and max being dependent on the context of the value.
F32 mVariance[ NUM_VALUES ][ 2 ];
F32 getValue( U32 index = 0, F32 min = TypeTraits< F32 >::MIN, F32 max = TypeTraits< F32 >::MAX ) const
F32 mVariance[NUM_VALUES][2];
F32 getValue(U32 index = 0, F32 min = TypeTraits< F32 >::MIN, F32 max = TypeTraits< F32 >::MAX) const
{
AssertFatal( index < NUM_VALUES, "SFXVariantFloat::getValue() - index out of range!" );
return mClampF( gRandGen.randF( mValue[ index ] + mVariance[ index ][ 0 ],
mValue[ index ] + mVariance[ index ][ 1 ] ),
min, max );
AssertFatal(index < NUM_VALUES, "SFXVariantFloat::getValue() - index out of range!");
return mClampF(gRandGen.randF(mValue[index] + mVariance[index][0],
mValue[index] + mVariance[index][1]),
min, max);
}
void validate()
{
for( U32 i = 0; i < NUM_VALUES; ++ i )
mVariance[ i ][ 0 ] = getMin( mVariance[ i ][ 0 ], mVariance[ i ][ 1 ] );
for (U32 i = 0; i < NUM_VALUES; ++i)
mVariance[i][0] = getMin(mVariance[i][0], mVariance[i][1]);
}
};

View file

@ -173,7 +173,6 @@ SFXDescription::SFXDescription( const SFXDescription& desc )
mStreamPacketSize( desc.mStreamPacketSize ),
mUseReverb( desc.mUseReverb ),
mStreamReadAhead( desc.mStreamReadAhead ),
mReverb( desc.mReverb ),
mScatterDistance( desc.mScatterDistance ),
mPriority( desc.mPriority )
{
@ -206,7 +205,6 @@ SFXDescription::SFXDescription(const SFXDescription& other, bool temp_clone)
mStreamPacketSize( other.mStreamPacketSize ),
mStreamReadAhead( other.mStreamReadAhead ),
mUseReverb( other.mUseReverb ),
mReverb( other.mReverb ),
mPriority( other.mPriority ),
mScatterDistance( other.mScatterDistance )
{
@ -396,48 +394,6 @@ void SFXDescription::initPersistFields()
"a custom reverb setup can be defined using the \"Reverb\" properties that will then be assigned "
"to sounds playing with the description.\n\n"
"@ref SFX_reverb");
addFieldV("reverbDensity", TypeRangedF32, Offset(mReverb.flDensity, SFXDescription), &CommonValidators::PositiveFloat,
"Density of reverb environment.");
addFieldV("reverbDiffusion", TypeRangedF32, Offset(mReverb.flDiffusion, SFXDescription), &CommonValidators::PositiveFloat,
"Environment diffusion.");
addFieldV("reverbGain", TypeRangedF32, Offset(mReverb.flGain, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb Gain Level.");
addFieldV("reverbGainHF", TypeRangedF32, Offset(mReverb.flGainHF, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb Gain to high frequencies");
addFieldV("reverbGainLF", TypeRangedF32, Offset(mReverb.flGainLF, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb Gain to high frequencies");
addFieldV("reverbDecayTime", TypeRangedF32, Offset(mReverb.flDecayTime, SFXDescription), &CommonValidators::PositiveFloat,
"Decay time for the reverb.");
addFieldV("reverbDecayHFRatio", TypeRangedF32, Offset(mReverb.flDecayHFRatio, SFXDescription), &CommonValidators::PositiveFloat,
"High frequency decay time ratio.");
addFieldV("reverbDecayLFRatio", TypeRangedF32, Offset(mReverb.flDecayLFRatio, SFXDescription), &CommonValidators::PositiveFloat,
"High frequency decay time ratio.");
addFieldV("reflectionsGain", TypeRangedF32, Offset(mReverb.flReflectionsGain, SFXDescription), &CommonValidators::PositiveFloat,
"Reflection Gain.");
addFieldV("reflectionDelay", TypeRangedF32, Offset(mReverb.flReflectionsDelay, SFXDescription), &CommonValidators::PositiveFloat,
"How long to delay reflections.");
addFieldV("lateReverbGain", TypeRangedF32, Offset(mReverb.flLateReverbGain, SFXDescription), &CommonValidators::PositiveFloat,
"Late reverb gain amount.");
addFieldV("lateReverbDelay", TypeRangedF32, Offset(mReverb.flLateReverbDelay, SFXDescription), &CommonValidators::PositiveFloat,
"Late reverb delay time.");
addFieldV("reverbEchoTime", TypeRangedF32, Offset(mReverb.flEchoTime, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb echo time.");
addFieldV("reverbEchoDepth", TypeRangedF32, Offset(mReverb.flEchoDepth, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb echo depth.");
addFieldV("reverbModTime", TypeRangedF32, Offset(mReverb.flModulationTime, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb Modulation time.");
addFieldV("reverbModDepth", TypeRangedF32, Offset(mReverb.flModulationDepth, SFXDescription), &CommonValidators::NormalizedFloat,
"Reverb Modulation Depth.");
addFieldV("airAbsorbtionGainHF", TypeRangedF32, Offset(mReverb.flAirAbsorptionGainHF, SFXDescription), &CommonValidators::PositiveFloat,
"High Frequency air absorbtion");
addFieldV("reverbHFRef", TypeRangedF32, Offset(mReverb.flHFReference, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb High Frequency Reference.");
addFieldV("reverbLFRef", TypeRangedF32, Offset(mReverb.flLFReference, SFXDescription), &CommonValidators::PositiveFloat,
"Reverb Low Frequency Reference.");
addFieldV("roomRolloffFactor", TypeRangedF32, Offset(mReverb.flRoomRolloffFactor, SFXDescription), &CommonValidators::NegDefaultF32,
"Rolloff factor for reverb.");
addFieldV("decayHFLimit", TypeRangedS32, Offset(mReverb.iDecayHFLimit, SFXDescription), &CommonValidators::PositiveInt,
"High Frequency decay limit.");
endGroup("Reverb");
Parent::initPersistFields();
@ -496,10 +452,6 @@ void SFXDescription::validate()
mConeOutsideAngle = mClamp( mConeOutsideAngle, mConeInsideAngle, 360 );
mConeOutsideVolume = mClampF( mConeOutsideVolume, 0, 1 );
if( !mIs3D )
mUseReverb = false;
mReverb.validate();
}
//-----------------------------------------------------------------------------
@ -534,30 +486,6 @@ void SFXDescription::packData( BitStream *stream )
stream->writeFloat( mConeOutsideVolume, 6 );
if( mUseReverb )
{
stream->write(mReverb.flDensity);
stream->write(mReverb.flDiffusion);
stream->write(mReverb.flGain);
stream->write(mReverb.flGainHF);
stream->write(mReverb.flGainLF);
stream->write(mReverb.flDecayTime);
stream->write(mReverb.flDecayHFRatio);
stream->write(mReverb.flDecayLFRatio);
stream->write(mReverb.flReflectionsGain);
stream->write(mReverb.flReflectionsDelay);
stream->write(mReverb.flLateReverbGain);
stream->write(mReverb.flLateReverbDelay);
stream->write(mReverb.flEchoTime);
stream->write(mReverb.flEchoDepth);
stream->write(mReverb.flModulationTime);
stream->write(mReverb.flModulationDepth);
stream->write(mReverb.flAirAbsorptionGainHF);
stream->write(mReverb.flHFReference);
stream->write(mReverb.flLFReference);
stream->write(mReverb.flRoomRolloffFactor);
stream->write(mReverb.iDecayHFLimit);
}
}
stream->write( mFadeInTime );
@ -607,30 +535,6 @@ void SFXDescription::unpackData( BitStream *stream )
mConeOutsideVolume = stream->readFloat( 6 );
if( mUseReverb )
{
stream->read(&mReverb.flDensity);
stream->read(&mReverb.flDiffusion);
stream->read(&mReverb.flGain);
stream->read(&mReverb.flGainHF);
stream->read(&mReverb.flGainLF);
stream->read(&mReverb.flDecayTime);
stream->read(&mReverb.flDecayHFRatio);
stream->read(&mReverb.flDecayLFRatio);
stream->read(&mReverb.flReflectionsGain);
stream->read(&mReverb.flReflectionsDelay);
stream->read(&mReverb.flLateReverbGain);
stream->read(&mReverb.flLateReverbDelay);
stream->read(&mReverb.flEchoTime);
stream->read(&mReverb.flEchoDepth);
stream->read(&mReverb.flModulationTime);
stream->read(&mReverb.flModulationDepth);
stream->read(&mReverb.flAirAbsorptionGainHF);
stream->read(&mReverb.flHFReference);
stream->read(&mReverb.flLFReference);
stream->read(&mReverb.flRoomRolloffFactor);
stream->read(&mReverb.iDecayHFLimit);
}
}
stream->read( &mFadeInTime );

View file

@ -170,9 +170,6 @@ class SFXDescription : public SimDataBlock
/// The number of streaming packets to read and buffer in advance.
/// Only relevant if "isStreaming" is true.
U32 mStreamReadAhead;
/// Reverb properties for sound playback.
SFXSoundReverbProperties mReverb;
/// Parameters to which sources playing with this description should automatically
/// connect when created.
@ -202,4 +199,4 @@ class SFXDescription : public SimDataBlock
};
#endif // _SFXDESCRIPTION_H_
#endif // _SFXDESCRIPTION_H_

View file

@ -29,20 +29,55 @@
#include "console/consoleTypes.h"
//-----------------------------------------------------------------------------
S32 SFXDevice::smUpdateInterval = SFXInternal::DEFAULT_UPDATE_INTERVAL;
S32 SFXDevice::smDeviceFrequency = 44100;
S32 SFXDevice::smMaxSendsPerSource = 4;
S32 SFXDevice::smMaxEffectSlots = 4;
S32 SFXDevice::smDeviceHRTFProfile = -1;
S8 SFXDevice::smDeviceBitrate = 16;
bool SFXDevice::smDeviceHRTF = false;
SFXDevice::SFXDevice( const String& name, SFXProvider* provider, bool useHardware, S32 maxBuffers )
: mName( name ),
mProvider( provider ),
mUseHardware( useHardware ),
mMaxBuffers( maxBuffers ),
mCaps( 0 ),
mStatNumBuffers( 0 ),
mStatNumVoices( 0 ),
mStatNumBufferBytes( 0 )
void SFXDevice::initConsole()
{
AssertFatal( provider, "We must have a provider pointer on device creation!" );
// Add global preferences for sfx devices.
Con::addVariable("$pref::SFX::bitrate", TypeS8, &smDeviceBitrate,
"The devices bitrate.\n"
"@ingroup SFX\n");
Con::addVariable("$pref::SFX::frequency", TypeS32, &smDeviceFrequency,
"The devices frequency.\n"
"@ingroup SFX\n");
Con::addVariable("$pref::SFX::useHRTF", TypeBool, &smDeviceHRTF,
"The device uses hrtf.\n"
"@ingroup SFX\n");
Con::addVariable("$pref::SFX::hrtfProfile", TypeS32, &smDeviceHRTFProfile,
"Index of the HRTF profile to use. -1 = driver default. "
"Use sfxGetHRTFProfileCount/sfxGetHRTFProfileName to enumerate available profiles.\n"
"@ingroup SFX\n");
Con::addVariable("$pref::SFX::updateInterval", TypeS32, &smUpdateInterval,
"The update interval.\n"
"@ingroup SFX\n");
Con::addVariable("$pref::SFX::maxSendsPerSource", TypeS32, &smMaxSendsPerSource,
"The maximum number sends allowed per source.\n"
"@ingroup SFX\n");
Con::addVariable("$pref::SFX::maxEffectSlots", TypeS32, &smMaxEffectSlots,
"The maximum number of effect slots supported by this device.\n"
"@ingroup SFX\n");
}
SFXDevice::SFXDevice()
: mStatNumBuffers( 0 ),
mStatNumVoices( 0 ),
mStatNumBufferBytes( 0 ),
mMaxBuffers(16),
mUseHardware(false),
mCaps(0)
{
VECTOR_SET_ASSOCIATION( mBuffers );
VECTOR_SET_ASSOCIATION( mVoices );
@ -54,8 +89,6 @@ SFXDevice::SFXDevice( const String& name, SFXProvider* provider, bool useHardwar
Con::addVariable( "SFX::Device::numBufferBytes", TypeS32, &mStatNumBufferBytes );
}
//-----------------------------------------------------------------------------
SFXDevice::~SFXDevice()
{
Con::removeVariable( "SFX::Device::numBuffers" );
@ -78,13 +111,13 @@ void SFXDevice::_releaseAllResources()
ThreadSafeRef< SFXUpdateThread > sfxThread = UPDATE_THREAD();
if( sfxThread != NULL )
{
gUpdateThread = NULL; // Kill the global reference.
sfxThread->stop();
sfxThread->triggerUpdate();
sfxThread->join();
sfxThread = NULL;
gUpdateThread = NULL; // Kill the global reference.
}
// Clean up voices. Do this before cleaning up buffers so that
@ -92,9 +125,11 @@ void SFXDevice::_releaseAllResources()
// get released properly.
SFXVoice::smVoiceDestroyedSignal.remove( this, &SFXDevice::_removeVoice );
for( VoiceIterator voice = mVoices.begin();
voice != mVoices.end(); voice++ )
( *voice )->destroySelf();
for (VoiceIterator voice = mVoices.begin(); voice != mVoices.end(); voice++)
{
(*voice)->stop();
(*voice)->destroySelf();
}
mVoices.clear();
// Clean up buffers.

View file

@ -23,21 +23,19 @@
#ifndef _SFXDEVICE_H_
#define _SFXDEVICE_H_
#ifndef _SFXPROVIDER_H_
#include "sfx/sfxProvider.h"
#endif
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _SFXCOMMON_H_
#include "sfx/sfxCommon.h"
#endif
#ifndef _THREADSAFEREF_H_
#include "platform/threads/threadSafeRefCount.h"
#endif
class SFXProvider;
class SFXListener;
class SFXBuffer;
class SFXVoice;
@ -46,8 +44,6 @@ class SFXDevice;
class SFXStream;
class SFXDescription;
/// Abstract base class for back-end sound API implementations.
class SFXDevice
{
@ -58,13 +54,43 @@ class SFXDevice
/// Device capability flags.
enum ECaps
{
CAPS_Reverb = BIT( 0 ), ///< Device supports reverb environments.
CAPS_VoiceManagement = BIT( 1 ), ///< Device manages voices on its own; deactivates virtualization code in SFX system.
CAPS_Occlusion = BIT( 2 ), ///< Device has its own sound occlusion handling (SFXOcclusionManager).
CAPS_DSPEffects = BIT( 3 ), ///< Device implements DSP effects (SFXDSPManager).
CAPS_MultiListener = BIT( 4 ), ///< Device supports multiple listeners.
CAPS_Reverb = BIT(0), ///< Device supports reverb environments.
CAPS_EXTReverb = BIT(1), ///< Device supports extended reverb environments.
CAPS_VoiceManagement = BIT(2), ///< Device manages voices on its own; deactivates virtualization code in SFX system.
CAPS_Occlusion = BIT(3), ///< Device has its own sound occlusion handling (SFXOcclusionManager).
CAPS_DSPEffects = BIT(4), ///< Device implements DSP effects (SFXDSPManager).
CAPS_MultiListener = BIT(5), ///< Device supports multiple listeners.
CAPS_HRTF = BIT(6), ///< Device supports HRTF (3D audio positioning).
CAPS_Float32 = BIT(7), ///< Device supports 32-bit float playback.
CAPS_MonoStereo = BIT(8), ///< Device supports mono/stereo output modes.
CAPS_EFX_EQ = BIT(9), ///< Device Supports Equalizer effect
CAPS_EFX_Compressor = BIT(10), ///< Device Supports Compressor effect
CAPS_EFX_Echo = BIT(11), ///< Device Supports Echo effect
CAPS_EFX_Chorus = BIT(12), ///< Device Supports Chorus effect
CAPS_EFX_Distortion = BIT(13), ///< Device Supports Distortion effect
CAPS_EFX_Flanger = BIT(14), ///< Device Supports Flanger effect
CAPS_SourceFilters = BIT(15), ///< Device Supports Per-source send filters (low/high/band pass)
CAPS_SourceSpatialize = BIT(16), ///< Device Supports Explicit per-source spatialize control
CAPS_HotReconnect = BIT(17), ///< Device Supports Device can be reopened without destroying context
CAPS_DeviceClock = BIT(18), ///< Device Supports High precision device clock
CAPS_DisconnectDetect = BIT(19), ///< Device Can detect hardware disconnection
};
static void initConsole();
static S32 smUpdateInterval;
/// The device frequency, used when reading in buffers for the device.
static S32 smDeviceFrequency;
/// The device hrtf profile to use.
static S32 smDeviceHRTFProfile;
/// The device bitrate.
static S8 smDeviceBitrate;
/// Does the device use hrtf
static bool smDeviceHRTF;
/// How many effect slots does this device support.
static S32 smMaxEffectSlots;
/// How many sends can each source have.
static S32 smMaxSendsPerSource;
protected:
typedef Vector< SFXBuffer* > BufferVector;
@ -73,11 +99,6 @@ class SFXDevice
typedef BufferVector::iterator BufferIterator;
typedef VoiceVector::iterator VoiceIterator;
SFXDevice( const String& name, SFXProvider* provider, bool useHardware, S32 maxBuffers );
/// The name of this device.
String mName;
/// The provider which created this device.
SFXProvider* mProvider;
@ -125,11 +146,12 @@ class SFXDevice
void _releaseAllResources();
public:
SFXDevice();
virtual ~SFXDevice();
/// Returns the provider which created this device.
SFXProvider* getProvider() const { return mProvider; }
virtual SFXProvider* getProvider() { return mProvider; }
virtual void setProvider(SFXProvider* provider) { mProvider = provider; }
/// Is the device set to use hardware processing.
bool getUseHardware() const { return mUseHardware; }
@ -138,7 +160,7 @@ public:
S32 getMaxBuffers() const { return mMaxBuffers; }
/// Returns the name of this device.
const String& getName() const { return mName; }
const String& getName() const { return mProvider->getName(); }
/// Return the device capability flags.
U32 getCaps() const { return mCaps; }
@ -174,6 +196,9 @@ public:
/// Set the scale factor to use for doppler effects on 3D sounds.
virtual void setDopplerFactor( F32 factor ) {}
/// Set the speed of sound for the device.
virtual void setSpeedOfSound(F32 speedOfSound) {}
/// Set the rolloff scale factor for distance attenuation of 3D sounds.
virtual void setRolloffFactor( F32 factor ) {}
@ -183,6 +208,9 @@ public:
/// Set the global reverb environment.
virtual void setReverb( const SFXReverbProperties& reverb ) {}
virtual bool isDeviceConnected() { return true; }
virtual bool reconnectDevice(U32 provider) { return false; }
/// Reset the global reverb environment to its default.
virtual void resetReverb() {}

View file

@ -1,95 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "core/strings/stringFunctions.h"
#include "sfx/sfxProvider.h"
SFXProvider* SFXProvider::smProviders = NULL;
Vector<SFXProvider*> SFXProvider::sAllProviders( __FILE__, __LINE__ );
SFXProvider* SFXProvider::findProvider( String providerName )
{
if( providerName.isEmpty() )
return NULL;
SFXProvider* curr = smProviders;
for ( ; curr != NULL; curr = curr->mNextProvider )
{
if( curr->getName().equal( providerName, String::NoCase ) )
return curr;
}
return NULL;
}
void SFXProvider::regProvider( SFXProvider* provider )
{
AssertFatal( provider, "Got null provider!" );
AssertFatal( findProvider( provider->getName() ) == NULL, "Can't register provider twice!" );
AssertFatal( provider->mNextProvider == NULL, "Can't register provider twice!" );
SFXProvider* oldHead = smProviders;
smProviders = provider;
provider->mNextProvider = oldHead;
}
SFXProvider::SFXProvider( const String& name )
: mNextProvider( NULL ),
mName( name )
{
VECTOR_SET_ASSOCIATION( mDeviceInfo );
sAllProviders.push_back( this );
}
void SFXProvider::initializeAllProviders()
{
for (U32 i = 0; i < sAllProviders.size(); i++)
sAllProviders[i]->init();
}
SFXProvider::~SFXProvider()
{
SFXDeviceInfoVector::iterator iter = mDeviceInfo.begin();
for ( ; iter != mDeviceInfo.end(); iter++ )
delete *iter;
}
SFXDeviceInfo* SFXProvider::_findDeviceInfo( const String& deviceName )
{
SFXDeviceInfoVector::iterator iter = mDeviceInfo.begin();
for ( ; iter != mDeviceInfo.end(); iter++ )
{
if( deviceName.equal( ( *iter )->name, String::NoCase ) )
return *iter;
}
// If not found and deviceName is empty,
// return first (default) device.
if( deviceName.isEmpty() && mDeviceInfo.size() > 0 )
return mDeviceInfo[ 0 ];
return NULL;
}

View file

@ -23,102 +23,44 @@
#ifndef _SFXPROVIDER_H_
#define _SFXPROVIDER_H_
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#ifndef _SFXCOMMON_H_
#include "sfx/sfxCommon.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _UTIL_DELEGATE_H_
#include "core/util/delegate.h"
#endif
class SFXDevice;
struct SFXDeviceInfo
struct SFXProvider
{
String driver;
String internalName;
String name;
bool hasHardware = false;
S32 maxBuffers =0;
public:
typedef Delegate<SFXDevice* (U32 providerIndex)> CreateProviderInstanceDelegate;
virtual ~SFXDeviceInfo() {}
};
String mName;
bool mHasHardware;
SFXProviderType mType;
SFXDeviceType mDeviceType;
U32 mIndex;
bool mDefault;
CreateProviderInstanceDelegate mCreateDeviceInstanceDelegate;
typedef Vector<SFXDeviceInfo*> SFXDeviceInfoVector;
class SFXProvider
{
friend class SFXSystem;
private:
/// The head of the linked list of avalible providers.
static SFXProvider* smProviders;
/// The next provider in the linked list of available providers.
SFXProvider* mNextProvider;
/// The provider name which is passed by the concrete provider
/// class to the SFXProvider constructor.
String mName;
static Vector<SFXProvider*> sAllProviders;
protected:
/// The array of avaIlable devices from this provider. The
/// concrete provider class will fill this on construction.
SFXDeviceInfoVector mDeviceInfo;
/// This registers the provider to the available provider list. It should be called
/// for providers that are properly initialized and available for device enumeration and creation.
/// the add and registration process is 2 steps to avoid issues when TGEA is used as a shared library (specifically on Windows)
static void regProvider( SFXProvider* provider );
virtual void init() = 0;
SFXProvider( const String& name );
~SFXProvider();
/// Look up the SFXDeviceInfo for the given device in mDeviceInfo.
/// Return default device (first in list) if no other device matches (or null if device list is empty).
SFXDeviceInfo* _findDeviceInfo( const String& deviceName );
/// This is called from SFXSystem to create a new device. Must be implemented
/// by all contrete provider classes.
///
/// @param deviceName The case sensitive name of the device or NULL to create the
// default device.
/// @param useHardware Toggles the use of hardware processing when available.
/// @param maxBuffers The maximum buffers for this device to use or -1
/// for the device to pick a reasonable default for that device.
///
/// @return Returns the created device or NULL for failure.
///
virtual SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers ) = 0;
public:
/// Returns a specific provider by searching the provider list
/// for the first provider with the case sensitive name.
static SFXProvider* findProvider( String providerName );
/// Returns the first provider in the provider list. Use
/// getNextProvider() to iterate over list.
static SFXProvider* getFirstProvider() { return smProviders; }
/// Returns the next provider in the provider list or NULL
/// when the end of the list is reached.
SFXProvider* getNextProvider() const { return mNextProvider; }
/// The case sensitive name of this provider.
const String& getName() const { return mName; }
/// Returns a read only vector with device information for
/// all creatable devices available from this provider.
const SFXDeviceInfoVector& getDeviceInfo() const { return mDeviceInfo; }
static void initializeAllProviders();
const char* getName() const { return mName; }
SFXProvider()
{
mName = String::EmptyString;
mHasHardware = false;
mType = NullProvider;
mIndex = 0;
mDefault = false;
mDeviceType = Output;
}
};

View file

@ -261,11 +261,6 @@ bool SFXSound::_allocVoice( SFXDevice* device )
_setCone( mConeInsideAngle, mConeOutsideAngle, mConeOutsideVolume );
}
// Set reverb, if enabled.
if( mDescription->mUseReverb )
mVoice->setReverb( mDescription->mReverb );
// Update the duration... it shouldn't have changed, but
// its probably better that we're accurate if it did.
mDuration = mBuffer->getDuration();
@ -395,8 +390,10 @@ void SFXSound::_play()
{
Parent::_play();
if( mVoice )
mVoice->play( isLooping() );
if (mVoice)
{
mVoice->play(isLooping());
}
else
{
// To ensure the fastest possible reaction
@ -447,6 +444,11 @@ void SFXSound::_updateStatus()
if( mVoice )
{
// properties can change while a voice is playing, respect that.
if (getSourceGroup())
mVoice->setReverb(getSourceGroup()->getDescription()->mUseReverb);
SFXStatus voiceStatus = mVoice->getStatus();
// Filter out SFXStatusBlocked.

View file

@ -131,14 +131,30 @@ void SFXSoundscapeManager::update()
SFXAmbience* ambience = mStack[ reverbIndex ]->getAmbience();
AssertFatal( ambience->getEnvironment(), "SFXSoundscapeManager::update - Reverb lookup return ambience without reverb!" );
SFX->setRolloffFactor( ambience->getRolloffFactor() );
SFX->setDopplerFactor( ambience->getDopplerFactor() );
SFX->setReverb( ambience->getEnvironment()->getReverb() );
SFX->setRolloffFactor(ambience->getRolloffFactor());
SFX->setDopplerFactor(ambience->getDopplerFactor());
SFX->setSpeedOfSound(ambience->getSpeedOfSound());
if (ambience->getEnvironment())
SFX->setReverb(ambience->getEnvironment()->getReverb());
}
mCurrentReverbIndex = reverbIndex;
}
if (mStack[mStack.size() - 1]->mDirtyBits.test(SFXSoundscape::AmbienceDirty))
{
SFXAmbience* ambience = mStack[mStack.size() - 1]->getAmbience();
SFX->setRolloffFactor(ambience->getRolloffFactor());
SFX->setDopplerFactor(ambience->getDopplerFactor());
SFX->setSpeedOfSound(ambience->getSpeedOfSound());
if (ambience->getEnvironment())
SFX->setReverb(ambience->getEnvironment()->getReverb());
mCurrentReverbIndex = mStack.size() - 1;
mStack[mStack.size() - 1]->mDirtyBits.clear(SFXSoundscape::AmbienceDirty);
}
// Update the active soundscapes.
for( U32 i = 0; i < mStack.size(); ++ i )

View file

@ -42,8 +42,11 @@
#include "platform/platformTimer.h"
#include "core/util/autoPtr.h"
#include "core/module.h"
#include "T3D/sfx/sfx3DWorld.h"
Vector<SFXProvider*> SFXSystem::smProviders(__FILE__, __LINE__);
SFXSystem::RegisterProviderSignal* SFXSystem::smRegisterProviderSignal;
MODULE_BEGIN( SFX )
@ -54,6 +57,8 @@ MODULE_BEGIN( SFX )
MODULE_INIT
{
SFXSystem::init();
if (engineAPI::gUseConsoleInterop)
SFXDevice::initConsole();
}
MODULE_SHUTDOWN
@ -69,6 +74,25 @@ SFXSystem* SFXSystem::smSingleton = NULL;
/// Default SFXAmbience used to reset the global soundscape.
SFXAmbience *sDefaultAmbience;
// Provider type
ImplementEnumType(SFXProviderType,
"The sfx provider.\n"
"@ingroup SFX")
{ SFXProviderType::OpenAL, "OpenAL", "OpenAL Provider." },
{ SFXProviderType::DirectSound, "DirectSound", "DirectSound Provider." },
{ SFXProviderType::XAudio, "XAudio", "XAudio Provider." },
{ SFXProviderType::NullProvider, "NullProvider","NullProvider Provider." }
EndImplementEnumType;
// Device type
ImplementEnumType(SFXDeviceType,
"The sfx device type input/output.\n"
"@ingroup SFX")
{ SFXDeviceType::Input, "InputDevice", "Input/Capture device" },
{ SFXDeviceType::Output, "OutputDevice", "Output Device." },
EndImplementEnumType;
// Excludes Null and Blocked as these are not passed out to the control layer.
ImplementEnumType( SFXStatus,
"Playback status of sound source.\n"
@ -185,6 +209,165 @@ static const U32 sDeviceInfoMaxBuffers = 3;
//-----------------------------------------------------------------------------
SFXSystem::RegisterProviderSignal& SFXSystem::getRegisterProviderSignal()
{
if (smRegisterProviderSignal)
return *smRegisterProviderSignal;
smRegisterProviderSignal = new RegisterProviderSignal();
return *smRegisterProviderSignal;
}
S32 SFXSystem::getProviderCount()
{
return smProviders.size();
}
inline static void _SFXInitReportProviders(Vector<SFXProvider*>& providers)
{
for (U32 i = 0; i < providers.size(); i++)
{
switch (providers[i]->mType)
{
case OpenAL:
Con::printf(" OpenAL Device Found: %s Device %s %s", providers[i]->mDeviceType == Input ? "Input" : "Output", providers[i]->getName(), providers[i]->mDefault ? "(Default)" : "");
break;
case NullProvider:
Con::printf(" Null device found");
break;
case XAudio:
Con::printf(" XAudio Device Found: %s Device %s %s", providers[i]->mDeviceType == Input ? "Input" : "Output", providers[i]->getName(), providers[i]->mDefault ? "(Default)" : "");
break;
case DirectSound:
Con::printf(" DirectSound Device Found: %s Device %s %s", providers[i]->mDeviceType == Input ? "Input" : "Output", providers[i]->getName(), providers[i]->mDefault ? "(Default)" : "");
break;
default:
Con::printf(" Unknown device found");
break;
}
}
}
void SFXSystem::getProviders(Vector<SFXProvider*>* providers)
{
providers->clear();
for (U32 k = 0; k < smProviders.size(); k++)
providers->push_back(smProviders[k]);
}
const char* SFXSystem::getProviderNameFromType(SFXProviderType type)
{
static const char* _names[] = { "OpenAL", "DirectSound", "XAudio", "NullProvider" };
if (type < 0 || type >= SFXProviderType_Count)
return _names[OpenAL];
return _names[type];
}
SFXProviderType SFXSystem::getProviderTypeFromName(const char* name)
{
for (U32 i = 0; i < SFXProviderType_Count; i++)
{
if (dStrcmp(getProviderNameFromType((SFXProviderType)i), name) == 0)
return (SFXProviderType)i;
}
// Default to NullProvider if no match rather than silently falling through
Con::warnf("SFXSystem::getProviderTypeFromName - unknown provider '%s', defaulting to NullProvider", name);
return SFXProviderType::NullProvider;
}
SFXProvider* SFXSystem::getProviderByTypeAndName(SFXProviderType type, const char* deviceName)
{
// First try exact type+name match
for (U32 i = 0; i < smProviders.size(); i++)
{
if (smProviders[i]->mType == type &&
String::compare(smProviders[i]->getName(), deviceName) == 0)
return smProviders[i];
}
// Fall back to default device for that type
for (U32 i = 0; i < smProviders.size(); i++)
{
if (smProviders[i]->mType == type && smProviders[i]->mDefault)
return smProviders[i];
}
// Last resort: any device of that type
for (U32 i = 0; i < smProviders.size(); i++)
{
if (smProviders[i]->mType == type)
return smProviders[i];
}
return NULL;
}
SFXProvider* SFXSystem::getBestProviderChoice()
{
const String preferredProvider = Con::getVariable("$pref::SFX::provider");
const String preferredDevice = Con::getVariable("$pref::SFX::device");
// Resolve provider type.
SFXProviderType providerType = OpenAL;
if (!preferredProvider.isEmpty())
{
for (U32 i = 0; i < SFXProviderType_Count; i++)
{
if (!dStrcmp(getProviderNameFromType((SFXProviderType)i),preferredProvider))
{
providerType = (SFXProviderType)i;
break;
}
}
}
if (!preferredDevice.isEmpty())
{
for (U32 i = 0; i < smProviders.size(); i++)
{
SFXProvider* provider = smProviders[i];
if (provider->mType != providerType)
continue;
if (String::compare(provider->getName(), preferredDevice.c_str()) == 0)
{
return provider;
}
}
}
for (U32 i = 0; i < smProviders.size(); i++)
{
SFXProvider* provider = smProviders[i];
if (provider->mType != providerType)
continue;
if (provider->mDefault)
return provider;
}
for (U32 i = 0; i < smProviders.size(); i++)
{
SFXProvider* provider = smProviders[i];
if (provider->mType != providerType)
continue;
return provider;
}
return NULL;
}
SFXProvider* SFXSystem::getProvider(U32 index)
{
return smProviders[index];
}
SFXSystem::SFXSystem()
: mDevice( NULL ),
mLastSourceUpdateTime( 0 ),
@ -200,6 +383,7 @@ SFXSystem::SFXSystem()
mDistanceModel( SFXDistanceModelLinear ),
mStatAmbientUpdateTime( 0 ),
mDopplerFactor( 0.5 ),
mSpeedOfSound(343.3f),
mRolloffFactor( 1.0 ),
mSoundscapeMgr( NULL )
{
@ -340,15 +524,36 @@ SFXSystem::~SFXSystem()
deleteDevice();
}
void SFXSystem::enumerateProviders()
{
if (smProviders.size())
{
return;
}
getRegisterProviderSignal().trigger(SFXSystem::smProviders);
}
//-----------------------------------------------------------------------------
void SFXSystem::init()
{
AssertWarn( smSingleton == NULL, "SFX has already been initialized!" );
SFXProvider::initializeAllProviders();
// Create the stream thread pool.
// SFXProvider::initializeAllProviders();
Con::printf("SFX Init:");
// find our providers
Vector<SFXProvider*> providers( __FILE__, __LINE__ );
SFXSystem::enumerateProviders();
SFXSystem::getProviders(&providers);
if (!providers.size())
Con::errorf("Could not find a sound provider");
//loop through and tell the user what kind of provider we found
_SFXInitReportProviders(providers);
Con::printf("");
SFXInternal::SFXThreadPool::createSingleton();
@ -366,6 +571,13 @@ void SFXSystem::destroy()
{
AssertWarn( smSingleton != NULL, "SFX has not been initialized!" );
while (smProviders.size())
{
SFXProvider* provider = smProviders.last();
smProviders.decrement();
delete provider;
}
delete smSingleton;
smSingleton = NULL;
@ -373,6 +585,9 @@ void SFXSystem::destroy()
SFXInternal::SFXThreadPool::deleteSingleton();
delete(sDefaultAmbience);
if (smRegisterProviderSignal)
SAFE_DELETE(smRegisterProviderSignal);
}
//-----------------------------------------------------------------------------
@ -397,61 +612,54 @@ void SFXSystem::removePlugin( SFXSystemPlugin* plugin )
}
}
//-----------------------------------------------------------------------------
bool SFXSystem::createDevice( const String& providerName, const String& deviceName, bool useHardware, S32 maxBuffers, bool changeDevice )
bool SFXSystem::createDeviceByName(const char* providerName, const char* deviceName)
{
// Make sure we don't have a device already.
if( mDevice && !changeDevice )
return false;
SFXProviderType type = getProviderTypeFromName(providerName);
SFXProvider* provider = getProviderByTypeAndName(type, deviceName);
// Lookup the provider.
SFXProvider* provider = SFXProvider::findProvider( providerName );
if( !provider )
return false;
// If we have already created this device and are using it then no need to do anything.
if( mDevice
&& providerName.equal( mDevice->getProvider()->getName(), String::NoCase )
&& deviceName.equal( mDevice->getName(), String::NoCase )
&& useHardware == mDevice->getUseHardware() )
return true;
// If we have an existing device remove it.
if( mDevice )
deleteDevice();
// Create the new device..
mDevice = provider->createDevice( deviceName, useHardware, maxBuffers );
if( !mDevice )
if (!provider)
{
Con::errorf( "SFXSystem::createDevice - failed creating %s device '%s'", providerName.c_str(), deviceName.c_str() );
Con::errorf("SFXSystem::createDeviceByName - could not find provider '%s' device '%s'",
providerName, deviceName);
return false;
}
// Print capabilities.
Con::printf( "SFXSystem::createDevice - created %s device '%s'", providerName.c_str(), deviceName.c_str() );
if( mDevice->getCaps() & SFXDevice::CAPS_Reverb )
Con::printf( " CAPS_Reverb" );
if( mDevice->getCaps() & SFXDevice::CAPS_VoiceManagement )
Con::printf( " CAPS_VoiceManagement" );
if( mDevice->getCaps() & SFXDevice::CAPS_Occlusion )
Con::printf( "\tCAPS_Occlusion" );
if( mDevice->getCaps() & SFXDevice::CAPS_MultiListener )
Con::printf( "\tCAPS_MultiListener" );
// Set defaults.
return createDevice(provider);
}
//-----------------------------------------------------------------------------
bool SFXSystem::createDevice(SFXProvider* provider)
{
// this should probably just happen tbh.
if (mDevice)
{
// called to create the same device bug out.
// this may need to be changed later to check if
// the provider names also match.
if (String::compare(mDevice->getName(), provider->getName()) == 0)
return false;
deleteDevice();
}
mDevice = provider->mCreateDeviceInstanceDelegate(provider->mIndex);
if( !mDevice )
{
Con::errorf( "SFXSystem::createDevice - failed creating device '%s'", provider->getName());
return false;
}
mDevice->setProvider(provider);
// device is responsible for printing its information.
// Set defaults.
mDevice->setNumListeners( getNumListeners() );
mDevice->setDistanceModel( mDistanceModel );
mDevice->setDopplerFactor( mDopplerFactor );
mDevice->setRolloffFactor( mRolloffFactor );
mDevice->setSpeedOfSound( mSpeedOfSound );
//OpenAL requires slots for effects, this creates an empty function
//that will run when a sfxdevice is created.
mDevice->openSlots();
@ -464,17 +672,15 @@ bool SFXSystem::createDevice( const String& providerName, const String& deviceNa
return true;
}
//-----------------------------------------------------------------------------
String SFXSystem::getDeviceInfoString()
{
// Make sure we have a valid device.
if( !mDevice )
return String();
return String::ToString( "%s\t%s\t%s\t%d\t%d",
mDevice->getProvider()->getName().c_str(),
mDevice->getName().c_str(),
return String::ToString( "%s\t%s\t%s\t%d\t%d",
getProviderNameFromType(mDevice->getProvider()->mType),
mDevice->getProvider()->getName(),
mDevice->getUseHardware() ? "1" : "0",
mDevice->getMaxBuffers(),
mDevice->getCaps() );
@ -794,8 +1000,10 @@ void SFXSystem::_update()
}
// If we have a device then update it.
if( mDevice )
if (mDevice)
{
mDevice->update();
}
}
//-----------------------------------------------------------------------------
@ -1020,6 +1228,18 @@ void SFXSystem::setDopplerFactor( F32 factor )
//-----------------------------------------------------------------------------
void SFXSystem::setSpeedOfSound(F32 speedOfSound)
{
const bool changed = (speedOfSound != mSpeedOfSound);
mSpeedOfSound = speedOfSound;
if (mDevice && changed)
mDevice->setSpeedOfSound(speedOfSound);
}
//-----------------------------------------------------------------------------
void SFXSystem::setRolloffFactor( F32 factor )
{
const bool changed = ( factor != mRolloffFactor );
@ -1210,6 +1430,43 @@ void SFXSystem::dumpSources( StringBuilder* toString, bool excludeGroups )
//-----------------------------------------------------------------------------
DefineEngineFunction(sfxGetProviderCount, S32, (), ,
"Returns the number of sound providers available\n\n"
"@ingroup SFX")
{
return SFXSystem::getProviderCount();
}
DefineEngineFunction(sfxGetProviderType, SFXProviderType, (S32 index), ,
"Returns the type (OpenAL, XAudio, DirectSound, Null) of a sound provider.\n"
"@param index The index of the adapter.")
{
Vector<SFXProvider*> providers(__FILE__, __LINE__);
SFXSystem::getProviders(&providers);
if (index >= 0 && index < providers.size())
return providers[index]->mType;
Con::errorf("SFXSystem::sfxGetProviderType - Out of range provider index.");
return SFXProviderType_Count;
}
DefineEngineFunction(sfxGetProviderDevice, const char*, (S32 index), ,
"Returns the device name of the sound provider.\n"
"@param index The index of the adapter.")
{
Vector<SFXProvider*> providers(__FILE__, __LINE__);
SFXSystem::getProviders(&providers);
if (index >= 0 && index < providers.size())
return providers[index]->getName();
Con::errorf("SFXSystem::sfxGetProviderDevice - Out of range provider index.");
return "";
}
DefineEngineFunction( sfxGetAvailableDevices, const char*, (),,
"Get a list of all available sound devices.\n"
"The return value will be a newline-separated list of entries where each line describes one available sound "
@ -1240,27 +1497,14 @@ DefineEngineFunction( sfxGetAvailableDevices, const char*, (),,
char *ptr = deviceList;
*ptr = 0;
SFXProvider* provider = SFXProvider::getFirstProvider();
while ( provider )
Vector<SFXProvider*> providers(__FILE__, __LINE__);
SFXSystem::getProviders(&providers);
for (U32 i = 0; i < providers.size(); i++)
{
// List the devices in this provider.
const SFXDeviceInfoVector& deviceInfo = provider->getDeviceInfo();
for ( S32 d=0; d < deviceInfo.size(); d++ )
{
const SFXDeviceInfo* info = deviceInfo[d];
const char *providerName = provider->getName().c_str();
char *infoName = (char*)info->name.c_str();
dSprintf(ptr, len, "%s\t%s\t%s\t%i\n", providerName, infoName, info->hasHardware ? "1" : "0", info->maxBuffers);
ptr += dStrlen(ptr);
len = bufferSize - (ptr - deviceList);
if (len <= 0)
return deviceList;
}
provider = provider->getNextProvider();
dSprintf(ptr, len, "%s\t", providers[i]->getName());
ptr += dStrlen(ptr);
len = bufferSize - (ptr - deviceList);
}
return deviceList;
@ -1268,7 +1512,7 @@ DefineEngineFunction( sfxGetAvailableDevices, const char*, (),,
//-----------------------------------------------------------------------------
DefineEngineFunction( sfxCreateDevice, bool, ( const char* provider, const char* device, bool useHardware, S32 maxBuffers ),,
DefineEngineFunction( sfxCreateDevice, bool, (),,
"Try to create a new sound device using the given properties.\n"
"If a sound device is currently initialized, it will be uninitialized first. However, be aware that in this case, "
"if this function fails, it will not restore the previously active device but rather leave the sound system in an "
@ -1276,10 +1520,6 @@ DefineEngineFunction( sfxCreateDevice, bool, ( const char* provider, const char*
"Sounds that are already playing while the new device is created will be temporarily transitioned to virtualized "
"playback and then resume normal playback once the device has been created.\n\n"
"In the core scripts, sound is automatically set up during startup in the sfxStartup() function.\n\n"
"@param provider The name of the device provider as returned by sfxGetAvailableDevices().\n"
"@param device The name of the device as returned by sfxGetAvailableDevices().\n"
"@param useHardware Whether to enabled hardware mixing on the device or not. Only relevant if supported by the given device.\n"
"@param maxBuffers The maximum number of concurrent voices for this device to use or -1 for the device to pick its own reasonable default."
"@return True if the initialization was successful, false if not.\n"
"@note This function must be called before any of the sound playback functions can be used.\n"
"@see sfxGetAvailableDevices\n"
@ -1288,7 +1528,34 @@ DefineEngineFunction( sfxCreateDevice, bool, ( const char* provider, const char*
"@ref SFX_devices\n"
"@ingroup SFX" )
{
return SFX->createDevice( provider, device, useHardware, maxBuffers, true );
// return SFX->createDevice( provider, device, useHardware, maxBuffers, true );
SFXProvider* p = SFXSystem::getBestProviderChoice();
if (p)
{
SFX->createDevice(p);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
DefineEngineFunction(sfxCreateDeviceFromName, bool, (const char* providerName, const char* deviceName), ("", ""),
"Create a sound device. Optionally specify provider and device name directly.\n"
"@param providerName Optional provider type name (e.g. \"OpenAL\", \"NullProvider\").\n"
"@param deviceName Optional device name to match against.\n"
"@ingroup SFX")
{
// If explicit names were provided, use them directly
if (providerName[0] != '\0' && deviceName[0] != '\0')
return SFX->createDeviceByName(providerName, deviceName);
// Otherwise fall back to autodetect via prefs
SFXProvider* p = SFXSystem::getBestProviderChoice();
if (p)
return SFX->createDevice(p);
return false;
}
//-----------------------------------------------------------------------------
@ -1621,13 +1888,13 @@ DefineEngineFunction( sfxPlayOnce, S32, (StringTableEntry assetId, const char* a
if (String::isEmpty(arg0) || !tempSoundAsset->is3D())
{
source = SFX->playOnce(tempSoundAsset->getSfxProfile());
source = SFX->playOnce(tempSoundAsset->getSFXTrack());
}
else
{
MatrixF transform;
transform.set(EulerF(0, 0, 0), Point3F(dAtof(arg0), dAtof(arg1), dAtof(arg2)));
source = SFX->playOnce(tempSoundAsset->getSfxProfile(), &transform, NULL, dAtof(arg3));
source = SFX->playOnce(tempSoundAsset->getSFXTrack(), &transform, NULL, dAtof(arg3));
}
}
else

View file

@ -23,9 +23,10 @@
#ifndef _SFXSYSTEM_H_
#define _SFXSYSTEM_H_
#ifndef _SFXCOMMON_H_
#include "sfx/sfxCommon.h"
#endif
#ifndef _SFXPROVIDER_H_
#include "sfx/sfxProvider.h"
#endif // !_SFXPROVIDER_H_
#ifndef _TSIGNAL_H_
#include "core/util/tSignal.h"
#endif
@ -98,343 +99,362 @@ class SFXSystemPlugin
///
class SFXSystem
{
friend class SFXSound; // _assignVoices
friend class SFXSource; // _onAddSource, _onRemoveSource.
friend class SFXProfile; // _createBuffer.
friend class SFXSound; // _assignVoices
friend class SFXSource; // _onAddSource, _onRemoveSource.
friend class SFXProfile; // _createBuffer.
public:
/// Allows device to register themselves as available
typedef Signal<void(Vector<SFXProvider*>&)> RegisterProviderSignal;
static RegisterProviderSignal& getRegisterProviderSignal();
/// Get the number of available providers.
static S32 getProviderCount();
/// Enumerate all the sound providers on the system
static void enumerateProviders();
static void getProviders(Vector<SFXProvider*>* providers);
static const char* getProviderNameFromType(SFXProviderType type);
static SFXProvider* getBestProviderChoice();
static SFXProvider* getProvider(U32 index);
static SFXProviderType getProviderTypeFromName(const char* name);
static SFXProvider* getProviderByTypeAndName(SFXProviderType type, const char* deviceName);
typedef Signal< void( SFXSystemEventType event ) > EventSignalType;
typedef Vector< SFXSource* > SFXSourceVector;
typedef Vector< SFXSound* > SFXSoundVector;
private:
/// List of known adapters.
static Vector<SFXProvider*> smProviders;
static RegisterProviderSignal* smRegisterProviderSignal;
protected:
/// The one and only instance of the SFXSystem.
static SFXSystem* smSingleton;
/// The protected constructor.
///
/// @see SFXSystem::init()
///
SFXSystem();
/// The non-virtual destructor. You shouldn't
/// ever need to overload this class.
~SFXSystem();
public:
typedef Signal< void( SFXSystemEventType event ) > EventSignalType;
typedef Vector< SFXSource* > SFXSourceVector;
typedef Vector< SFXSound* > SFXSoundVector;
/// The current output sound device initialized
/// and ready to play back.
SFXDevice* mDevice;
protected:
///
SFXSoundVector mSounds;
/// The one and only instance of the SFXSystem.
static SFXSystem* smSingleton;
/// The protected constructor.
///
/// @see SFXSystem::init()
///
SFXSystem();
/// The non-virtual destructor. You shouldn't
/// ever need to overload this class.
~SFXSystem();
/// The current output sound device initialized
/// and ready to play back.
SFXDevice* mDevice;
///
SFXSoundVector mSounds;
/// This is used to keep track of play once sources
/// that must be released when they stop playing.
SFXSourceVector mPlayOnceSources;
/// This is used to keep track of play once sources
/// that must be released when they stop playing.
SFXSourceVector mPlayOnceSources;
/// The last time the sources got an update.
U32 mLastSourceUpdateTime;
/// The last time the sources got an update.
U32 mLastSourceUpdateTime;
///
U32 mLastAmbientUpdateTime;
///
U32 mLastAmbientUpdateTime;
///
U32 mLastParameterUpdateTime;
///
U32 mLastParameterUpdateTime;
/// The distance model used for rolloff curve computation on 3D sounds.
SFXDistanceModel mDistanceModel;
/// The distance model used for rolloff curve computation on 3D sounds.
SFXDistanceModel mDistanceModel;
/// The current doppler scale factor.
F32 mDopplerFactor;
/// The current doppler scale factor.
F32 mDopplerFactor;
/// The current speed of sound.
F32 mSpeedOfSound;
/// The current curve rolloff factor.
F32 mRolloffFactor;
/// The current curve rolloff factor.
F32 mRolloffFactor;
/// The current position and orientation of all listeners.
Vector< SFXListenerProperties > mListeners;
/// The current position and orientation of all listeners.
Vector< SFXListenerProperties > mListeners;
/// Current global reverb properties.
SFXReverbProperties mReverb;
/// Current global reverb properties.
SFXReverbProperties mReverb;
/// SFX system event signal.
EventSignalType mEventSignal;
/// SFX system event signal.
EventSignalType mEventSignal;
/// Ambient soundscape manager.
SFXSoundscapeManager* mSoundscapeMgr;
/// Ambient soundscape manager.
SFXSoundscapeManager* mSoundscapeMgr;
/// List of plugins currently linked to the SFX system.
Vector< SFXSystemPlugin* > mPlugins;
/// List of plugins currently linked to the SFX system.
Vector< SFXSystemPlugin* > mPlugins;
/// @name Stats
///
/// Stats reported back to the console for tracking performance.
///
/// @{
/// @name Stats
///
/// Stats reported back to the console for tracking performance.
///
/// @{
S32 mStatNumSources;
S32 mStatNumSounds;
S32 mStatNumPlaying;
S32 mStatNumCulled;
S32 mStatNumVoices;
S32 mStatSourceUpdateTime;
S32 mStatParameterUpdateTime;
S32 mStatAmbientUpdateTime;
S32 mStatNumSources;
S32 mStatNumSounds;
S32 mStatNumPlaying;
S32 mStatNumCulled;
S32 mStatNumVoices;
S32 mStatSourceUpdateTime;
S32 mStatParameterUpdateTime;
S32 mStatAmbientUpdateTime;
/// @}
/// @}
/// Called to reprioritize and reassign buffers as
/// sources change state, volumes are adjusted, and
/// the listener moves around.
///
/// @see SFXSource::_update()
///
void _updateSources();
/// Called to reprioritize and reassign buffers as
/// sources change state, volumes are adjusted, and
/// the listener moves around.
///
/// @see SFXSource::_update()
///
void _updateSources();
/// This called to reprioritize and reassign
/// voices to sources.
void _assignVoices();
/// This called to reprioritize and reassign
/// voices to sources.
void _assignVoices();
///
void _assignVoice( SFXSound* sound );
///
void _assignVoice( SFXSound* sound );
///
void _sortSounds( const SFXListenerProperties& listener );
///
void _sortSounds( const SFXListenerProperties& listener );
/// Called from SFXSource::onAdd to register the source.
void _onAddSource( SFXSource* source );
/// Called from SFXSource::onAdd to register the source.
void _onAddSource( SFXSource* source );
/// Called from SFXSource::onRemove to unregister the source.
void _onRemoveSource( SFXSource* source );
/// Called from SFXSource::onRemove to unregister the source.
void _onRemoveSource( SFXSource* source );
/// Called from SFXProfile to create a device specific
/// sound buffer used in conjunction with a voice in playback.
SFXBuffer* _createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
/// Called from SFXProfile to create a device specific
/// sound buffer used in conjunction with a voice in playback.
SFXBuffer* _createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
/// Load file directly through SFXDevice. Depends on
/// availability with selected SFXDevice.
///
/// @return Return new buffer or NULL.
SFXBuffer* _createBuffer( const String& filename, SFXDescription* description );
/// Load file directly through SFXDevice. Depends on
/// availability with selected SFXDevice.
///
/// @return Return new buffer or NULL.
SFXBuffer* _createBuffer( const String& filename, SFXDescription* description );
///
SFXDevice* _getDevice() const { return mDevice; }
///
SFXDevice* _getDevice() const { return mDevice; }
public:
public:
/// Returns the one an only instance of the SFXSystem
/// unless it hasn't been initialized or its been disabled
/// in your build.
///
/// For convienence you can use the SFX-> macro as well.
///
/// @see SFXSystem::init()
/// @see SFX
static SFXSystem* getSingleton() { return smSingleton; }
/// Returns the one an only instance of the SFXSystem
/// unless it hasn't been initialized or its been disabled
/// in your build.
///
/// For convienence you can use the SFX-> macro as well.
///
/// @see SFXSystem::init()
/// @see SFX
static SFXSystem* getSingleton() { return smSingleton; }
/// This is called from initialization to prepare the
/// sound system singleton. This also includes registering
/// common resource types and initializing available sound
/// providers.
static void init();
/// This is called from initialization to prepare the
/// sound system singleton. This also includes registering
/// common resource types and initializing available sound
/// providers.
static void init();
/// This is called after Sim::shutdown() in shutdownLibraries()
/// to free the sound system singlton. After this the SFX
/// singleton is null and any call to it will crash.
static void destroy();
/// This is called after Sim::shutdown() in shutdownLibraries()
/// to free the sound system singlton. After this the SFX
/// singleton is null and any call to it will crash.
static void destroy();
/// This is only public so that it can be called by
/// the game update loop. It updates the current
/// device and all sources.
void _update();
/// This is only public so that it can be called by
/// the game update loop. It updates the current
/// device and all sources.
void _update();
/// Register the given plugin with the system.
void addPlugin( SFXSystemPlugin* plugin );
/// Register the given plugin with the system.
void addPlugin( SFXSystemPlugin* plugin );
/// Unregister the given plugin with the system.
void removePlugin( SFXSystemPlugin* plugin );
/// Unregister the given plugin with the system.
void removePlugin( SFXSystemPlugin* plugin );
/// @name Device Management
/// @{
bool createDeviceByName(const char* providerName, const char* deviceName);
/// This initializes a new device.
///
/// @return Returns true if the device was created.
bool createDevice( SFXProvider* provider);
/// Returns the current device information or NULL if no
/// device is present. The information string is in the
/// following format:
///
/// Provider Name\tDevice Name\tUse Hardware\tMax Buffers
String getDeviceInfoString();
/// This destroys the current device. All sources loose their
/// playback buffers, but otherwise continue to function.
void deleteDevice();
/// Returns true if a device is allocated.
bool hasDevice() const { return mDevice != NULL; }
/// @name Device Management
/// @{
/// This initializes a new device.
///
/// @param providerName The name of the provider.
/// @param deviceName The name of the provider device.
/// @param useHardware Toggles the use of hardware processing when available.
/// @param maxBuffers The maximum buffers for this device to use or -1
/// for the device to pick its own reasonable default.
/// @param changeDevice Allows this to change the current device to a new one
/// @return Returns true if the device was created.
bool createDevice( const String& providerName,
const String& deviceName,
bool useHardware,
S32 maxBuffers,
bool changeDevice = false);
/// Returns the current device information or NULL if no
/// device is present. The information string is in the
/// following format:
///
/// Provider Name\tDevice Name\tUse Hardware\tMax Buffers
String getDeviceInfoString();
/// This destroys the current device. All sources loose their
/// playback buffers, but otherwise continue to function.
void deleteDevice();
/// Returns true if a device is allocated.
bool hasDevice() const { return mDevice != NULL; }
/// @}
/// @}
/// @name Source Creation
/// @{
/// @name Source Creation
/// @{
/// Used to create new sound sources from a sound profile. The
/// returned source is in a stopped state and ready for playback.
/// Use the SFX_DELETE macro to free the source when your done.
///
/// @note The track must have at least the same lifetime as the
/// source. If the description disappears while the source is still
/// there, the source will go with it.
///
/// @param profile The sound profile for the created source.
/// @param transform The optional transform if creating a 3D source.
/// @param velocity The optional doppler velocity if creating a 3D source.
///
/// @return The sound source or NULL if an error occured.
SFXSource* createSource( SFXTrack* track,
const MatrixF* transform = NULL,
const VectorF* velocity = NULL );
/// Used to create new sound sources from a sound profile. The
/// returned source is in a stopped state and ready for playback.
/// Use the SFX_DELETE macro to free the source when your done.
///
/// @note The track must have at least the same lifetime as the
/// source. If the description disappears while the source is still
/// there, the source will go with it.
///
/// @param profile The sound profile for the created source.
/// @param transform The optional transform if creating a 3D source.
/// @param velocity The optional doppler velocity if creating a 3D source.
///
/// @return The sound source or NULL if an error occured.
SFXSource* createSource( SFXTrack* track,
const MatrixF* transform = NULL,
const VectorF* velocity = NULL );
/// Used to create a streaming sound source from a user supplied
/// stream object.
///
/// It is only intended for memory based streams. For sound file
/// streaming use createSource() with a streaming SFXProfile.
///
/// Use the SFX_DELETE macro to free the source when your done.
///
/// @note The description must have at least the same lifetime as the
/// sound. If the description disappears while the source is still
/// there, the sound will go with it.
///
/// @param stream The stream used to create the sound buffer. It
/// must exist for the lifetime of the source and will
/// have its reference count decremented when the source
/// is destroyed.
///
/// @param description The sound description to apply to the source.
///
/// @return The sound source or NULL if an error occured.
SFXSound* createSourceFromStream( const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description );
/// Used to create a streaming sound source from a user supplied
/// stream object.
///
/// It is only intended for memory based streams. For sound file
/// streaming use createSource() with a streaming SFXProfile.
///
/// Use the SFX_DELETE macro to free the source when your done.
///
/// @note The description must have at least the same lifetime as the
/// sound. If the description disappears while the source is still
/// there, the sound will go with it.
///
/// @param stream The stream used to create the sound buffer. It
/// must exist for the lifetime of the source and will
/// have its reference count decremented when the source
/// is destroyed.
///
/// @param description The sound description to apply to the source.
///
/// @return The sound source or NULL if an error occured.
SFXSound* createSourceFromStream( const ThreadSafeRef< SFXStream >& stream,
SFXDescription* description );
/// Creates a source which when it finishes playing will auto delete
/// itself. Be aware that the returned SFXSource pointer should only
/// be used for error checking or immediate setting changes. It may
/// be deleted as soon as the next system tick.
///
/// @param profile The sound profile for the created source.
/// @param transform The optional transform if creating a 3D source.
/// @param velocity The optional doppler velocity if creating a 3D source.
///
/// @return The sound source or NULL if an error occured.
SFXSource* playOnce( SFXTrack* track,
const MatrixF* transform = NULL,
const VectorF* velocity = NULL,
F32 fadeInTime = -1.f );
SFXSource* playOnce( SFXProfile* profile,
const MatrixF* transform = NULL,
const VectorF* velocity = NULL,
F32 fadeInTime = -1.f )
{ // Avoids having to require inclusion of sfxProfile.h
return playOnce( ( SFXTrack* ) profile, transform, velocity, fadeInTime );
}
/// Creates a source which when it finishes playing will auto delete
/// itself. Be aware that the returned SFXSource pointer should only
/// be used for error checking or immediate setting changes. It may
/// be deleted as soon as the next system tick.
///
/// @param profile The sound profile for the created source.
/// @param transform The optional transform if creating a 3D source.
/// @param velocity The optional doppler velocity if creating a 3D source.
///
/// @return The sound source or NULL if an error occured.
SFXSource* playOnce( SFXTrack* track,
const MatrixF* transform = NULL,
const VectorF* velocity = NULL,
F32 fadeInTime = -1.f );
SFXSource* playOnce( SFXProfile* profile,
const MatrixF* transform = NULL,
const VectorF* velocity = NULL,
F32 fadeInTime = -1.f )
{ // Avoids having to require inclusion of sfxProfile.h
return playOnce( ( SFXTrack* ) profile, transform, velocity, fadeInTime );
}
/// Stop the source and delete it. This method will take care of
/// the fade-out time that the source may need before it will actually
/// stop and may be deleted.
void stopAndDeleteSource( SFXSource* source );
/// Stop the source and delete it. This method will take care of
/// the fade-out time that the source may need before it will actually
/// stop and may be deleted.
void stopAndDeleteSource( SFXSource* source );
/// Mark source for deletion when it is moving into stopped state.
/// This method is useful to basically make a source a play-once source
/// after the fact.
void deleteWhenStopped( SFXSource* source );
/// Mark source for deletion when it is moving into stopped state.
/// This method is useful to basically make a source a play-once source
/// after the fact.
void deleteWhenStopped( SFXSource* source );
/// @}
/// @}
/// @}
/// @}
/// @name Listeners
/// @{
/// @name Listeners
/// @{
/// Return the number of listeners currently configured.
U32 getNumListeners() const { return mListeners.size(); }
/// Return the number of listeners currently configured.
U32 getNumListeners() const { return mListeners.size(); }
/// Set the number of concurrent listeners.
/// @note It depends on the selected device if more than one listener is actually supported.
void setNumListeners( U32 num );
/// Set the number of concurrent listeners.
/// @note It depends on the selected device if more than one listener is actually supported.
void setNumListeners( U32 num );
/// Set the property of the given listener.
const SFXListenerProperties& getListener( U32 index = 0 ) const { return mListeners[ index ]; }
/// Set the property of the given listener.
const SFXListenerProperties& getListener( U32 index = 0 ) const { return mListeners[ index ]; }
/// Set the 3D attributes of the given listener.
void setListener( U32 index, const MatrixF& transform, const Point3F& velocity );
void setListener( U32 index, const SFXListenerProperties& properties )
{
setListener( index, properties.getTransform(), properties.getVelocity() );
}
/// Set the 3D attributes of the given listener.
void setListener( U32 index, const MatrixF& transform, const Point3F& velocity );
void setListener( U32 index, const SFXListenerProperties& properties )
{
setListener( index, properties.getTransform(), properties.getVelocity() );
}
/// @}
/// @}
/// @name 3D Sound Configuration
/// {
/// @name 3D Sound Configuration
/// {
/// Return the curve model currently used distance attenuation of positional sounds.
SFXDistanceModel getDistanceModel() const { return mDistanceModel; }
/// Return the curve model currently used distance attenuation of positional sounds.
SFXDistanceModel getDistanceModel() const { return mDistanceModel; }
///
void setDistanceModel( SFXDistanceModel model );
///
void setDistanceModel( SFXDistanceModel model );
///
F32 getDopplerFactor() const { return mDopplerFactor; }
///
F32 getDopplerFactor() const { return mDopplerFactor; }
///
void setDopplerFactor( F32 factor );
///
void setDopplerFactor( F32 factor );
///
F32 getRolloffFactor() const { return mRolloffFactor; }
///
F32 getRolloffFactor() const { return mRolloffFactor; }
/// <summary>
/// Change the devices speed of sound.
/// </summary>
/// <param name="speedOfSound">F32 for speed of sound.</param>
void setSpeedOfSound(F32 speedOfSound);
///
void setRolloffFactor( F32 factor );
///
void setRolloffFactor( F32 factor );
///
const SFXReverbProperties& getReverb() const { return mReverb; }
///
const SFXReverbProperties& getReverb() const { return mReverb; }
///
void setReverb( const SFXReverbProperties& reverb );
///
void setReverb( const SFXReverbProperties& reverb );
/// @}
/// @}
///
SFXSoundscapeManager* getSoundscapeManager() const { return mSoundscapeMgr; }
///
SFXSoundscapeManager* getSoundscapeManager() const { return mSoundscapeMgr; }
/// Dump information about all current SFXSources to the console or
/// to the given StringBuilder.
void dumpSources( StringBuilder* toString = NULL, bool excludeGroups = true );
/// Dump information about all current SFXSources to the console or
/// to the given StringBuilder.
void dumpSources( StringBuilder* toString = NULL, bool excludeGroups = true );
/// Return the SFX system event signal.
EventSignalType& getEventSignal() { return mEventSignal; }
/// Return the SFX system event signal.
EventSignalType& getEventSignal() { return mEventSignal; }
/// Notify the SFX system that the given description has changed.
/// All sources currently using the description will be updated.
void notifyDescriptionChanged( SFXDescription* description);
/// Notify the SFX system that the given description has changed.
/// All sources currently using the description will be updated.
void notifyDescriptionChanged( SFXDescription* description);
///
void notifyTrackChanged( SFXTrack* track );
///
void notifyTrackChanged( SFXTrack* track );
};

View file

@ -210,9 +210,9 @@ class SFXVoice : public StrongRefBase,
F32 outerAngle,
F32 outerVolume ) = 0;
/// Set the reverb properties for playback of this sound.
/// Allow this sound to use SFXEnvironment reverb.
/// @note Has no effect on devices that do not support reverb.
virtual void setReverb( const SFXSoundReverbProperties& reverb ) {}
virtual void setReverb( bool useReverb ) {}
/// Set the priority of this voice. Default 1.0.
/// @note Has no effect on devices that do not support voice management.

View file

@ -387,7 +387,7 @@ void SFXWorld< NUM_DIMENSIONS, Object >::_onScopeOut( Object object )
// Remove its soundscape.
Scope& scope = mScopeStack[ index ];
if( scope.mSoundscape )
if( scope.mSoundscape && SFX )
SFX->getSoundscapeManager()->removeSoundscape( scope.mSoundscape );
mScopeStack.erase( index );

View file

@ -1,125 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/xaudio/sfxXAudioBuffer.h"
#include "sfx/xaudio/sfxXAudioVoice.h"
//#define DEBUG_SPEW
SFXXAudioBuffer* SFXXAudioBuffer::create( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
{
SFXXAudioBuffer *buffer = new SFXXAudioBuffer( stream, description );
return buffer;
}
SFXXAudioBuffer::SFXXAudioBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
: Parent( stream, description )
{
VECTOR_SET_ASSOCIATION( mBufferQueue );
}
SFXXAudioBuffer::~SFXXAudioBuffer()
{
_flush();
}
void SFXXAudioBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
{
AssertFatal( SFXInternal::isSFXThread(), "SFXXAudioBuffer::write() - not on SFX thread" );
using namespace SFXInternal;
// Unqueue processed packets.
if( isStreaming() )
{
EnterCriticalSection( &_getUniqueVoice()->mLock );
XAUDIO2_VOICE_STATE state;
_getUniqueVoice()->mXAudioVoice->GetState( &state );
U32 numProcessed = mBufferQueue.size() - state.BuffersQueued;
for( U32 i = 0; i < numProcessed; ++ i )
{
destructSingle< SFXStreamPacket* >( mBufferQueue.first().mPacket );
mBufferQueue.pop_front();
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioBuffer] Unqueued packet" );
#endif
}
LeaveCriticalSection( &_getUniqueVoice()->mLock );
}
// Queue new packets.
for( U32 i = 0; i < num; ++ i )
{
SFXStreamPacket* packet = packets[ i ];
Buffer buffer;
if( packet->mIsLast )
buffer.mData.Flags = XAUDIO2_END_OF_STREAM;
buffer.mPacket = packet;
buffer.mData.AudioBytes = packet->mSizeActual;
buffer.mData.pAudioData = packet->data;
mBufferQueue.push_back( buffer );
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioBuffer] Queued packet" );
#endif
// If this is a streaming buffer, submit the packet to the
// voice queue right away.
if( isStreaming() )
{
EnterCriticalSection( &_getUniqueVoice()->mLock );
IXAudio2SourceVoice* voice = _getUniqueVoice()->mXAudioVoice;
voice->SubmitSourceBuffer( &buffer.mData );
LeaveCriticalSection( &_getUniqueVoice()->mLock );
}
}
}
void SFXXAudioBuffer::_flush()
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioBuffer] Flushing buffer" );
#endif
if( _getUniqueVoice() )
_getUniqueVoice()->_stop();
while( !mBufferQueue.empty() )
{
destructSingle( mBufferQueue.last().mPacket );
mBufferQueue.pop_back();
}
}

View file

@ -1,83 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _SFXXAUDIOBUFFER_H_
#define _SFXXAUDIOBUFFER_H_
#include <xaudio2.h>
#ifndef _SFXINTERNAL_H_
#include "sfx/sfxInternal.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
/// Audio data buffer for the XAudio device layer.
class SFXXAudioBuffer : public SFXBuffer
{
public:
typedef SFXBuffer Parent;
friend class SFXXAudioDevice;
friend class SFXXAudioVoice;
protected:
struct Buffer
{
XAUDIO2_BUFFER mData;
SFXInternal::SFXStreamPacket* mPacket;
Buffer()
: mPacket( 0 )
{
dMemset( &mData, 0, sizeof( mData ) );
}
};
typedef Vector< Buffer > QueueType;
QueueType mBufferQueue;
/// If this is a streaming buffer, return the unique voice associated
/// with the buffer.
SFXXAudioVoice* _getUniqueVoice() { return ( SFXXAudioVoice* ) mUniqueVoice.getPointer(); }
///
SFXXAudioBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
virtual ~SFXXAudioBuffer();
// SFXBuffer.
virtual void write( SFXInternal::SFXStreamPacket* const* packets, U32 num );
void _flush();
public:
///
static SFXXAudioBuffer* create( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
};
#endif // _SFXXAUDIOBUFFER_H_

View file

@ -1,245 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/xaudio/sfxXAudioDevice.h"
#include "platform/async/asyncUpdate.h"
#include "core/stringTable.h"
#include "console/console.h"
#include "core/util/safeRelease.h"
#include "core/tAlgorithm.h"
#include "platform/profiler.h"
SFXXAudioDevice::SFXXAudioDevice( SFXProvider* provider,
const String& name,
IXAudio2 *xaudio,
U32 deviceIndex,
U32 speakerChannelMask,
U32 maxBuffers )
: Parent( name, provider, false, maxBuffers ),
mXAudio( xaudio ),
mMasterVoice( NULL )
{
dMemset( &mListener, 0, sizeof( mListener ) );
// If mMaxBuffers is negative then use some default value.
// to decide on a good maximum value... or set 8.
//
// TODO: We should change the terminology to voices!
if ( mMaxBuffers < 0 )
mMaxBuffers = 64;
// Create the mastering voice.
HRESULT hr = mXAudio->CreateMasteringVoice( &mMasterVoice,
XAUDIO2_DEFAULT_CHANNELS,
XAUDIO2_DEFAULT_SAMPLERATE,
0,
deviceIndex,
NULL );
if ( FAILED( hr ) || !mMasterVoice )
{
Con::errorf( "SFXXAudioDevice - Failed creating master voice!" );
return;
}
mMasterVoice->GetVoiceDetails( &mMasterVoiceDetails );
// Init X3DAudio.
X3DAudioInitialize( speakerChannelMask,
X3DAUDIO_SPEED_OF_SOUND,
mX3DAudio );
// Start the update thread.
if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
{
SFXInternal::gUpdateThread = new AsyncUpdateThread
( "XAudio Update Thread", SFXInternal::gBufferUpdateList );
SFXInternal::gUpdateThread->start();
}
}
SFXXAudioDevice::~SFXXAudioDevice()
{
_releaseAllResources();
if ( mMasterVoice )
{
mMasterVoice->DestroyVoice();
mMasterVoice = NULL;
}
// Kill the engine.
SAFE_RELEASE( mXAudio );
}
SFXBuffer* SFXXAudioDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
{
SFXXAudioBuffer* buffer = SFXXAudioBuffer::create( stream, description );
if ( !buffer )
return NULL;
_addBuffer( buffer );
return buffer;
}
SFXVoice* SFXXAudioDevice::createVoice( bool is3D, SFXBuffer *buffer )
{
// Don't bother going any further if we've
// exceeded the maximum voices.
if ( mVoices.size() >= mMaxBuffers )
return NULL;
AssertFatal( buffer, "SFXXAudioDevice::createVoice() - Got null buffer!" );
SFXXAudioBuffer* xaBuffer = dynamic_cast<SFXXAudioBuffer*>( buffer );
AssertFatal( xaBuffer, "SFXXAudioDevice::createVoice() - Got bad buffer!" );
SFXXAudioVoice* voice = SFXXAudioVoice::create( mXAudio, is3D, xaBuffer );
if ( !voice )
return NULL;
voice->mXAudioDevice = this;
_addVoice( voice );
return voice;
}
void SFXXAudioDevice::_setOutputMatrix( SFXXAudioVoice *voice )
{
X3DAUDIO_DSP_SETTINGS dspSettings = {0};
FLOAT32 matrix[12] = { 0 };
dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels;
dspSettings.pMatrixCoefficients = matrix;
const X3DAUDIO_EMITTER &emitter = voice->getEmitter();
dspSettings.SrcChannelCount = emitter.ChannelCount;
// Calculate the output volumes and doppler.
X3DAudioCalculate( mX3DAudio,
&mListener,
&emitter,
X3DAUDIO_CALCULATE_MATRIX |
X3DAUDIO_CALCULATE_DOPPLER,
&dspSettings );
voice->mXAudioVoice->SetOutputMatrix( mMasterVoice,
dspSettings.SrcChannelCount,
dspSettings.DstChannelCount,
dspSettings.pMatrixCoefficients,
4321 );
voice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * voice->mPitch,
4321 );
// Commit the changes.
mXAudio->CommitChanges( 4321 );
}
void SFXXAudioDevice::update()
{
PROFILE_SCOPE( SFXXAudioDevice_Update );
Parent::update();
X3DAUDIO_DSP_SETTINGS dspSettings = {0};
FLOAT32 matrix[12] = { 0 };
dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels;
dspSettings.pMatrixCoefficients = matrix;
dspSettings.DopplerFactor = mDopplerFactor;
// Now update the volume and frequency of
// all the active 3D voices.
VoiceVector::iterator voice = mVoices.begin();
for ( ; voice != mVoices.end(); voice++ )
{
SFXXAudioVoice* xaVoice = ( SFXXAudioVoice* ) *voice;
// Skip 2D or stopped voices.
if ( !xaVoice->is3D() ||
xaVoice->getStatus() != SFXStatusPlaying )
continue;
const X3DAUDIO_EMITTER &emitter = xaVoice->getEmitter();
dspSettings.SrcChannelCount = emitter.ChannelCount;
// Calculate the output volumes and doppler.
X3DAudioCalculate( mX3DAudio,
&mListener,
&emitter,
X3DAUDIO_CALCULATE_MATRIX |
X3DAUDIO_CALCULATE_DOPPLER,
&dspSettings );
xaVoice->mXAudioVoice->SetOutputMatrix( mMasterVoice,
dspSettings.SrcChannelCount,
dspSettings.DstChannelCount,
dspSettings.pMatrixCoefficients,
4321 ) ;
xaVoice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * xaVoice->mPitch,
4321 );
}
// Commit the changes.
mXAudio->CommitChanges( 4321 );
}
void SFXXAudioDevice::setListener( U32 index, const SFXListenerProperties& listener )
{
// Get the transform from the listener.
const MatrixF& transform = listener.getTransform();
transform.getColumn( 3, (Point3F*)&mListener.Position );
transform.getColumn( 1, (Point3F*)&mListener.OrientFront );
transform.getColumn( 2, (Point3F*)&mListener.OrientTop );
// And the velocity...
const VectorF& velocity = listener.getVelocity();
mListener.Velocity.x = velocity.x;
mListener.Velocity.y = velocity.y;
mListener.Velocity.z = velocity.z;
// XAudio and Torque use opposite handedness, so
// flip the z coord to account for that.
mListener.Position.z *= -1.0f;
mListener.OrientFront.z *= -1.0f;
mListener.OrientTop.z *= -1.0f;
mListener.Velocity.z *= -1.0f;
}
void SFXXAudioDevice::setDistanceModel( SFXDistanceModel model )
{
mDistanceModel = model;
}
void SFXXAudioDevice::setDopplerFactor( F32 factor )
{
mDopplerFactor = factor;
}
void SFXXAudioDevice::setRolloffFactor( F32 factor )
{
mRolloffFactor = factor;
}

View file

@ -1,101 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _SFXXAUDIODEVICE_H_
#define _SFXXAUDIODEVICE_H_
class SFXProvider;
#ifndef _SFXDEVICE_H_
#include "sfx/sfxDevice.h"
#endif
#ifndef _SFXPROVIDER_H_
#include "sfx/sfxProvider.h"
#endif
#ifndef _SFXXAUDIOVOICE_H_
#include "sfx/xaudio/sfxXAudioVoice.h"
#endif
#ifndef _SFXXAUDIOBUFFER_H_
#include "sfx/xaudio/sfxXAudioBuffer.h"
#endif
#include <xaudio2.h>
#include <x3daudio.h>
class SFXXAudioDevice : public SFXDevice
{
public:
typedef SFXDevice Parent;
friend class SFXXAudioVoice; // mXAudio
protected:
/// The XAudio engine interface passed
/// on creation from the provider.
IXAudio2 *mXAudio;
/// The X3DAudio instance.
X3DAUDIO_HANDLE mX3DAudio;
/// The one and only mastering voice.
IXAudio2MasteringVoice* mMasterVoice;
/// The details of the master voice.
XAUDIO2_VOICE_DETAILS mMasterVoiceDetails;
/// The one listener.
X3DAUDIO_LISTENER mListener;
SFXDistanceModel mDistanceModel;
F32 mRolloffFactor;
F32 mDopplerFactor;
public:
SFXXAudioDevice( SFXProvider* provider,
const String& name,
IXAudio2 *xaudio,
U32 deviceIndex,
U32 speakerChannelMask,
U32 maxBuffers );
virtual ~SFXXAudioDevice();
// SFXDevice
virtual SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
virtual SFXVoice* createVoice( bool is3D, SFXBuffer *buffer );
virtual void update();
virtual void setListener( U32 index, const SFXListenerProperties& listener );
virtual void setDistanceModel( SFXDistanceModel model );
virtual void setRolloffFactor( F32 factor );
virtual void setDopplerFactor( F32 factor );
/// Called from the voice when its about to start playback.
void _setOutputMatrix( SFXXAudioVoice *voice );
};
#endif // _SFXXAUDIODEVICE_H_

View file

@ -1,188 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// Note: This must be defined before platform.h so that
// CoInitializeEx is properly included.
#define _WIN32_DCOM
#include <xaudio2.h>
#include "sfx/xaudio/sfxXAudioDevice.h"
#include "sfx/sfxProvider.h"
#include "core/util/safeRelease.h"
#include "core/strings/unicode.h"
#include "core/strings/stringFunctions.h"
#include "console/console.h"
#include "core/module.h"
class SFXXAudioProvider : public SFXProvider
{
public:
SFXXAudioProvider()
: SFXProvider( "XAudio" ) {}
virtual ~SFXXAudioProvider();
protected:
/// Extended SFXDeviceInfo to also store some
/// extra XAudio specific data.
struct XADeviceInfo : SFXDeviceInfo
{
UINT32 deviceIndex;
XAUDIO2_DEVICE_ROLE role;
WAVEFORMATEXTENSIBLE format;
};
/// Helper for creating the XAudio engine.
static bool _createXAudio( IXAudio2 **xaudio );
public:
// SFXProvider
void init();
SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers );
};
MODULE_BEGIN( XAudio )
MODULE_INIT_BEFORE( SFX )
MODULE_SHUTDOWN_AFTER( SFX )
SFXXAudioProvider* mProvider;
MODULE_INIT
{
mProvider = new SFXXAudioProvider;
}
MODULE_SHUTDOWN
{
delete mProvider;
}
MODULE_END;
SFXXAudioProvider::~SFXXAudioProvider()
{
}
void SFXXAudioProvider::init()
{
// Create a temp XAudio object for device enumeration.
IXAudio2 *xAudio = NULL;
if ( !_createXAudio( &xAudio ) )
{
Con::errorf( "SFXXAudioProvider::init() - XAudio2 failed to load!" );
return;
}
// Add the devices to the info list.
UINT32 count = 0;
xAudio->GetDeviceCount( &count );
for ( UINT32 i = 0; i < count; i++ )
{
XAUDIO2_DEVICE_DETAILS details;
HRESULT hr = xAudio->GetDeviceDetails( i, &details );
if ( FAILED( hr ) )
continue;
// Add a device to the info list.
XADeviceInfo* info = new XADeviceInfo;
info->deviceIndex = i;
info->driver = String( "XAudio" );
info->name = String( details.DisplayName );
info->hasHardware = false;
info->maxBuffers = 64;
info->role = details.Role;
info->format = details.OutputFormat;
mDeviceInfo.push_back( info );
}
// We're done with XAudio for now.
SAFE_RELEASE( xAudio );
// If we have no devices... we're done.
if ( mDeviceInfo.empty() )
{
Con::errorf( "SFXXAudioProvider::init() - No valid XAudio2 devices found!" );
return;
}
// If we got this far then we should be able to
// safely create a device for XAudio.
regProvider( this );
}
bool SFXXAudioProvider::_createXAudio( IXAudio2 **xaudio )
{
// In debug builds enable the debug version
// of the XAudio engine.
#ifdef TORQUE_DEBUG
#define XAUDIO_FLAGS XAUDIO2_DEBUG_ENGINE
#else
#define XAUDIO_FLAGS 0
#endif
// This must be called first... it doesn't hurt to
// call it more than once.
CoInitialize( NULL );
// Try creating the xaudio engine.
HRESULT hr = XAudio2Create( xaudio, XAUDIO_FLAGS, XAUDIO2_DEFAULT_PROCESSOR );
return SUCCEEDED( hr ) && (*xaudio);
}
SFXDevice* SFXXAudioProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
{
String devName;
devName = deviceName;
XADeviceInfo* info = dynamic_cast< XADeviceInfo* >( _findDeviceInfo( devName ) );
// Do we find one to create?
if ( info )
{
// Create the XAudio object to pass to the device.
IXAudio2 *xAudio = NULL;
if ( !_createXAudio( &xAudio ) )
{
Con::errorf( "SFXXAudioProvider::createDevice() - XAudio2 failed to load!" );
return NULL;
}
return new SFXXAudioDevice( this,
devName,
xAudio,
info->deviceIndex,
info->format.dwChannelMask,
maxBuffers );
}
// We didn't find a matching valid device.
return NULL;
}

View file

@ -1,445 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "sfx/xaudio/sfxXAudioVoice.h"
#include "sfx/xaudio/sfxXAudioDevice.h"
#include "sfx/xaudio/sfxXAudioBuffer.h"
#include "core/util/safeDelete.h"
#include "math/mMathFn.h"
//#define DEBUG_SPEW
static void sfxFormatToWAVEFORMATEX( const SFXFormat& format, WAVEFORMATEX *wfx )
{
dMemset( wfx, 0, sizeof( WAVEFORMATEX ) );
wfx->wFormatTag = WAVE_FORMAT_PCM;
wfx->nChannels = format.getChannels();
wfx->nSamplesPerSec = format.getSamplesPerSecond();
wfx->wBitsPerSample = format.getBitsPerChannel();
wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8;
wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
}
SFXXAudioVoice* SFXXAudioVoice::create( IXAudio2 *xaudio,
bool is3D,
SFXXAudioBuffer *buffer,
SFXXAudioVoice* inVoice )
{
AssertFatal( xaudio, "SFXXAudioVoice::create() - Got null XAudio!" );
AssertFatal( buffer, "SFXXAudioVoice::create() - Got null buffer!" );
// Create the voice object first as it also the callback object.
SFXXAudioVoice* voice = inVoice;
if( !voice )
voice = new SFXXAudioVoice( buffer );
// Get the buffer format.
WAVEFORMATEX wfx;
sfxFormatToWAVEFORMATEX( buffer->getFormat(), &wfx );
// We don't support multi-channel 3d sounds!
if ( is3D && wfx.nChannels > 1 )
return NULL;
// Create the voice.
IXAudio2SourceVoice *xaVoice;
HRESULT hr = xaudio->CreateSourceVoice( &xaVoice,
(WAVEFORMATEX*)&wfx,
0,
XAUDIO2_DEFAULT_FREQ_RATIO,
voice,
NULL,
NULL );
if( FAILED( hr ) || !voice )
{
if( !inVoice )
delete voice;
return NULL;
}
voice->mIs3D = is3D;
voice->mEmitter.ChannelCount = wfx.nChannels;
voice->mXAudioVoice = xaVoice;
return voice;
}
SFXXAudioVoice::SFXXAudioVoice( SFXXAudioBuffer* buffer )
: Parent( buffer ),
mXAudioDevice( NULL ),
mXAudioVoice( NULL ),
mIs3D( false ),
mPitch( 1.0f ),
mHasStopped( false ),
mHasStarted( false ),
mIsLooping( false ),
mIsPlaying( false ),
mNonStreamSampleStartPos( 0 ),
mNonStreamBufferLoaded( false ),
mSamplesPlayedOffset( 0 )
{
dMemset( &mEmitter, 0, sizeof( mEmitter ) );
mEmitter.DopplerScaler = 1.0f;
InitializeCriticalSection( &mLock );
}
SFXXAudioVoice::~SFXXAudioVoice()
{
if ( mEmitter.pVolumeCurve )
{
SAFE_DELETE_ARRAY( mEmitter.pVolumeCurve->pPoints );
SAFE_DELETE( mEmitter.pVolumeCurve );
}
SAFE_DELETE( mEmitter.pCone );
if ( mXAudioVoice )
mXAudioVoice->DestroyVoice();
DeleteCriticalSection( &mLock );
}
SFXStatus SFXXAudioVoice::_status() const
{
if( mHasStopped )
return SFXStatusStopped;
else if( mHasStarted )
{
if( !mIsPlaying )
return SFXStatusPaused;
else
return SFXStatusPlaying;
}
else
return SFXStatusStopped;
}
void SFXXAudioVoice::_flush()
{
AssertFatal( mXAudioVoice != NULL,
"SFXXAudioVoice::_flush() - invalid voice" );
EnterCriticalSection( &mLock );
mXAudioVoice->Stop( 0 );
mXAudioVoice->FlushSourceBuffers();
mNonStreamBufferLoaded = false;
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioVoice] Flushed state" );
#endif
mIsPlaying = false;
mHasStarted = false;
mHasStopped = true;
//WORKAROUND: According to the docs, SamplesPlayed reported by the
// voice should get reset as soon as we submit a new buffer to the voice.
// Alas it won't. So, save the current value here and offset our future
// play cursors.
XAUDIO2_VOICE_STATE state;
mXAudioVoice->GetState( &state );
mSamplesPlayedOffset = - S32( state.SamplesPlayed );
LeaveCriticalSection( &mLock );
}
void SFXXAudioVoice::_play()
{
AssertFatal( mXAudioVoice != NULL,
"SFXXAudioVoice::_play() - invalid voice" );
// For non-streaming voices queue the data if we haven't yet.
if( !mBuffer->isStreaming() && !mNonStreamBufferLoaded )
_loadNonStreamed();
// Start playback.
mXAudioVoice->Start( 0, 0 );
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioVoice] Started playback" );
#endif
mIsPlaying = true;
mHasStarted = true;
mHasStopped = false;
}
void SFXXAudioVoice::_pause()
{
AssertFatal( mXAudioVoice != NULL,
"SFXXAudioVoice::_pause() - invalid voice" );
mXAudioVoice->Stop( 0 );
mIsPlaying = false;
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioVoice] Paused playback" );
#endif
}
void SFXXAudioVoice::_stop()
{
AssertFatal( mXAudioVoice != NULL,
"SFXXAudioVoice::_stop() - invalid voice" );
_flush();
mIsPlaying = false;
mHasStarted = false;
mHasStopped = true;
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioVoice] Stopped playback" );
#endif
}
void SFXXAudioVoice::_seek( U32 sample )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioVoice] Seeking to %i", sample );
#endif
mNonStreamSampleStartPos = sample;
bool wasPlaying = mIsPlaying;
_stop();
if( wasPlaying )
_play();
}
void SFXXAudioVoice::_loadNonStreamed()
{
AssertFatal( !mBuffer->isStreaming(), "SFXXAudioVoice::_loadNonStreamed - must not be called on streaming voices" );
AssertFatal( mXAudioVoice != NULL, "SFXXAudioVoice::_loadNonStreamed - invalid voice" );
AssertWarn( !mNonStreamBufferLoaded, "SFXXAudioVoice::_nonStreamNonstreamed - Data already loaded" );
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[SFXXAudioVoice] Loading non-stream buffer at %i", mNonStreamSampleStartPos );
#endif
EnterCriticalSection( &mLock );
const XAUDIO2_BUFFER& orgBuffer = _getBuffer()->mBufferQueue.front().mData;
mNonStreamBuffer = orgBuffer;
if( mNonStreamSampleStartPos )
{
mNonStreamBuffer.PlayBegin = mNonStreamSampleStartPos;
mNonStreamBuffer.PlayLength = _getBuffer()->getNumSamples() - mNonStreamSampleStartPos;
mSamplesPlayedOffset += mNonStreamSampleStartPos; // Add samples that we are skipping.
mNonStreamSampleStartPos = 0;
}
if( mIsLooping )
{
mNonStreamBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
mNonStreamBuffer.LoopLength = _getBuffer()->getNumSamples();
}
// Submit buffer.
mXAudioVoice->SubmitSourceBuffer( &mNonStreamBuffer );
mNonStreamBufferLoaded = true;
LeaveCriticalSection( &mLock );
}
U32 SFXXAudioVoice::_tell() const
{
XAUDIO2_VOICE_STATE state;
mXAudioVoice->GetState( &state );
// Workaround SamplesPlayed not getting reset.
return ( state.SamplesPlayed + mSamplesPlayedOffset );
}
void SFXXAudioVoice::setMinMaxDistance( F32 min, F32 max )
{
// Set the overall volume curve scale.
mEmitter.CurveDistanceScaler = max;
// The curve uses normalized distances, so
// figure out the normalized min distance.
F32 normMin = 0.0f;
if ( min > 0.0f )
normMin = min / max;
// See what type of curve we are supposed to generate.
const bool linear = ( mXAudioDevice->mDistanceModel == SFXDistanceModelLinear );
// Have we setup the curve yet?
if( !mEmitter.pVolumeCurve
|| ( linear && mEmitter.pVolumeCurve->PointCount != 2 )
|| ( !linear && mEmitter.pVolumeCurve->PointCount != 6 ) )
{
if( !mEmitter.pVolumeCurve )
mEmitter.pVolumeCurve = new X3DAUDIO_DISTANCE_CURVE;
else
SAFE_DELETE_ARRAY( mEmitter.pVolumeCurve->pPoints );
// We use 6 points for logarithmic volume curves and 2 for linear volume curves.
if( linear )
{
mEmitter.pVolumeCurve->pPoints = new X3DAUDIO_DISTANCE_CURVE_POINT[ 2 ];
mEmitter.pVolumeCurve->PointCount = 2;
}
else
{
mEmitter.pVolumeCurve->pPoints = new X3DAUDIO_DISTANCE_CURVE_POINT[ 6 ];
mEmitter.pVolumeCurve->PointCount = 6;
}
// The first and last points are known
// and will not change.
mEmitter.pVolumeCurve->pPoints[ 0 ].Distance = 0.0f;
mEmitter.pVolumeCurve->pPoints[ 0 ].DSPSetting = 1.0f;
mEmitter.pVolumeCurve->pPoints[ linear ? 1 : 5 ].Distance = 1.0f;
mEmitter.pVolumeCurve->pPoints[ linear ? 1 : 5 ].DSPSetting = 0.0f;
}
if( !linear )
{
// Set the second point of the curve.
mEmitter.pVolumeCurve->pPoints[1].Distance = normMin;
mEmitter.pVolumeCurve->pPoints[1].DSPSetting = 1.0f;
// The next three points are calculated to
// give the sound a rough logarithmic falloff.
F32 distStep = ( 1.0f - normMin ) / 4.0f;
for ( U32 i=0; i < 3; i++ )
{
U32 index = 2 + i;
F32 dist = normMin + ( distStep * (F32)( i + 1 ) );
mEmitter.pVolumeCurve->pPoints[index].Distance = dist;
mEmitter.pVolumeCurve->pPoints[index].DSPSetting = 1.0f - log10( dist * 10.0f );
}
}
}
void SFXXAudioVoice::OnBufferEnd( void* bufferContext )
{
if( mBuffer->isStreaming() )
SFXInternal::TriggerUpdate();
}
void SFXXAudioVoice::OnStreamEnd()
{
// Warning: This is being called within the XAudio
// thread, so be sure you're thread safe!
mHasStopped = true;
if( mBuffer->isStreaming() )
SFXInternal::TriggerUpdate();
else
_stop();
}
void SFXXAudioVoice::play( bool looping )
{
// Give the device a chance to calculate our positional
// audio settings before we start playback... this is
// important else we get glitches.
if( mIs3D )
mXAudioDevice->_setOutputMatrix( this );
mIsLooping = looping;
Parent::play( looping );
}
void SFXXAudioVoice::setVelocity( const VectorF& velocity )
{
mEmitter.Velocity.x = velocity.x;
mEmitter.Velocity.y = velocity.y;
// XAudio and Torque use opposite handedness, so
// flip the z coord to account for that.
mEmitter.Velocity.z = -velocity.z;
}
void SFXXAudioVoice::setTransform( const MatrixF& transform )
{
transform.getColumn( 3, (Point3F*)&mEmitter.Position );
transform.getColumn( 1, (Point3F*)&mEmitter.OrientFront );
transform.getColumn( 2, (Point3F*)&mEmitter.OrientTop );
// XAudio and Torque use opposite handedness, so
// flip the z coord to account for that.
mEmitter.Position.z *= -1.0f;
mEmitter.OrientFront.z *= -1.0f;
mEmitter.OrientTop.z *= -1.0f;
}
void SFXXAudioVoice::setVolume( F32 volume )
{
mXAudioVoice->SetVolume( volume );
}
void SFXXAudioVoice::setPitch( F32 pitch )
{
mPitch = mClampF( pitch, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO );
mXAudioVoice->SetFrequencyRatio( mPitch );
}
void SFXXAudioVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
{
// If the cone is set to 360 then the
// cone is null and doesn't need to be
// set on the voice.
if ( mIsEqual( innerAngle, 360 ) )
{
SAFE_DELETE( mEmitter.pCone );
return;
}
if ( !mEmitter.pCone )
{
mEmitter.pCone = new X3DAUDIO_CONE;
// The inner volume is always 1... the overall
// volume is what scales it.
mEmitter.pCone->InnerVolume = 1.0f;
// We don't use these yet.
mEmitter.pCone->InnerLPF = 0.0f;
mEmitter.pCone->OuterLPF = 0.0f;
mEmitter.pCone->InnerReverb = 0.0f;
mEmitter.pCone->OuterReverb = 0.0f;
}
mEmitter.pCone->InnerAngle = mDegToRad( innerAngle );
mEmitter.pCone->OuterAngle = mDegToRad( outerAngle );
mEmitter.pCone->OuterVolume = outerVolume;
}

View file

@ -1,154 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _SFXXAUDIOVOICE_H_
#define _SFXXAUDIOVOICE_H_
#include <xaudio2.h>
#include <x3daudio.h>
#include "sfx/sfxVoice.h"
class SFXXAudioBuffer;
class SFXXAudioVoice : public SFXVoice,
public IXAudio2VoiceCallback
{
public:
typedef SFXVoice Parent;
friend class SFXXAudioDevice;
friend class SFXXAudioBuffer;
protected:
/// This constructor does not create a valid voice.
/// @see SFXXAudioVoice::create
SFXXAudioVoice( SFXXAudioBuffer* buffer );
/// The device that created us.
SFXXAudioDevice *mXAudioDevice;
/// The XAudio voice.
IXAudio2SourceVoice *mXAudioVoice;
///
CRITICAL_SECTION mLock;
/// Used to know what sounds need positional updates.
bool mIs3D;
/// Whether the voice has stopped playing.
mutable bool mHasStopped;
/// Whether we have started playback.
bool mHasStarted;
/// Whether playback is currently running.
bool mIsPlaying;
/// Whether playback is looping.
bool mIsLooping;
/// Since 3D sounds are pitch shifted for doppler
/// effect we need to track the users base pitch.
F32 mPitch;
/// The cached X3DAudio emitter data.
X3DAUDIO_EMITTER mEmitter;
/// XAudio does not reset the SamplesPlayed count as is stated in the docs. To work around
/// that, we offset the values reported by XAudio through this field.
S32 mSamplesPlayedOffset;
/// @name Data for Non-Streaming Voices
/// @{
/// Whether we have loaded our non-streaming data. We use an explicit
/// flag here as we really can't rely on XAUDIO2_VOICE_STATE.
bool mNonStreamBufferLoaded;
/// Audio buffer for non-streaming voice.
XAUDIO2_BUFFER mNonStreamBuffer;
/// Sample to start playing at when seting up #mNonStreamBuffer.
U32 mNonStreamSampleStartPos;
/// @}
// IXAudio2VoiceCallback
void STDMETHODCALLTYPE OnStreamEnd();
void STDMETHODCALLTYPE OnVoiceProcessingPassStart( UINT32 BytesRequired ) {}
void STDMETHODCALLTYPE OnVoiceProcessingPassEnd() {}
void STDMETHODCALLTYPE OnBufferEnd( void *bufferContext );
void STDMETHODCALLTYPE OnBufferStart( void *bufferContext ) {}
void STDMETHODCALLTYPE OnLoopEnd( void *bufferContext ) {}
void STDMETHODCALLTYPE OnVoiceError( void * bufferContext, HRESULT error ) {}
/// @deprecated This is only here for compatibility with
/// the March 2008 SDK version of IXAudio2VoiceCallback.
void STDMETHODCALLTYPE OnVoiceProcessingPassStart() {}
void _flush();
void _loadNonStreamed();
// SFXVoice.
virtual SFXStatus _status() const;
virtual void _play();
virtual void _pause();
virtual void _stop();
virtual void _seek( U32 sample );
virtual U32 _tell() const;
SFXXAudioBuffer* _getBuffer() const { return ( SFXXAudioBuffer* ) mBuffer.getPointer(); }
public:
///
static SFXXAudioVoice* create( IXAudio2 *xaudio,
bool is3D,
SFXXAudioBuffer *buffer,
SFXXAudioVoice* inVoice = NULL );
///
virtual ~SFXXAudioVoice();
// SFXVoice
void setMinMaxDistance( F32 min, F32 max );
void play( bool looping );
void setVelocity( const VectorF& velocity );
void setTransform( const MatrixF& transform );
void setVolume( F32 volume );
void setPitch( F32 pitch );
void setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume );
/// Is this a 3D positional voice.
bool is3D() const { return mIs3D; }
///
const X3DAUDIO_EMITTER& getEmitter() const { return mEmitter; }
};
#endif // _SFXXAUDIOVOICE_H_

View file

@ -70,9 +70,7 @@ function CoreModule::onCreate(%this)
// Init the physics plugin.
physicsInit();
sfxStartup();
// Set up networking.
setNetPort(0);

View file

@ -25,6 +25,7 @@ function createCanvas(%windowTitle)
if ($isDedicated)
{
GFXInit::createNullDevice();
sfxCreateDevice("Null","Null Device", false, 8);
return true;
}

View file

@ -3,13 +3,21 @@ function Core_SFX::onCreate(%this)
{
exec("./scripts/audio." @ $TorqueScriptFileExtension);
exec("./scripts/audioData." @ $TorqueScriptFileExtension);
exec("./scripts/audioStates." @ $TorqueScriptFileExtension);
exec("./scripts/audioEnvironments." @ $TorqueScriptFileExtension);
exec("./scripts/audioAmbience." @ $TorqueScriptFileExtension);
exec("./scripts/audioDescriptions." @ $TorqueScriptFileExtension);
exec("./scripts/audioEnvironments." @ $TorqueScriptFileExtension);
exec("./scripts/audioStates." @ $TorqueScriptFileExtension);
exec("./scripts/audioOptions." @ $TorqueScriptFileExtension);
}
function Core_SFX::onDestroy(%this)
{
}
function Core_SFX::initClient(%this)
{
if($pref::SFX::autoDetect)
{
AutodetectSound();
}
}

View file

@ -24,7 +24,11 @@
// Source groups.
//-----------------------------------------------------------------------------
singleton SFXDescription( AudioMaster );
singleton SFXDescription( AudioMaster )
{
useCustomReverb = false;
};
singleton SFXSource( AudioChannelMaster )
{
description = AudioMaster;
@ -33,8 +37,16 @@ singleton SFXSource( AudioChannelMaster )
singleton SFXDescription( AudioChannel )
{
sourceGroup = AudioChannelMaster;
useCustomReverb = false;
};
singleton SFXDescription( AudioEffectChannel )
{
sourceGroup = AudioChannelMaster;
useCustomReverb = true;
};
singleton SFXSource( AudioChannelDefault )
{
description = AudioChannel;
@ -45,7 +57,7 @@ singleton SFXSource( AudioChannelGui )
};
singleton SFXSource( AudioChannelEffects )
{
description = AudioChannel;
description = AudioEffectChannel;
};
singleton SFXSource( AudioChannelMessages )
{
@ -66,7 +78,7 @@ AudioChannelMusic.play();
AudioChannelMessages.play();
// Stop in-game effects channels.
AudioChannelEffects.stop();
AudioChannelEffects.play();
//-----------------------------------------------------------------------------
// Master SFXDescriptions.
@ -145,10 +157,6 @@ function sfxStartup()
function sfxInit()
{
// If already initialized, shut down the current device first.
if( sfxGetDeviceInfo() !$= "" )
sfxShutdown();
if ($isDedicated)
{
sfxCreateDevice("Null","Null Device", false, 8);
@ -156,12 +164,16 @@ function sfxInit()
}
// Start it up!
%maxBuffers = $pref::SFX::useHardware ? -1 : $pref::SFX::maxSoftwareBuffers;
if ( !sfxCreateDevice( $pref::SFX::provider, $pref::SFX::device, $pref::SFX::useHardware, %maxBuffers ) )
return false;
%info = sfxGetDeviceInfo();
if(%info $= "" )
{
%maxBuffers = $pref::SFX::useHardware ? -1 : $pref::SFX::maxSoftwareBuffers;
if ( !sfxCreateDevice() )
return false;
}
// This returns a tab seperated string with
// the initialized system info.
// the initialized system info
%info = sfxGetDeviceInfo();
$pref::SFX::provider = getField( %info, 0 );
$pref::SFX::device = getField( %info, 1 );
@ -440,4 +452,4 @@ function sfxResume( %pauseSet )
// Clear our pause set... the caller is left
// to clear his own if he passed one.
%pauseSet.clear();
}*/
}*/

View file

@ -23,22 +23,27 @@
singleton SFXAmbience( AudioAmbienceDefault )
{
environment = AudioEnvOff;
dopplerFactor = "1";
};
singleton SFXAmbience( AudioAmbienceOutside )
{
environment = AudioEnvPlain;
states[ 0 ] = AudioLocationOutside;
dopplerFactor = "1";
};
singleton SFXAmbience( AudioAmbienceInside )
{
environment = AudioEnvRoom;
states[ 0 ] = AudioLocationInside;
dopplerFactor = "1";
};
singleton SFXAmbience( AudioAmbienceUnderwater )
{
environment = AudioEnvUnderwater;
states[ 0 ] = AudioLocationUnderwater;
dopplerFactor = "0.5";
speedOfSound = "1500.0";
};

View file

@ -6,8 +6,8 @@ new SimGroup(AudioSettingsGroup)
new SimGroup()
{
class = "SubOptionsGroup";
displayName = "Audio Devices";
displayName = "Audio Settings";
new SimGroup(AudioSettingsProviderGroup)
{
class = "AudioOptionsSettings";
@ -15,7 +15,7 @@ new SimGroup(AudioSettingsGroup)
OptionName = "Audio Provider";
Description = "";
};
new SimGroup(AudioSettingsDeviceGroup)
{
class = "AudioOptionsSettings";
@ -26,58 +26,92 @@ new SimGroup(AudioSettingsGroup)
};
};
function getDeviceDisplayName(%fullName)
{
%openPos = strstr(%fullName, "(");
%closePos = strstr(%fullName, ")");
if (%openPos == -1 || %closePos == -1)
return %fullName;
// +1 to skip past the "(" itself
return trim(getSubStr(%fullName, %openPos + 1, %closePos - %openPos - 1));
}
function AudioSettingsGroup::populateSettings(%this)
{
AudioSettingsProviderGroup.clear();
AudioSettingsDeviceGroup.clear();
%buffer = sfxGetAvailableDevices();
%count = getRecordCount( %buffer );
%pCount = sfxGetProviderCount();
for(%i = 0; %i < %count; %i++)
// --- First pass: build deduplicated provider list ---
for (%i = 0; %i < %pCount; %i++)
{
%record = getRecord(%buffer, %i);
%provider = getField(%record, 0);
%device = getField(%record, 1);
%providerType = sfxGetProviderType(%i);
//When the client is actually running, we don't care about null audo devices
if(%provider $= "null")
if (%providerType $= "NullProvider")
continue;
//We can't have duplicate providers, so double check for uniqueness
%foundProvider = false;
foreach(%registeredProviders in AudioSettingsProviderGroup)
%alreadyAdded = false;
foreach (%entry in AudioSettingsProviderGroup)
{
if(%registeredProviders.displayName $= %provider)
if (%entry.displayName $= %providerType)
{
%foundProvider = true;
%alreadyAdded = true;
break;
}
}
if(!%foundProvider)
if (!%alreadyAdded)
{
//Provider entry
%providerEntry = new ArrayObject()
{
class = "OptionsQualityLevel";
displayName = %provider;
key["$pref::SFX::provider"] = %provider;
class = "OptionsQualityLevel";
displayName = %providerType;
key["$pref::SFX::provider"] = %providerType;
};
AudioSettingsProviderGroup.add(%providerEntry);
}
//Device Entry
%deviceEntry = new ArrayObject()
{
class = "OptionsQualityLevel";
displayName = %device;
provider = %provider; //this is for filtering later, if we need to
key["$pref::SFX::device"] = %device;
};
}
// --- Second pass: for each provider, collect its devices ---
foreach (%providerEntry in AudioSettingsProviderGroup)
{
%providerType = %providerEntry.displayName;
AudioSettingsDeviceGroup.add(%deviceEntry);
for (%i = 0; %i < %pCount; %i++)
{
if (sfxGetProviderType(%i) !$= %providerType)
continue;
%deviceName = sfxGetProviderDevice(%i);
%deviceEntry = new ArrayObject()
{
class = "OptionsQualityLevel";
displayName = getDeviceDisplayName(%deviceName);
providerType = %providerType;
key["$pref::SFX::device"] = %deviceName;
};
AudioSettingsDeviceGroup.add(%deviceEntry);
}
}
// Highlight the currently active entries
%activeProvider = $pref::SFX::provider;
%activeDevice = $pref::SFX::device;
foreach (%entry in AudioSettingsProviderGroup)
{
if (%entry.displayName $= %activeProvider)
AudioSettingsProviderGroup.currentValue = %activeProvider;
}
foreach (%entry in AudioSettingsDeviceGroup)
{
if (%entry.displayName $= %activeDevice && %entry.providerType $= %activeProvider)
AudioSettingsDeviceGroup.currentValue = %activeDevice;
}
}
@ -93,11 +127,15 @@ function AudioSettingsDeviceGroup::onApply(%this)
function updateAudioOptionsSettings()
{
if ( !sfxCreateDevice( $pref::SFX::provider,
$pref::SFX::device,
$pref::SFX::useHardware,
-1 ) )
if ( !sfxCreateDeviceFromName($pref::SFX::provider, $pref::SFX::device) )
error( "Unable to create SFX device: " @ $pref::SFX::provider
SPC $pref::SFX::device
SPC $pref::SFX::useHardware );
}
function AutodetectSound()
{
// Nothing to actually do in here?
// function here for convenience.
$pref::SFX::autoDetect = false;
}

View file

@ -223,7 +223,6 @@ function OptionsMenu::openOptionsCategory(%this, %categoryName)
else if(%categoryName $= "Audio")
{
$MenuList = AudioSettingsList;
%this.currentCatgeoryIdx = 1;
}
else if(%categoryName $= "KBM")
@ -856,6 +855,8 @@ function OptionsMenu::resetSettings(%this)
function OptionsMenu::populateAudioSettings(%this)
{
AudioSettingsList.clear();
OptionsMenu.optsListCount = -1;
AudioSettingsGroup.populateSettings();
//Process the lists

View file

@ -12,6 +12,53 @@ function SoundAsset::onChanged(%this)
if (isObject($PreviewSoundSource))
sfxStop($PreviewSoundSource);
}
function SoundAsset::onShowActionMenu(%this)
{
GenericAsset::onShowActionMenu(%this);
%assetId = %this.getAssetId();
EditAssetPopup.objectData = %assetId;
EditAssetPopup.objectType = AssetDatabase.getAssetType(%assetId);
EditAssetPopup.reloadItems();
EditAssetPopup.showPopup(Canvas);
}
function SoundAsset::onEditProperties(%this)
{
Canvas.pushDialog(AssetBrowser_editAsset);
AssetBrowser_editAssetWindow.text = "Asset Properties - " @ %this.getAssetId();
AssetEditInspector.tempAsset = %this.deepClone();
AssetEditInspector.inspect(%this);
AssetBrowser_editAsset.editedObjectData = %this.getAssetId();
AssetBrowser_editAsset.editedObject = %this;
AssetBrowser_editAsset.editedObjectType = AssetDatabase.getAssetType(%this.getAssetId());
//remove some of the groups we don't need:
for(%i=0; %i < AssetEditInspector.getCount(); %i++)
{
%caption = AssetEditInspector.getObject(%i).caption;
if(%caption $= "Ungrouped" || %caption $= "Object" || %caption $= "Editing"
|| %caption $= "Persistence" || %caption $= "Dynamic Fields")
{
AssetEditInspector.remove(AssetEditInspector.getObject(%i));
%i--;
}
}
}
//Called when the AssetType has it's properties saved from the onEditProperties process
function SoundAsset::onSaveProperties(%this)
{
%this.refreshAsset();
}
function SoundAsset::buildBrowserElement(%this, %previewData)
{

View file

@ -1,8 +0,0 @@
# OpenAL module
option(TORQUE_SFX_DIRECTX "Use DirectSound SFX" OFF)
if(TORQUE_SFX_DIRECTX AND WIN32)
message("Enabling DirectSound Module")
torqueAddSourceDirectories("${CMAKE_SOURCE_DIR}/Engine/source/sfx/dsound" "${CMAKE_SOURCE_DIR}/Engine/source/sfx/xaudio")
endif(TORQUE_SFX_DIRECTX AND WIN32)