mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-08 21:24:34 +00:00
Merge pull request #1730 from marauder2k9-torque/SFXSystem-Refactor
Sfx system refactor
This commit is contained in:
commit
dae2a7714f
66 changed files with 3710 additions and 7727 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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())\
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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) )
|
||||
|
||||
|
|
@ -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) );
|
||||
}
|
||||
|
|
@ -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_
|
||||
|
|
@ -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.
|
||||
}
|
||||
|
|
@ -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_
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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!" );
|
||||
}
|
||||
|
|
@ -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_
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
176
Engine/source/sfx/openal/LoadOAL.cpp
Normal file
176
Engine/source/sfx/openal/LoadOAL.cpp
Normal 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);
|
||||
}
|
||||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 ] );
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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_
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_
|
||||
|
|
@ -70,9 +70,7 @@ function CoreModule::onCreate(%this)
|
|||
|
||||
// Init the physics plugin.
|
||||
physicsInit();
|
||||
|
||||
sfxStartup();
|
||||
|
||||
|
||||
// Set up networking.
|
||||
setNetPort(0);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ function createCanvas(%windowTitle)
|
|||
if ($isDedicated)
|
||||
{
|
||||
GFXInit::createNullDevice();
|
||||
sfxCreateDevice("Null","Null Device", false, 8);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}*/
|
||||
}*/
|
||||
|
|
@ -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";
|
||||
};
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue