Skip to content
Closed
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
35 changes: 35 additions & 0 deletions core/libs/prx/libSceAudioPropagation/AudioPropagation.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef CORE_LIBS_PRX_LIBSCEAUDIOPROPAGATION_AUDIOPROPAGATION_HPP
#define CORE_LIBS_PRX_LIBSCEAUDIOPROPAGATION_AUDIOPROPAGATION_HPP

#include <array>
#include <cstddef>
#include <cstdint>

Expand All @@ -23,6 +24,39 @@ inline constexpr std::size_t PortalParamsSize = 0x60;
inline constexpr std::uint32_t PathEntryId = 0x010107d9;
inline constexpr std::size_t PathEntrySize = 0x28;

inline constexpr std::uint32_t MaxPaths = 36;
inline constexpr std::uint32_t MaxPathPoints = 4;
inline constexpr std::uint32_t PathId = 0x010107d3;
inline constexpr std::uint32_t PathPointId = 0x010107d2;
inline constexpr std::uint32_t PathInvalid = 1;
inline constexpr std::uint32_t PathPortal = 2;

struct Vector3 {
float x;
float y;
float z;
std::uint32_t pad;
};

struct PathPoint {
AudioPropagationStructDescriptor desc;
AudioPropagationHandle material;
float gain;
Vector3 position;
};

struct AudioPath {
AudioPropagationStructDescriptor desc;
std::array<PathPoint, MaxPathPoints> points;
std::uint32_t numPoints;
std::uint32_t flags;
std::uint32_t pad;
};

static_assert(sizeof(Vector3) == 0x10);
static_assert(sizeof(PathPoint) == 0x30 && offsetof(PathPoint, position) == 0x1c);
static_assert(sizeof(AudioPath) == 0xe0 && offsetof(AudioPath, numPoints) == 0xd0);

struct Attribute {
std::uint32_t id;
std::uint32_t reserved0;
Expand Down Expand Up @@ -78,6 +112,7 @@ std::int32_t APS5_VABI sceAudioPropagationSourceDestroy(AudioPropagationHandle s
std::int32_t APS5_VABI sceAudioPropagationSourceSetAttributes(AudioPropagationHandle source, const AudioPropagation::Attribute* attributes, std::uint32_t count);
std::int32_t APS5_VABI sceAudioPropagationSourceGetAudioPathCount(AudioPropagationHandle source, std::uint32_t* count);
std::int32_t APS5_VABI sceAudioPropagationSourceGetAudioPath(AudioPropagationHandle source, std::uint32_t index, AudioPropagationHandle* outPath);
std::int32_t APS5_VABI sceAudioPropagationPathGetNumPoints(AudioPropagationHandle path, std::uint32_t* count);
std::int32_t APS5_VABI sceAudioPropagationSourceGetRays(AudioPropagationHandle source, void* rays, std::uint32_t* count);
std::int32_t APS5_VABI sceAudioPropagationSourceCalculateAudioPaths(AudioPropagationHandle source, const void* rays, std::uint32_t rayCount, std::uint32_t flags, void* paths, std::uint32_t pathCount);
std::int32_t APS5_VABI sceAudioPropagationSourceSetAudioPaths(AudioPropagationHandle source, const void* entries, std::uint32_t count);
Expand Down
97 changes: 85 additions & 12 deletions core/libs/prx/libSceAudioPropagation/Export.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "AudioPropagation.hpp"

#include <cmath>
#include <cstdint>
#include <cstring>
#include <mutex>
Expand All @@ -24,18 +25,25 @@ struct SystemState {
std::uint64_t reserved;
};

enum class Kind { Room, Portal, Source, Material };
enum class Kind { Room, Portal, Source, Material, Path };

struct Object {
Kind kind;
AudioPropagationHandle system;
};

struct PathState {
AudioPath data{};
float gain = 0.0f;
};

struct Registry {
std::mutex mutex;
std::unordered_set<AudioPropagationHandle> systems;
std::unordered_map<AudioPropagationHandle, Object> objects;
std::unordered_map<AudioPropagationHandle, Object> orphans;
std::unordered_map<AudioPropagationHandle, std::array<AudioPropagationHandle, MaxPaths>> sourcePaths;
std::unordered_map<AudioPropagationHandle, PathState> paths;
AudioPropagationHandle next = 1;
};

Expand Down Expand Up @@ -98,6 +106,13 @@ void destroyObject(AudioPropagationHandle system, AudioPropagationHandle handle,
return;
}
require(requireObject(state, handle, kind, function).system == system, function);
if (kind == Kind::Source) {
for (const auto path : state.sourcePaths.at(handle)) {
state.paths.erase(path);
state.objects.erase(path);
}
state.sourcePaths.erase(handle);
}
state.objects.erase(handle);
}

Expand Down Expand Up @@ -140,9 +155,11 @@ std::int32_t APS5_VABI sceAudioPropagationSystemDestroy(AudioPropagationHandle s
auto& state = registry();
std::lock_guard lock(state.mutex);
requireSystem(state, system, __func__);
std::erase_if(state.paths, [&](const auto& entry) { return state.objects.at(entry.first).system == system; });
std::erase_if(state.sourcePaths, [&](const auto& entry) { return state.objects.at(entry.first).system == system; });
std::erase_if(state.objects, [&](const auto& entry) {
if (entry.second.system != system) return false;
state.orphans.insert(entry);
if (entry.second.kind != Kind::Path) state.orphans.insert(entry);
return true;
});
reinterpret_cast<SystemState*>(system)->magic = 0;
Expand Down Expand Up @@ -228,7 +245,30 @@ std::int32_t APS5_VABI sceAudioPropagationPortalSetAttributes(AudioPropagationHa
}

std::int32_t APS5_VABI sceAudioPropagationSourceCreate(AudioPropagationHandle system, AudioPropagationHandle* outSource) {
createObject(system, Kind::Source, outSource, __func__);
require(outSource != nullptr, __func__);
auto& state = registry();
std::lock_guard lock(state.mutex);
AudioPropagationHandle source = 0;
createObjectLocked(state, system, Kind::Source, &source, __func__);
std::array<AudioPropagationHandle, MaxPaths> handles{};
try {
for (auto& handle : handles) {
createObjectLocked(state, system, Kind::Path, &handle, __func__);
PathState path{};
path.data.desc = {PathId, sizeof(AudioPath)};
path.data.flags = PathInvalid;
state.paths.emplace(handle, path);
}
state.sourcePaths.emplace(source, handles);
} catch (...) {
for (const auto handle : handles) {
state.paths.erase(handle);
state.objects.erase(handle);
}
state.objects.erase(source);
throw;
}
*outSource = source;
return 0;
}

Expand All @@ -250,16 +290,26 @@ std::int32_t APS5_VABI sceAudioPropagationSourceGetAudioPathCount(AudioPropagati
std::lock_guard lock(state.mutex);
requireObject(state, source, Kind::Source, __func__);
require(count != nullptr, __func__);
*count = 0;
*count = MaxPaths;
return 0;
}

std::int32_t APS5_VABI sceAudioPropagationSourceGetAudioPath(AudioPropagationHandle source, std::uint32_t index, AudioPropagationHandle* outPath) {
auto& state = registry();
std::lock_guard lock(state.mutex);
requireObject(state, source, Kind::Source, __func__);
static_cast<void>(outPath);
throw std::invalid_argument(std::string(__func__) + ": index " + std::to_string(index) + " out of range (0 audio paths)");
require(outPath != nullptr && index < MaxPaths, __func__);
*outPath = state.sourcePaths.at(source)[index];
return 0;
}

std::int32_t APS5_VABI sceAudioPropagationPathGetNumPoints(AudioPropagationHandle path, std::uint32_t* count) {
auto& state = registry();
std::lock_guard lock(state.mutex);
requireObject(state, path, Kind::Path, __func__);
require(count != nullptr, __func__);
*count = state.paths.at(path).data.numPoints;
return 0;
}

std::int32_t APS5_VABI sceAudioPropagationSourceGetRays(AudioPropagationHandle source, void* rays, std::uint32_t* count) {
Expand Down Expand Up @@ -292,10 +342,19 @@ std::int32_t APS5_VABI sceAudioPropagationSourceSetAudioPaths(AudioPropagationHa
}

std::int32_t APS5_VABI sceAudioPropagationSourceSetAudioPath(AudioPropagationHandle path, const void* data, float gain) {
static_cast<void>(path);
static_cast<void>(data);
static_cast<void>(gain);
NotImplemented_nid_no_patch(__func__);
auto& state = registry();
std::lock_guard lock(state.mutex);
const auto system = requireObject(state, path, Kind::Path, __func__).system;
requireDescriptor(data != nullptr ? &static_cast<const AudioPath*>(data)->desc : nullptr, PathId, sizeof(AudioPath), __func__);
const auto replacement = *static_cast<const AudioPath*>(data);
require(std::isfinite(gain) && gain >= 0.0f && replacement.numPoints <= MaxPathPoints && (replacement.flags & ~(PathInvalid | PathPortal)) == 0 && replacement.pad == 0, __func__);
for (std::uint32_t index = 0; index < replacement.numPoints; ++index) {
const auto& point = replacement.points[index];
requireDescriptor(&point.desc, PathPointId, sizeof(PathPoint), __func__);
require(std::isfinite(point.gain) && point.gain >= 0.0f && std::isfinite(point.position.x) && std::isfinite(point.position.y) && std::isfinite(point.position.z) && point.position.pad == 0, __func__);
if (point.material != 0) require(requireObject(state, point.material, Kind::Material, __func__).system == system, __func__);
}
state.paths.at(path) = PathState{replacement, gain};
return 0;
}

Expand All @@ -309,9 +368,23 @@ std::int32_t APS5_VABI sceAudioPropagationSourceRender(AudioPropagationHandle sy
requireDescriptor(&info.desc, RenderInfoId, RenderInfoSize, __func__);
require(requireObject(state, info.source, Kind::Source, __func__).system == system, __func__);
require(info.output != nullptr && info.outputSize != 0, __func__);
if (info.format != RenderFormat) throw std::runtime_error(std::string(__func__) + ": render format " + std::to_string(info.format) + " is unknown");
std::uint32_t channels = 0;
switch (info.format) {
case 0: channels = 4; break;
case 1: channels = 9; break;
case 2: channels = 16; break;
case 4:
case 5: channels = 8; break;
default: throw std::runtime_error(std::string(__func__) + ": render format " + std::to_string(info.format) + " is unknown");
}
require(info.outputSize % (channels * sizeof(float)) == 0, __func__);
for (const auto handle : state.sourcePaths.at(info.source)) {
const auto& path = state.paths.at(handle);
if (path.gain > 0.0f && path.data.numPoints != 0 && (path.data.flags & PathInvalid) == 0) {
throw std::runtime_error(std::string(__func__) + ": nonempty audio path rendering is not implemented");
}
}
}
for (std::uint32_t index = 0; index < count; ++index) std::memset(infos[index].output, 0, infos[index].outputSize);
return 0;
}

Expand Down
Loading
Loading