Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/RE/IDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ namespace RE::ID
inline constexpr REL::ID GetEventSource{ 100427 }; // 151162
}

// Statically-linked Wwise 2021.1 AK::SoundEngine entry points (no exported symbols).
namespace AkSoundEngine
{
inline constexpr REL::ID GetIDFromString{ 150371 };
inline constexpr REL::ID PostEvent{ 150391 };
inline constexpr REL::ID PostEventByName{ 150393 };
inline constexpr REL::ID LoadBank{ 150389 };
inline constexpr REL::ID LoadBankByID{ 150388 };
inline constexpr REL::ID UnloadBank{ 150434 };
inline constexpr REL::ID SetPosition{ 150420 };
}


namespace AttachReference::Event
{
inline constexpr REL::ID GetEventSource{ 0 }; // 778826
Expand Down
1 change: 1 addition & 0 deletions include/RE/Starfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,5 +482,6 @@
#include "RE/V/VirtualMachine.h"
#include "RE/W/WritableStringTable.h"
#include "RE/W/WritableTypeTable.h"
#include "RE/W/WwiseExternalSource.h"
#include "RE/W/WwiseGUID.h"
#include "RE/W/WwiseSoundHook.h"
144 changes: 144 additions & 0 deletions include/RE/W/WwiseExternalSource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#pragma once

//statically linked so no RTTI

namespace RE::BGSAudio
{
// Wwise 2021.1 codec IDs (AkCodecID). The engine's default external-source is kVorbis (voice .wem are Vorbis).
// File/encoding types of Audiokinetic. Pulled from AkTypes.h of wwise sdk 2021.1.14
enum class AkCodecID : std::uint32_t
{
kBank = 0,
kPCM = 1,
kADPCM = 2,
kXMA = 3,
kVorbis = 4,
kWiiADPCM = 5,
kPCMEX = 7,
kExternalSource = 8,
kXWMA = 9,
kAAC = 10,
kFilePackage = 11,
kATRAC9 = 12,
kVAG = 13,
kProfilerCapture = 14,
kAnalysisFile = 15,
kMIDI = 16,
kOpusNX = 17,
kCAF = 18,
kAkOpus = 20,
kAkOpusWem = 20,
kAkMemoryMgrDump = 21,
};

// hash of "External_Source" - the cookie engine uses for its own VO posts.
inline constexpr std::uint32_t kExternalSourceCookie = 0x24DB9834;

//AkExternalSourceInfo from wwise 2021.1.
struct AkExternalSourceInfo
{
std::uint32_t iExternalSrcCookie; /// 00 - Cookie identifying the source, given by hashing the name of the source given in the project.
std::uint32_t idCodec; /// 04 - Codec ID for the file. One of the audio formats defined in AkCodecID
wchar_t* szFile; /// 08 - File path for the source. If not NULL, the source will be streaming from disk. Set pInMemory to NULL. If idFile is set, this field is used as stream name (for profiling purposes).
void* pInMemory; /// 10 - Pointer to the in-memory file. If not NULL, the source will be read from memory. Set szFile and idFile to NULL.
std::uint32_t uiMemorySize; /// 18 - Size of the data pointed by pInMemory
std::uint32_t idFile; /// 1C - File ID. If not zero, the source will be streaming from disk. This ID can be anything.
};
static_assert(sizeof(AkExternalSourceInfo) == 0x20);

// Wwise 2021.1 3D vector (AkTypes.h).
struct AkVector
{
float X;
float Y;
float Z;
};
static_assert(sizeof(AkVector) == 0x0C);

// Wwise 2021.1 AkSoundPosition (== AkTransform, AkTypes.h). Param of SetPosition.
struct AkSoundPosition
{
AkVector orientationFront; // 00 - must be normalized
AkVector orientationTop; // 0C - must be normalized, orthogonal to front
AkVector position; // 18
};
static_assert(sizeof(AkSoundPosition) == 0x24);



//Thin binding over wwise AK::SoundEngine entry points.
//Posted events ride game mix (volume, pause, ducking, etc...) for "free"
class AkSoundEngine
{
public:
using AkUniqueID = std::uint32_t;
using AkGameObjectID = std::uint64_t;
using AkPlayingID = std::uint32_t;
using AkBankID = std::uint32_t;
using AKRESULT = std::uint32_t; // AK_Success == 1

// The player TESObjectREFR is the engine special case: AkGameObjectID 2
//Positioned 3d audio resolve via WwiseGameObjectMgr::GetOrCreateGameObjectId
static constexpr AkGameObjectID kPlayerGameObject = 2;
static constexpr AKRESULT kAkSuccess = 1;

// Lets you resolve a custom event name with no WWED Form
static AkUniqueID GetIDFromString(const char* a_name)
{
using func_t = decltype(&AkSoundEngine::GetIDFromString);
static REL::Relocation<func_t> func{ ID::AkSoundEngine::GetIDFromString };
return func(a_name);
}

// PostEvent from wwise. To play pass in_cExternals=1 and
// in_pExternalSources pointing at an AkExternalSourceInfo whose iExternalSrcCookie matches a placeholder in in_eventID.
// Returns AkPlayingID (0 = rejected — usually a_event not in any loadedd bank, or no matching external-source slot).
// Enqueue-only and should be safe to call from any thread.
static AkPlayingID PostEvent(
AkUniqueID in_eventID, ///< Unique ID of the event
AkGameObjectID in_gameObjectID, ///< Associated game object ID
std::uint32_t in_uFlags = 0, ///< Bitmask: see \ref AkCallbackType
void* in_pfnCallback = nullptr, ///< Callback function
void * in_pCookie = nullptr, ///< Callback cookie that will be sent to the callback function along with additional information
std::uint32_t in_cExternals = 0, ///< Optional count of external source structures
AkExternalSourceInfo *in_pExternalSources = nullptr, ///< Optional array of external source resolution information
AkPlayingID in_PlayingID = 0 ///< Optional (advanced users only) Specify the playing ID to target with the event.
)
{
using func_t = decltype(&AkSoundEngine::PostEvent);
static REL::Relocation<func_t> func{ ID::AkSoundEngine::PostEvent };
return func(in_eventID, in_gameObjectID, in_uFlags, in_pfnCallback, in_pCookie, in_cExternals, in_pExternalSources, in_PlayingID);
}

// Load a SoundBank by name. The engine appends ".bnk" and resolves it
static AKRESULT LoadBank(const char* a_name, AkBankID& a_outBankID)
{
using func_t = decltype(&AkSoundEngine::LoadBank);
static REL::Relocation<func_t> func{ ID::AkSoundEngine::LoadBank };
return func(a_name, a_outBankID);
}

// Unloads a SoundBank by name. a_inMemoryBankPtr must be the pointer the
// bank was loaded from, or nullptr for name/file-loaded banks (our case).
// NOTE: this build has NO memory-load (LoadBankMemoryView) overload — it was
// dead-code-eliminated — so a mod bank is always name/file-loaded, and this
// is the matching unload. Returns AKRESULT (kAkSuccess == 1). AddrLib 150434.

//unload a sound bank. a_inMemoryBankPtr must be the pointer bank loaded from, or nullptr for name/file-loaded banks
//Pretty sure banks are always name/file-loaded
static AKRESULT UnloadBank(const char* a_name, const void* a_inMemoryBankPtr = nullptr)
{
using func_t = decltype(&AkSoundEngine::UnloadBank);
static REL::Relocation<func_t> func{ ID::AkSoundEngine::UnloadBank };
return func(a_name, a_inMemoryBankPtr);
}

//Sets a registered game object's 3D position/orientationa so its spacialized.
static AKRESULT SetPosition(AkGameObjectID a_gameObject, const AkSoundPosition& a_position)
{
using func_t = decltype(&AkSoundEngine::SetPosition);
static REL::Relocation<func_t> func{ ID::AkSoundEngine::SetPosition };
return func(a_gameObject, a_position);
}
};
}
Loading