Repository navigation
Expand file tree
/
Copy pathSystem.cpp
More file actions
256 lines (225 loc) · 10.2 KB
/
Copy pathSystem.cpp
File metadata and controls
256 lines (225 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <memory>
#include <mutex>
#include <new>
#include <stdexcept>
#include <string>
#include <vector>
#include "prx/libc/include/General.hpp"
#include "Ngs2Internal.hpp"
static std::vector<Ngs2System*>& Systems() {
static auto* const systems = new std::vector<Ngs2System*>();
return *systems;
}
std::string Ngs2Hex(std::uint32_t value) {
char text[16];
std::snprintf(text, sizeof(text), "0x%x", value);
return text;
}
std::recursive_mutex& Ngs2Mutex() {
static auto* const mutex = new std::recursive_mutex();
return *mutex;
}
Ngs2System* Ngs2FindSystem(Ngs2Handle handle) {
auto& systems = Systems();
const auto found = std::find(systems.begin(), systems.end(), reinterpret_cast<Ngs2System*>(handle));
return found == systems.end() ? nullptr : *found;
}
Ngs2Rack* Ngs2FindRack(Ngs2Handle handle) {
for (auto* system : Systems()) {
for (auto* rack : system->racks) {
if (reinterpret_cast<Ngs2Handle>(rack) == handle) return rack;
}
}
return nullptr;
}
Ngs2Voice* Ngs2FindVoice(Ngs2Handle handle) {
for (auto* system : Systems()) {
for (auto* rack : system->racks) {
for (auto& voice : rack->voices) {
if (reinterpret_cast<Ngs2Handle>(&voice) == handle) return &voice;
}
}
}
return nullptr;
}
void* Ngs2Place(const Ngs2ContextBufferInfo* bufferInfo, std::size_t size, std::size_t alignment) {
if (bufferInfo == nullptr || bufferInfo->host_buffer == nullptr || bufferInfo->host_buffer_size < size) {
throw std::invalid_argument("NGS2: the context buffer is missing or smaller than the queried size");
}
if (reinterpret_cast<std::uintptr_t>(bufferInfo->host_buffer) % alignment != 0) {
throw std::invalid_argument("NGS2: the context buffer is not aligned to " + std::to_string(alignment) + " bytes");
}
return bufferInfo->host_buffer;
}
int Ngs2ReleaseBuffer(const Ngs2BufferAllocator& allocator, Ngs2ContextBufferInfo bufferInfo, Ngs2ContextBufferInfo* outBufferInfo) {
if (outBufferInfo != nullptr) *outBufferInfo = allocator.free_handler == nullptr ? bufferInfo : Ngs2ContextBufferInfo{};
return allocator.free_handler == nullptr ? SCE_NGS2_OK : allocator.free_handler(&bufferInfo);
}
static Ngs2ContextBufferInfo Allocate(const Ngs2BufferAllocator* allocator, std::size_t size) {
if (allocator == nullptr || allocator->alloc_handler == nullptr || allocator->free_handler == nullptr) APS5_INVALID_ARG_EX;
Ngs2ContextBufferInfo bufferInfo{};
bufferInfo.host_buffer_size = size;
bufferInfo.user_data = allocator->user_data;
const int result = allocator->alloc_handler(&bufferInfo);
if (result != SCE_NGS2_OK) throw std::runtime_error("NGS2: the allocator handler failed with " + std::to_string(result));
return bufferInfo;
}
static Ngs2SystemOption DefaultSystemOption() {
Ngs2SystemOption option{};
option.size = sizeof(Ngs2SystemOption);
option.max_grain_samples = 512;
option.num_grain_samples = 256;
option.sample_rate = 48000;
return option;
}
static Ngs2SystemOption CheckedSystemOption(const Ngs2SystemOption* option) {
if (option == nullptr) return DefaultSystemOption();
if (option->size != sizeof(Ngs2SystemOption)) throw std::invalid_argument("NGS2: unexpected system option size " + std::to_string(option->size));
if (option->flags != 0) throw std::runtime_error("NGS2: system option flags are not implemented");
if (option->sample_rate == 0 || option->max_grain_samples < MIN_GRAIN_SAMPLES || option->num_grain_samples == 0 ||
option->num_grain_samples > option->max_grain_samples) {
throw std::invalid_argument("NGS2: invalid system grain or sample rate");
}
return *option;
}
static int CreateSystem(const Ngs2SystemOption& option, const Ngs2ContextBufferInfo& bufferInfo, const Ngs2BufferAllocator& allocator, Ngs2Handle* handle) {
static std::uint32_t nextUid = 1;
auto* system = new (Ngs2Place(&bufferInfo, sizeof(Ngs2System), alignof(Ngs2System))) Ngs2System{};
system->option = option;
system->bufferInfo = bufferInfo;
system->allocator = allocator;
system->uid = nextUid++;
Systems().push_back(system);
*handle = reinterpret_cast<Ngs2Handle>(system);
return SCE_NGS2_OK;
}
#pragma GCC visibility push(default)
extern "C" {
int APS5_VABI sceNgs2SystemQueryBufferSize(const Ngs2SystemOption* option, Ngs2ContextBufferInfo* buffer_info) {
if (buffer_info == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
CheckedSystemOption(option);
*buffer_info = {};
buffer_info->host_buffer_size = sizeof(Ngs2System);
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemCreate(const Ngs2SystemOption* option, const Ngs2ContextBufferInfo* buffer_info, uintptr_t* handle) {
if (handle == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
const auto checked = CheckedSystemOption(option);
if (buffer_info == nullptr) APS5_INVALID_ARG_EX;
std::lock_guard lock(Ngs2Mutex());
return CreateSystem(checked, *buffer_info, {}, handle);
}
int APS5_VABI sceNgs2SystemCreateWithAllocator(const Ngs2SystemOption* option, const Ngs2BufferAllocator* allocator, uintptr_t* handle) {
if (handle == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
const auto checked = CheckedSystemOption(option);
const auto bufferInfo = Allocate(allocator, sizeof(Ngs2System));
std::lock_guard lock(Ngs2Mutex());
return CreateSystem(checked, bufferInfo, *allocator, handle);
}
int APS5_VABI sceNgs2SystemDestroy(uintptr_t system_handle, Ngs2ContextBufferInfo* buffer_info) {
std::lock_guard lock(Ngs2Mutex());
if (buffer_info != nullptr) *buffer_info = {};
auto* system = Ngs2FindSystem(system_handle);
if (system == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
while (!system->racks.empty()) {
const int result = Ngs2DestroyRack(*system->racks.back(), nullptr);
if (result != SCE_NGS2_OK) return result;
}
std::erase(Systems(), system);
const auto bufferInfo = system->bufferInfo;
const auto allocator = system->allocator;
std::destroy_at(system);
return Ngs2ReleaseBuffer(allocator, bufferInfo, buffer_info);
}
int APS5_VABI sceNgs2SystemGetInfo(uintptr_t system_handle, Ngs2SystemInfo* info, size_t info_size) {
if (info == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
if (info_size != sizeof(Ngs2SystemInfo)) return SCE_NGS2_ERROR_INVALID_OUT_SIZE;
std::lock_guard lock(Ngs2Mutex());
const auto* system = Ngs2FindSystem(system_handle);
if (system == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
*info = {};
std::memcpy(info->name, system->option.name, sizeof(info->name));
info->system_handle = system_handle;
info->buffer_info = system->bufferInfo;
info->uid = system->uid;
info->min_grain_samples = MIN_GRAIN_SAMPLES;
info->max_grain_samples = system->option.max_grain_samples;
info->state_flags = 1;
info->rack_count = static_cast<std::uint32_t>(system->racks.size());
info->render_count = system->renderCount;
info->sample_rate = system->option.sample_rate;
info->num_grain_samples = system->option.num_grain_samples;
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemSetGrainSamples(uintptr_t system_handle, uint32_t num_samples) {
std::lock_guard lock(Ngs2Mutex());
auto* system = Ngs2FindSystem(system_handle);
if (system == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
if (num_samples == 0 || num_samples > system->option.max_grain_samples) APS5_INVALID_ARG_EX;
system->option.num_grain_samples = num_samples;
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemSetSampleRate(uintptr_t system_handle, uint32_t sample_rate) {
std::lock_guard lock(Ngs2Mutex());
auto* system = Ngs2FindSystem(system_handle);
if (system == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
if (sample_rate == 0) APS5_INVALID_ARG_EX;
for (const auto* rack : system->racks) {
for (const auto& voice : rack->voices) {
for (const auto& filter : voice.filters) {
if (filter.enabled && sample_rate != system->option.sample_rate) {
throw std::runtime_error("NGS2: changing the sample rate under an enabled sampler filter is not implemented");
}
}
}
}
system->option.sample_rate = sample_rate;
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemSetUserData(uintptr_t system_handle, uintptr_t user_data) {
std::lock_guard lock(Ngs2Mutex());
auto* system = Ngs2FindSystem(system_handle);
if (system == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
system->userData = user_data;
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemGetUserData(uintptr_t system_handle, uintptr_t* user_data) {
std::lock_guard lock(Ngs2Mutex());
const auto* system = Ngs2FindSystem(system_handle);
if (system == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
if (user_data == nullptr) APS5_INVALID_ARG_EX;
*user_data = system->userData;
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemLock(uintptr_t system_handle) {
Ngs2Mutex().lock();
if (Ngs2FindSystem(system_handle) != nullptr) return SCE_NGS2_OK;
Ngs2Mutex().unlock();
return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
int APS5_VABI sceNgs2SystemUnlock(uintptr_t system_handle) {
std::lock_guard lock(Ngs2Mutex());
if (Ngs2FindSystem(system_handle) == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
Ngs2Mutex().unlock();
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemRender(uintptr_t system_handle, const Ngs2RenderBufferInfo* buffer_info, uint32_t num_buffer_info) {
std::lock_guard lock(Ngs2Mutex());
auto* system = Ngs2FindSystem(system_handle);
if (system == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
if (buffer_info == nullptr || num_buffer_info == 0) APS5_INVALID_ARG_EX;
Ngs2RenderSystem(*system, buffer_info, num_buffer_info);
return SCE_NGS2_OK;
}
int APS5_VABI sceNgs2SystemResetOption(Ngs2SystemOption* option) {
if (option == nullptr) APS5_INVALID_ARG_EX;
*option = DefaultSystemOption();
return SCE_NGS2_OK;
}
}
#pragma GCC visibility pop