Skip to content
Merged
2 changes: 1 addition & 1 deletion core/libs/prx/libSceNgs2.native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ if(BUILD_TESTING)
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNgs2.native>")
endif()
endforeach()
foreach(ngs2Test IN ITEMS Render Atrac9 Filter Custom Gain Routing PitchShift JobControl JobBuffer JobFx Activation Threads Detached Sampler Parse Stream UserFx Report Geom VoiceIndex HandleErrors VoiceHandles VoiceEvents)
foreach(ngs2Test IN ITEMS Render Atrac9 Filter Custom CustomReverb Gain Routing PitchShift JobControl JobBuffer JobFx Activation Threads Detached Sampler Parse Stream UserFx Report Geom VoiceIndex HandleErrors VoiceHandles VoiceEvents)
string(TOLOWER ${ngs2Test} testName)
add_test_executable(ngs2_${testName}_tests ${CMAKE_CURRENT_SOURCE_DIR}/tests/Ngs2${ngs2Test}.cpp)
target_include_directories(ngs2_${testName}_tests PRIVATE ${LIBS_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/3rdparty/LibAtrac9/C/src)
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceNgs2.native/include/Ngs2Types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ static constexpr std::uint32_t SCE_NGS2_CUSTOM_MASTERING_VOICE_PARAM_SETUP = 0x4
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MASTERING_VOICE_PARAM_GAIN = 0x40030004;
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MASTERING_VOICE_PARAM_OUTPUT = 0x40030005;
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_FILTER = 0x40001300;
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_REVERB = 0x40001b00;
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN = 0x40001500;
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_USER_FX = 0x40001900;
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_DELAY = 0x40001d00;
Expand Down
25 changes: 24 additions & 1 deletion core/libs/prx/libSceNgs2.native/src/Custom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ int Ngs2CheckCustomRack(std::uint32_t rackId, const Ngs2CustomRackOption& option
for (std::uint32_t m = 0; m < option.num_modules; m++) {
const auto moduleId = option.module[m].module_id;
if (moduleId == SCE_NGS2_CUSTOM_MODULE_ID_GAIN && option.module[m].option != nullptr) throw std::runtime_error("NGS2: an option for the custom Gain module is not implemented");
if (moduleId == SCE_NGS2_CUSTOM_MODULE_ID_REVERB) continue;
if (moduleId == SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT) continue;
if (moduleId == SCE_NGS2_CUSTOM_MODULE_ID_GAIN) continue;
const char* name = BuiltInModuleName(moduleId);
Expand Down Expand Up @@ -132,6 +133,7 @@ int Ngs2SetupUserFx(Ngs2Rack& rack, const Ngs2CustomRackOption& option) {
voice.userFx.resize(option.num_modules);
voice.customUserFx.resize(option.num_modules);
voice.customGain.assign(option.num_modules, {});
voice.customReverb.resize(option.num_modules);
if (hasPitchShift) voice.customPitchShift.resize(option.num_modules);
}
for (std::uint32_t m = 0; m < option.num_modules; m++) {
Expand All @@ -142,6 +144,11 @@ int Ngs2SetupUserFx(Ngs2Rack& rack, const Ngs2CustomRackOption& option) {
rack.customModuleOptions[m].assign(data, data + info.option->size);
}
rack.customModules[m] = {info.module_id, info.source_buffer_id, info.extra_buffer_id, info.dest_buffer_id, info.state_offset, info.state_size, 0, 0};
if (info.module_id == SCE_NGS2_CUSTOM_MODULE_ID_REVERB) {
const auto size = info.option == nullptr ? 1u : OptionWord(*info.option);
for (auto& voice : rack.voices) voice.customReverb[m] = Ngs2CreateCustomReverb(size);
continue;
}
if (option.module[m].module_id == SCE_NGS2_CUSTOM_MODULE_ID_FILTER) continue;
if (option.module[m].module_id == SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT) {
for (auto& voice : rack.voices) voice.customPitchShift[m].channels.resize(rack.maxChannels);
Expand Down Expand Up @@ -212,7 +219,10 @@ static void SetupCustomSubmixer(Ngs2Voice& voice, const Ngs2CustomSubmixerVoiceS
if (setup.num_input_channels != setup.num_output_channels) throw std::runtime_error("NGS2: custom submixer channel conversion is not implemented");
if (setup.num_input_channels == 0 || setup.num_input_channels > voice.rack->maxChannels || setup.num_input_channels > NGS2_MAX_CHANNELS) APS5_INVALID_ARG_EX;
if (Ngs2HasPitchShift(voice)) voice.ResetSetup();
else Ngs2ResetUserFx2(voice);
else {
Ngs2ResetUserFx2(voice);
Ngs2ResetCustomReverb(voice);
}
for (auto& gain : voice.customGain) if (gain.configured) gain.lifecycleUnknown = true;
++voice.waveformRevision;
voice.channels = setup.num_input_channels;
Expand Down Expand Up @@ -366,6 +376,15 @@ void Ngs2ApplyCustomParam(Ngs2Voice& voice, const Ngs2VoiceParamHeader& param) {
Ngs2SetFilter(voice, filter);
return;
}
if ((param.id & ~0xffu) == SCE_NGS2_CUSTOM_VOICE_PARAM_REVERB) {
if (rackId != SCE_NGS2_RACK_ID_CUSTOM_SAMPLER && rackId != SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) {
throw std::invalid_argument("NGS2: voice param " + Ngs2Hex(param.id) + " belongs to another rack");
}
const auto index = param.id & 0x1f;
if (index >= voice.customReverb.size() || !voice.customReverb[index]) APS5_INVALID_ARG_EX;
Ngs2SetCustomReverbParams(voice.customReverb[index], ParamAs<Ngs2ReverbVoiceI3DL2Param>(param).i3dl2);
return;
}
if ((param.id & ~0x1fu) == SCE_NGS2_CUSTOM_VOICE_PARAM_USER_FX2) {
if (rackId != SCE_NGS2_RACK_ID_CUSTOM_SAMPLER && rackId != SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) {
throw std::invalid_argument("NGS2: voice param " + Ngs2Hex(param.id) + " belongs to another rack");
Expand Down Expand Up @@ -395,6 +414,10 @@ void Ngs2ProcessUserFx(Ngs2Voice& voice, std::uint32_t grain, std::uint32_t samp
std::vector<float*> channels(voice.channels);
for (std::uint32_t c = 0; c < voice.channels; c++) channels[c] = voice.samples.data() + static_cast<std::size_t>(c) * grain;
for (std::size_t m = 0; m < voice.rack->customModuleIds.size(); m++) {
if (voice.rack->customModuleIds[m] == SCE_NGS2_CUSTOM_MODULE_ID_REVERB) {
voice.hasSamples = Ngs2ProcessCustomReverb(voice, m, grain, sampleRate);
continue;
}
if (voice.rack->customModuleIds[m] == SCE_NGS2_CUSTOM_MODULE_ID_DELAY) continue;
if (voice.rack->customModuleIds[m] == SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT) {
Ngs2ProcessPitchShift(voice, m, grain);
Expand Down
10 changes: 9 additions & 1 deletion core/libs/prx/libSceNgs2.native/src/Ngs2Internal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ struct Ngs2ReverbDeleter {
void operator()(Ngs2ReverbState* reverb) const;
};

using Ngs2Reverb = std::unique_ptr<Ngs2ReverbState, Ngs2ReverbDeleter>;

struct Ngs2Voice;

struct Ngs2ReturnCode {
Expand Down Expand Up @@ -167,7 +169,8 @@ struct Ngs2Voice {
std::uint32_t sampleRate = 0;
std::uint32_t waveformType = 0;
Ngs2Atrac9 atrac9;
std::unique_ptr<Ngs2ReverbState, Ngs2ReverbDeleter> reverb;
Ngs2Reverb reverb;
std::vector<Ngs2Reverb> customReverb;
float pitch = 1.0f;
std::uint64_t phase = 0;
std::array<std::array<float, 4>, NGS2_MAX_CHANNELS> samplerHistory{};
Expand Down Expand Up @@ -376,7 +379,12 @@ void Ngs2ApplyCustomParam(Ngs2Voice& voice, const Ngs2VoiceParamHeader& param);
void Ngs2ProcessUserFx(Ngs2Voice& voice, std::uint32_t grain, std::uint32_t sampleRate);
void Ngs2SetReverbParams(Ngs2Voice& voice, const Ngs2ReverbI3DL2Param& params);
void Ngs2SetupReverb(Ngs2Voice& voice);
Ngs2Reverb Ngs2CreateCustomReverb(std::uint32_t size);
void Ngs2SetCustomReverbParams(Ngs2Reverb& reverb, const Ngs2ReverbI3DL2Param& params);
bool Ngs2ProcessCustomReverb(Ngs2Voice& voice, std::size_t module, std::uint32_t grain, std::uint32_t sampleRate);
void Ngs2ClearReverb(Ngs2Voice& voice);
void Ngs2ClearCustomReverb(Ngs2Voice& voice);
void Ngs2ResetCustomReverb(Ngs2Voice& voice);
bool Ngs2ProcessReverb(Ngs2Voice& voice, std::uint32_t grain, std::uint32_t sampleRate);
void Ngs2ProcessLegacyUserFx(Ngs2Voice& voice, std::uint32_t grain, std::uint32_t sampleRate);
void Ngs2PublishSamplerState(Ngs2Voice& voice);
Expand Down
Loading
Loading