diff --git a/vita3k/modules/SceNgsUser/SceNgs.cpp b/vita3k/modules/SceNgsUser/SceNgs.cpp index 892d341a15..86df7f06f4 100644 --- a/vita3k/modules/SceNgsUser/SceNgs.cpp +++ b/vita3k/modules/SceNgsUser/SceNgs.cpp @@ -17,8 +17,6 @@ #include -#include "../SceProcessmgr/SceProcessmgr.h" - #include #include #include @@ -91,87 +89,21 @@ enum SceNgsVoiceInitFlag { static constexpr uint32_t SCE_NGS_SAMPLE_OFFSET_FROM_AT9_HEADER = 1 << 31; -EXPORT(int, sceNgsAT9GetSectionDetails, uint32_t samples_start, const uint32_t num_samples, uint32_t config_data, SceNgsAT9SkipBufferInfo *info) { +EXPORT(int, sceNgsAT9GetSectionDetails, uint32_t samples_start, const uint32_t num_samples, const uint32_t config_data, SceNgsAT9SkipBufferInfo *info) { TRACY_FUNC(sceNgsAT9GetSectionDetails, samples_start, num_samples, config_data, info); - if (!emuenv.cfg.current_config.ngs_enable) + if (!emuenv.cfg.current_config.ngs_enable) { return -1; - - if (!info) + } + if (!info) { return RET_ERROR(SCE_NGS_ERROR_INVALID_ARG); - + } // Check magic! - if ((config_data & 0xFF) != 0xFE) - return RET_ERROR(SCE_NGS_ERROR); - - // the following content is reverse engineered - const uint8_t sample_rate_index = ((config_data & (0b1111 << 12)) >> 12); - const uint32_t frame_bytes = ((((config_data & 0xFF0000) >> 16) << 3) | ((config_data & (0b111 << 29)) >> 29)) + 1; - - int nb_samples_per_frame; - if (sample_rate_index == 1) - nb_samples_per_frame = 64; - else if (sample_rate_index == 4) - nb_samples_per_frame = 128; - else if (sample_rate_index == 7) - nb_samples_per_frame = 256; - else + if ((config_data & 0xFF) != 0xFE) { return RET_ERROR(SCE_NGS_ERROR); - - const bool is_superframe = static_cast(config_data & (0b11 << 27)); - - // SCE_NGS_SAMPLE_OFFSET_FROM_AT9_HEADER was added in sdk 3.36 - const int sdk_version = CALL_EXPORT(sceKernelGetMainModuleSdkVersion); - const bool is_sdk_recent = sdk_version >= (336 << 16); - - if (is_sdk_recent && (samples_start & SCE_NGS_SAMPLE_OFFSET_FROM_AT9_HEADER)) { - samples_start &= ~SCE_NGS_SAMPLE_OFFSET_FROM_AT9_HEADER; - - // remove nb_samples_per_frame from it - samples_start = (samples_start > nb_samples_per_frame) ? (samples_start - nb_samples_per_frame) : 0; - } - - info->is_super_packet = static_cast(is_superframe); - if (is_superframe) { - // there are 4 frames per superframe - const int superframe_bytes = frame_bytes * 4; - const int nb_samples_per_superframe = nb_samples_per_frame * 4; - - samples_start += nb_samples_per_frame; - if (is_sdk_recent) - samples_start += nb_samples_per_frame; - - const int superframes_offset = samples_start / nb_samples_per_superframe; - - info->start_byte_offset = superframes_offset * superframe_bytes; - - const int start_skip_samples = samples_start - superframes_offset * nb_samples_per_superframe; - info->start_skip = static_cast(start_skip_samples); - - const int total_superframes = (start_skip_samples + num_samples + nb_samples_per_superframe - 1) / nb_samples_per_superframe; - const int total_bytes_read = (total_superframes - superframes_offset) * superframe_bytes; - info->num_bytes = total_bytes_read; - - info->end_skip = static_cast(total_superframes * nb_samples_per_superframe - (samples_start + num_samples)); - - // some special case, make sure to put a good amound of skipped samples - if (start_skip_samples < nb_samples_per_frame && superframes_offset > 0) { - // transfer one superframe into the skipped samples - info->start_byte_offset -= superframe_bytes; - info->start_skip += nb_samples_per_superframe; - info->num_bytes += superframe_bytes; - } - } else { - const int frames_offset = samples_start / nb_samples_per_frame; - info->start_byte_offset = frames_offset * frame_bytes; - // a frame is always added to skip - const int start_skip_samples = (samples_start + nb_samples_per_frame) - frames_offset * nb_samples_per_frame; - info->start_skip = static_cast(start_skip_samples); - - const int total_frames = (start_skip_samples + num_samples + nb_samples_per_frame - 1) / nb_samples_per_frame; - info->num_bytes = total_frames * frame_bytes; - - info->end_skip = static_cast(total_frames * nb_samples_per_frame - (start_skip_samples + num_samples)); } + samples_start &= ~SCE_NGS_SAMPLE_OFFSET_FROM_AT9_HEADER; + + ngs::atrac9_get_buffer_parameter(samples_start, num_samples, config_data, *info); return 0; } diff --git a/vita3k/ngs/include/ngs/system.h b/vita3k/ngs/include/ngs/system.h index 2480ccb786..ee821eebca 100644 --- a/vita3k/ngs/include/ngs/system.h +++ b/vita3k/ngs/include/ngs/system.h @@ -227,4 +227,6 @@ void voice_definition_init(State &ngs, MemState &mem); Ptr get_voice_definition(State &ngs, MemState &mem, ngs::BussType type); void apply_voice_definition(VoiceDefinition *definition, std::vector> &mods); uint32_t get_voice_definition_size(VoiceDefinition *definition); + +void atrac9_get_buffer_parameter(uint32_t start_sample, uint32_t num_samples, uint32_t info, SceNgsAT9SkipBufferInfo ¶meter); } // namespace ngs diff --git a/vita3k/ngs/src/modules/atrac9.cpp b/vita3k/ngs/src/modules/atrac9.cpp index 380d8a464f..52e6579fab 100644 --- a/vita3k/ngs/src/modules/atrac9.cpp +++ b/vita3k/ngs/src/modules/atrac9.cpp @@ -28,6 +28,34 @@ namespace ngs { SwrContext *Atrac9Module::swr_mono_to_stereo = nullptr; SwrContext *Atrac9Module::swr_stereo = nullptr; +void atrac9_get_buffer_parameter(const uint32_t start_sample, const uint32_t num_samples, const uint32_t info, SceNgsAT9SkipBufferInfo ¶meter) { + const uint8_t sample_rate_index = ((info & (0b1111 << 12)) >> 12); + const uint8_t block_rate_index = ((info & (0b111 << 9)) >> 9); + const uint16_t frame_bytes = ((((info & 0xFF0000) >> 16) << 3) | ((info & (0b111 << 29)) >> 29)) + 1; + const uint8_t superframe_index = (info & (0b11 << 27)) >> 27; + + // Calculate bytes per superframe. + const uint32_t frame_per_superframe = 1 << superframe_index; + const uint32_t bytes_per_superframe = frame_bytes * frame_per_superframe; + + // Calculate total superframe + static const int8_t sample_rate_index_to_frame_sample_power[] = { + 6, 6, 7, 7, 7, 8, 8, 8, 6, 6, 7, 7, 7, 8, 8, 8 + }; + + const uint32_t samples_per_frame = 1 << sample_rate_index_to_frame_sample_power[sample_rate_index]; + const uint32_t samples_per_superframe = samples_per_frame * frame_per_superframe; + + const uint32_t start_superframe = (start_sample / samples_per_superframe); + const uint32_t num_superframe = (start_sample + num_samples + samples_per_superframe - 1) / samples_per_superframe - start_superframe; + + parameter.num_bytes = num_superframe * bytes_per_superframe; + parameter.is_super_packet = (frame_per_superframe == 1) ? 0 : 1; + parameter.start_byte_offset = start_superframe * bytes_per_superframe; + parameter.start_skip = (start_sample - (start_superframe * samples_per_superframe)); + parameter.end_skip = (start_superframe + num_superframe) * samples_per_superframe - (start_sample + num_samples); +} + void Atrac9Module::on_state_change(const MemState &mem, ModuleData &data, const VoiceState previous) { SceNgsAT9States *state = data.get_state(); if (data.parent->state == VOICE_STATE_ACTIVE && previous == VOICE_STATE_AVAILABLE) {