Compare commits
2 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78b9956a04 | ||
|
|
90aa937593 |
5
.git-blame-ignore-revs
Normal file
5
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# CRLF -> LF
|
||||
90aa937593e53a5d5e070fb623b228578b0b225f
|
||||
@@ -1,107 +1,107 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_decode_object.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
namespace AudioCore::ADSP::OpusDecoder {
|
||||
namespace {
|
||||
bool IsValidChannelCount(u32 channel_count) {
|
||||
return channel_count == 1 || channel_count == 2;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) {
|
||||
if (!IsValidChannelCount(channel_count)) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
|
||||
}
|
||||
|
||||
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
||||
auto* new_decoder = reinterpret_cast<OpusDecodeObject*>(buffer);
|
||||
auto* comparison = reinterpret_cast<OpusDecodeObject*>(buffer2);
|
||||
|
||||
if (new_decoder->magic == DecodeObjectMagic) {
|
||||
if (!new_decoder->initialized ||
|
||||
(new_decoder->initialized && new_decoder->self == comparison)) {
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
} else {
|
||||
new_decoder->initialized = false;
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
return *new_decoder;
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::InitializeDecoder(u32 sample_rate, u32 channel_count) {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
// Unfortunately libopus does not expose the OpusDecoder struct publicly, so we can't include
|
||||
// it in this class. Nintendo does not allocate memory, which is why we have a workbuffer
|
||||
// provided.
|
||||
// We could use _create and have libopus allocate it for us, but then we have to separately
|
||||
// track which decoder is being used between this and multistream in order to call the correct
|
||||
// destroy from the host side.
|
||||
// This is a bit cringe, but is safe as these objects are only ever initialized inside the given
|
||||
// workbuffer, and GetWorkBufferSize will guarantee there's enough space to follow.
|
||||
decoder = (LibOpusDecoder*)(this + 1);
|
||||
s32 ret = opus_decoder_init(decoder, sample_rate, channel_count);
|
||||
if (ret == OPUS_OK) {
|
||||
magic = DecodeObjectMagic;
|
||||
initialized = true;
|
||||
state_valid = true;
|
||||
self = this;
|
||||
final_range = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::Shutdown() {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
magic = 0x0;
|
||||
initialized = false;
|
||||
state_valid = false;
|
||||
self = nullptr;
|
||||
final_range = 0;
|
||||
decoder = nullptr;
|
||||
}
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::ResetDecoder() {
|
||||
return opus_decoder_ctl(decoder, OPUS_RESET_STATE);
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::Decode(u32& out_sample_count, u64 output_data, u64 output_data_size,
|
||||
u64 input_data, u64 input_data_size) {
|
||||
ASSERT(initialized);
|
||||
out_sample_count = 0;
|
||||
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
auto ret_code_or_samples = opus_decode(
|
||||
decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size),
|
||||
reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0);
|
||||
|
||||
if (ret_code_or_samples < OPUS_OK) {
|
||||
return ret_code_or_samples;
|
||||
}
|
||||
|
||||
out_sample_count = ret_code_or_samples;
|
||||
return opus_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::ADSP::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_decode_object.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
namespace AudioCore::ADSP::OpusDecoder {
|
||||
namespace {
|
||||
bool IsValidChannelCount(u32 channel_count) {
|
||||
return channel_count == 1 || channel_count == 2;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) {
|
||||
if (!IsValidChannelCount(channel_count)) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count);
|
||||
}
|
||||
|
||||
OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
||||
auto* new_decoder = reinterpret_cast<OpusDecodeObject*>(buffer);
|
||||
auto* comparison = reinterpret_cast<OpusDecodeObject*>(buffer2);
|
||||
|
||||
if (new_decoder->magic == DecodeObjectMagic) {
|
||||
if (!new_decoder->initialized ||
|
||||
(new_decoder->initialized && new_decoder->self == comparison)) {
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
} else {
|
||||
new_decoder->initialized = false;
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
return *new_decoder;
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::InitializeDecoder(u32 sample_rate, u32 channel_count) {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
// Unfortunately libopus does not expose the OpusDecoder struct publicly, so we can't include
|
||||
// it in this class. Nintendo does not allocate memory, which is why we have a workbuffer
|
||||
// provided.
|
||||
// We could use _create and have libopus allocate it for us, but then we have to separately
|
||||
// track which decoder is being used between this and multistream in order to call the correct
|
||||
// destroy from the host side.
|
||||
// This is a bit cringe, but is safe as these objects are only ever initialized inside the given
|
||||
// workbuffer, and GetWorkBufferSize will guarantee there's enough space to follow.
|
||||
decoder = (LibOpusDecoder*)(this + 1);
|
||||
s32 ret = opus_decoder_init(decoder, sample_rate, channel_count);
|
||||
if (ret == OPUS_OK) {
|
||||
magic = DecodeObjectMagic;
|
||||
initialized = true;
|
||||
state_valid = true;
|
||||
self = this;
|
||||
final_range = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::Shutdown() {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
magic = 0x0;
|
||||
initialized = false;
|
||||
state_valid = false;
|
||||
self = nullptr;
|
||||
final_range = 0;
|
||||
decoder = nullptr;
|
||||
}
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::ResetDecoder() {
|
||||
return opus_decoder_ctl(decoder, OPUS_RESET_STATE);
|
||||
}
|
||||
|
||||
s32 OpusDecodeObject::Decode(u32& out_sample_count, u64 output_data, u64 output_data_size,
|
||||
u64 input_data, u64 input_data_size) {
|
||||
ASSERT(initialized);
|
||||
out_sample_count = 0;
|
||||
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
auto ret_code_or_samples = opus_decode(
|
||||
decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size),
|
||||
reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0);
|
||||
|
||||
if (ret_code_or_samples < OPUS_OK) {
|
||||
return ret_code_or_samples;
|
||||
}
|
||||
|
||||
out_sample_count = ret_code_or_samples;
|
||||
return opus_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::ADSP::OpusDecoder
|
||||
|
||||
@@ -1,111 +1,111 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_multistream_decode_object.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
namespace AudioCore::ADSP::OpusDecoder {
|
||||
|
||||
namespace {
|
||||
bool IsValidChannelCount(u32 channel_count) {
|
||||
return channel_count == 1 || channel_count == 2;
|
||||
}
|
||||
|
||||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
||||
return total_stream_count > 0 && stereo_stream_count > 0 &&
|
||||
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
u32 OpusMultiStreamDecodeObject::GetWorkBufferSize(u32 total_stream_count,
|
||||
u32 stereo_stream_count) {
|
||||
if (IsValidStreamCounts(total_stream_count, stereo_stream_count)) {
|
||||
return static_cast<u32>(sizeof(OpusMultiStreamDecodeObject)) +
|
||||
opus_multistream_decoder_get_size(total_stream_count, stereo_stream_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
OpusMultiStreamDecodeObject& OpusMultiStreamDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
||||
auto* new_decoder = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer);
|
||||
auto* comparison = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer2);
|
||||
|
||||
if (new_decoder->magic == DecodeMultiStreamObjectMagic) {
|
||||
if (!new_decoder->initialized ||
|
||||
(new_decoder->initialized && new_decoder->self == comparison)) {
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
} else {
|
||||
new_decoder->initialized = false;
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
return *new_decoder;
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::InitializeDecoder(u32 sample_rate, u32 total_stream_count,
|
||||
u32 channel_count, u32 stereo_stream_count,
|
||||
u8* mappings) {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
// See OpusDecodeObject::InitializeDecoder for an explanation of this
|
||||
decoder = (LibOpusMSDecoder*)(this + 1);
|
||||
s32 ret = opus_multistream_decoder_init(decoder, sample_rate, channel_count, total_stream_count,
|
||||
stereo_stream_count, mappings);
|
||||
if (ret == OPUS_OK) {
|
||||
magic = DecodeMultiStreamObjectMagic;
|
||||
initialized = true;
|
||||
state_valid = true;
|
||||
self = this;
|
||||
final_range = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::Shutdown() {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
magic = 0x0;
|
||||
initialized = false;
|
||||
state_valid = false;
|
||||
self = nullptr;
|
||||
final_range = 0;
|
||||
decoder = nullptr;
|
||||
}
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::ResetDecoder() {
|
||||
return opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE);
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::Decode(u32& out_sample_count, u64 output_data,
|
||||
u64 output_data_size, u64 input_data, u64 input_data_size) {
|
||||
ASSERT(initialized);
|
||||
out_sample_count = 0;
|
||||
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
auto ret_code_or_samples = opus_multistream_decode(
|
||||
decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size),
|
||||
reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0);
|
||||
|
||||
if (ret_code_or_samples < OPUS_OK) {
|
||||
return ret_code_or_samples;
|
||||
}
|
||||
|
||||
out_sample_count = ret_code_or_samples;
|
||||
return opus_multistream_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::ADSP::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_multistream_decode_object.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
namespace AudioCore::ADSP::OpusDecoder {
|
||||
|
||||
namespace {
|
||||
bool IsValidChannelCount(u32 channel_count) {
|
||||
return channel_count == 1 || channel_count == 2;
|
||||
}
|
||||
|
||||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
||||
return total_stream_count > 0 && stereo_stream_count > 0 &&
|
||||
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
u32 OpusMultiStreamDecodeObject::GetWorkBufferSize(u32 total_stream_count,
|
||||
u32 stereo_stream_count) {
|
||||
if (IsValidStreamCounts(total_stream_count, stereo_stream_count)) {
|
||||
return static_cast<u32>(sizeof(OpusMultiStreamDecodeObject)) +
|
||||
opus_multistream_decoder_get_size(total_stream_count, stereo_stream_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
OpusMultiStreamDecodeObject& OpusMultiStreamDecodeObject::Initialize(u64 buffer, u64 buffer2) {
|
||||
auto* new_decoder = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer);
|
||||
auto* comparison = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer2);
|
||||
|
||||
if (new_decoder->magic == DecodeMultiStreamObjectMagic) {
|
||||
if (!new_decoder->initialized ||
|
||||
(new_decoder->initialized && new_decoder->self == comparison)) {
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
} else {
|
||||
new_decoder->initialized = false;
|
||||
new_decoder->state_valid = true;
|
||||
}
|
||||
return *new_decoder;
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::InitializeDecoder(u32 sample_rate, u32 total_stream_count,
|
||||
u32 channel_count, u32 stereo_stream_count,
|
||||
u8* mappings) {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
// See OpusDecodeObject::InitializeDecoder for an explanation of this
|
||||
decoder = (LibOpusMSDecoder*)(this + 1);
|
||||
s32 ret = opus_multistream_decoder_init(decoder, sample_rate, channel_count, total_stream_count,
|
||||
stereo_stream_count, mappings);
|
||||
if (ret == OPUS_OK) {
|
||||
magic = DecodeMultiStreamObjectMagic;
|
||||
initialized = true;
|
||||
state_valid = true;
|
||||
self = this;
|
||||
final_range = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::Shutdown() {
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
magic = 0x0;
|
||||
initialized = false;
|
||||
state_valid = false;
|
||||
self = nullptr;
|
||||
final_range = 0;
|
||||
decoder = nullptr;
|
||||
}
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::ResetDecoder() {
|
||||
return opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE);
|
||||
}
|
||||
|
||||
s32 OpusMultiStreamDecodeObject::Decode(u32& out_sample_count, u64 output_data,
|
||||
u64 output_data_size, u64 input_data, u64 input_data_size) {
|
||||
ASSERT(initialized);
|
||||
out_sample_count = 0;
|
||||
|
||||
if (!state_valid) {
|
||||
return OPUS_INVALID_STATE;
|
||||
}
|
||||
|
||||
auto ret_code_or_samples = opus_multistream_decode(
|
||||
decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size),
|
||||
reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0);
|
||||
|
||||
if (ret_code_or_samples < OPUS_OK) {
|
||||
return ret_code_or_samples;
|
||||
}
|
||||
|
||||
out_sample_count = ret_code_or_samples;
|
||||
return opus_multistream_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::ADSP::OpusDecoder
|
||||
|
||||
@@ -1,179 +1,179 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/opus/decoder.h"
|
||||
#include "audio_core/opus/hardware_opus.h"
|
||||
#include "audio_core/opus/parameters.h"
|
||||
#include "common/alignment.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
using namespace Service::Audio;
|
||||
namespace {
|
||||
OpusPacketHeader ReverseHeader(OpusPacketHeader header) {
|
||||
OpusPacketHeader out;
|
||||
out.size = Common::swap32(header.size);
|
||||
out.final_range = Common::swap32(header.final_range);
|
||||
return out;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_)
|
||||
: system{system_}, hardware_opus{hardware_opus_} {}
|
||||
|
||||
OpusDecoder::~OpusDecoder() {
|
||||
if (decode_object_initialized) {
|
||||
hardware_opus.ShutdownDecodeObject(shared_buffer.get(), shared_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||
u64 transfer_memory_size) {
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
shared_buffer_size = transfer_memory_size;
|
||||
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
|
||||
shared_memory_mapped = true;
|
||||
|
||||
buffer_size =
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
|
||||
|
||||
out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
|
||||
size_t in_data_size{0x600u};
|
||||
in_data = {out_data.data() - in_data_size, in_data_size};
|
||||
|
||||
ON_RESULT_FAILURE {
|
||||
if (shared_memory_mapped) {
|
||||
shared_memory_mapped = false;
|
||||
ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
|
||||
}
|
||||
};
|
||||
|
||||
R_TRY(hardware_opus.InitializeDecodeObject(params.sample_rate, params.channel_count,
|
||||
shared_buffer.get(), shared_buffer_size));
|
||||
|
||||
sample_rate = params.sample_rate;
|
||||
channel_count = params.channel_count;
|
||||
use_large_frame_size = params.use_large_frame_size;
|
||||
decode_object_initialized = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
|
||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
shared_buffer_size = transfer_memory_size;
|
||||
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
|
||||
shared_memory_mapped = true;
|
||||
|
||||
buffer_size =
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
|
||||
|
||||
out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
|
||||
size_t in_data_size{Common::AlignUp(1500ull * params.total_stream_count, 64u)};
|
||||
in_data = {out_data.data() - in_data_size, in_data_size};
|
||||
|
||||
ON_RESULT_FAILURE {
|
||||
if (shared_memory_mapped) {
|
||||
shared_memory_mapped = false;
|
||||
ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
|
||||
}
|
||||
};
|
||||
|
||||
R_TRY(hardware_opus.InitializeMultiStreamDecodeObject(
|
||||
params.sample_rate, params.channel_count, params.total_stream_count,
|
||||
params.stereo_stream_count, params.mappings.data(), shared_buffer.get(),
|
||||
shared_buffer_size));
|
||||
|
||||
sample_rate = params.sample_rate;
|
||||
channel_count = params.channel_count;
|
||||
total_stream_count = params.total_stream_count;
|
||||
stereo_stream_count = params.stereo_stream_count;
|
||||
use_large_frame_size = params.use_large_frame_size;
|
||||
decode_object_initialized = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoder::DecodeInterleaved(u32* out_data_size, u64* out_time_taken,
|
||||
u32* out_sample_count, std::span<const u8> input_data,
|
||||
std::span<u8> output_data, bool reset) {
|
||||
u32 out_samples;
|
||||
u64 time_taken{};
|
||||
|
||||
R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
|
||||
|
||||
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
||||
OpusPacketHeader header{ReverseHeader(*header_p)};
|
||||
|
||||
R_UNLESS(in_data.size_bytes() >= header.size &&
|
||||
header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
|
||||
ResultBufferTooSmall);
|
||||
|
||||
if (!shared_memory_mapped) {
|
||||
R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
|
||||
shared_memory_mapped = true;
|
||||
}
|
||||
|
||||
std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
|
||||
|
||||
R_TRY(hardware_opus.DecodeInterleaved(out_samples, out_data.data(), out_data.size_bytes(),
|
||||
channel_count, in_data.data(), header.size,
|
||||
shared_buffer.get(), time_taken, reset));
|
||||
|
||||
std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
|
||||
|
||||
*out_data_size = header.size + sizeof(OpusPacketHeader);
|
||||
*out_sample_count = out_samples;
|
||||
if (out_time_taken) {
|
||||
*out_time_taken = time_taken / 1000;
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoder::SetContext([[maybe_unused]] std::span<const u8> context) {
|
||||
R_SUCCEED_IF(shared_memory_mapped);
|
||||
shared_memory_mapped = true;
|
||||
R_RETURN(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
|
||||
}
|
||||
|
||||
Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken,
|
||||
u32* out_sample_count,
|
||||
std::span<const u8> input_data,
|
||||
std::span<u8> output_data, bool reset) {
|
||||
u32 out_samples;
|
||||
u64 time_taken{};
|
||||
|
||||
R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
|
||||
|
||||
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
||||
OpusPacketHeader header{ReverseHeader(*header_p)};
|
||||
|
||||
LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
||||
header.size, input_data.size_bytes(), in_data.size_bytes());
|
||||
|
||||
R_UNLESS(in_data.size_bytes() >= header.size &&
|
||||
header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
|
||||
ResultBufferTooSmall);
|
||||
|
||||
if (!shared_memory_mapped) {
|
||||
R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
|
||||
shared_memory_mapped = true;
|
||||
}
|
||||
|
||||
std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
|
||||
|
||||
R_TRY(hardware_opus.DecodeInterleavedForMultiStream(
|
||||
out_samples, out_data.data(), out_data.size_bytes(), channel_count, in_data.data(),
|
||||
header.size, shared_buffer.get(), time_taken, reset));
|
||||
|
||||
std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
|
||||
|
||||
*out_data_size = header.size + sizeof(OpusPacketHeader);
|
||||
*out_sample_count = out_samples;
|
||||
if (out_time_taken) {
|
||||
*out_time_taken = time_taken / 1000;
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/opus/decoder.h"
|
||||
#include "audio_core/opus/hardware_opus.h"
|
||||
#include "audio_core/opus/parameters.h"
|
||||
#include "common/alignment.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
using namespace Service::Audio;
|
||||
namespace {
|
||||
OpusPacketHeader ReverseHeader(OpusPacketHeader header) {
|
||||
OpusPacketHeader out;
|
||||
out.size = Common::swap32(header.size);
|
||||
out.final_range = Common::swap32(header.final_range);
|
||||
return out;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_)
|
||||
: system{system_}, hardware_opus{hardware_opus_} {}
|
||||
|
||||
OpusDecoder::~OpusDecoder() {
|
||||
if (decode_object_initialized) {
|
||||
hardware_opus.ShutdownDecodeObject(shared_buffer.get(), shared_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||
u64 transfer_memory_size) {
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
shared_buffer_size = transfer_memory_size;
|
||||
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
|
||||
shared_memory_mapped = true;
|
||||
|
||||
buffer_size =
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
|
||||
|
||||
out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
|
||||
size_t in_data_size{0x600u};
|
||||
in_data = {out_data.data() - in_data_size, in_data_size};
|
||||
|
||||
ON_RESULT_FAILURE {
|
||||
if (shared_memory_mapped) {
|
||||
shared_memory_mapped = false;
|
||||
ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
|
||||
}
|
||||
};
|
||||
|
||||
R_TRY(hardware_opus.InitializeDecodeObject(params.sample_rate, params.channel_count,
|
||||
shared_buffer.get(), shared_buffer_size));
|
||||
|
||||
sample_rate = params.sample_rate;
|
||||
channel_count = params.channel_count;
|
||||
use_large_frame_size = params.use_large_frame_size;
|
||||
decode_object_initialized = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
|
||||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
shared_buffer_size = transfer_memory_size;
|
||||
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
|
||||
shared_memory_mapped = true;
|
||||
|
||||
buffer_size =
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
|
||||
|
||||
out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
|
||||
size_t in_data_size{Common::AlignUp(1500ull * params.total_stream_count, 64u)};
|
||||
in_data = {out_data.data() - in_data_size, in_data_size};
|
||||
|
||||
ON_RESULT_FAILURE {
|
||||
if (shared_memory_mapped) {
|
||||
shared_memory_mapped = false;
|
||||
ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
|
||||
}
|
||||
};
|
||||
|
||||
R_TRY(hardware_opus.InitializeMultiStreamDecodeObject(
|
||||
params.sample_rate, params.channel_count, params.total_stream_count,
|
||||
params.stereo_stream_count, params.mappings.data(), shared_buffer.get(),
|
||||
shared_buffer_size));
|
||||
|
||||
sample_rate = params.sample_rate;
|
||||
channel_count = params.channel_count;
|
||||
total_stream_count = params.total_stream_count;
|
||||
stereo_stream_count = params.stereo_stream_count;
|
||||
use_large_frame_size = params.use_large_frame_size;
|
||||
decode_object_initialized = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoder::DecodeInterleaved(u32* out_data_size, u64* out_time_taken,
|
||||
u32* out_sample_count, std::span<const u8> input_data,
|
||||
std::span<u8> output_data, bool reset) {
|
||||
u32 out_samples;
|
||||
u64 time_taken{};
|
||||
|
||||
R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
|
||||
|
||||
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
||||
OpusPacketHeader header{ReverseHeader(*header_p)};
|
||||
|
||||
R_UNLESS(in_data.size_bytes() >= header.size &&
|
||||
header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
|
||||
ResultBufferTooSmall);
|
||||
|
||||
if (!shared_memory_mapped) {
|
||||
R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
|
||||
shared_memory_mapped = true;
|
||||
}
|
||||
|
||||
std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
|
||||
|
||||
R_TRY(hardware_opus.DecodeInterleaved(out_samples, out_data.data(), out_data.size_bytes(),
|
||||
channel_count, in_data.data(), header.size,
|
||||
shared_buffer.get(), time_taken, reset));
|
||||
|
||||
std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
|
||||
|
||||
*out_data_size = header.size + sizeof(OpusPacketHeader);
|
||||
*out_sample_count = out_samples;
|
||||
if (out_time_taken) {
|
||||
*out_time_taken = time_taken / 1000;
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoder::SetContext([[maybe_unused]] std::span<const u8> context) {
|
||||
R_SUCCEED_IF(shared_memory_mapped);
|
||||
shared_memory_mapped = true;
|
||||
R_RETURN(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
|
||||
}
|
||||
|
||||
Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken,
|
||||
u32* out_sample_count,
|
||||
std::span<const u8> input_data,
|
||||
std::span<u8> output_data, bool reset) {
|
||||
u32 out_samples;
|
||||
u64 time_taken{};
|
||||
|
||||
R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
|
||||
|
||||
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
||||
OpusPacketHeader header{ReverseHeader(*header_p)};
|
||||
|
||||
LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
||||
header.size, input_data.size_bytes(), in_data.size_bytes());
|
||||
|
||||
R_UNLESS(in_data.size_bytes() >= header.size &&
|
||||
header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
|
||||
ResultBufferTooSmall);
|
||||
|
||||
if (!shared_memory_mapped) {
|
||||
R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
|
||||
shared_memory_mapped = true;
|
||||
}
|
||||
|
||||
std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
|
||||
|
||||
R_TRY(hardware_opus.DecodeInterleavedForMultiStream(
|
||||
out_samples, out_data.data(), out_data.size_bytes(), channel_count, in_data.data(),
|
||||
header.size, shared_buffer.get(), time_taken, reset));
|
||||
|
||||
std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
|
||||
|
||||
*out_data_size = header.size + sizeof(OpusPacketHeader);
|
||||
*out_sample_count = out_samples;
|
||||
if (out_time_taken) {
|
||||
*out_time_taken = time_taken / 1000;
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "audio_core/opus/parameters.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
class HardwareOpus;
|
||||
|
||||
class OpusDecoder {
|
||||
public:
|
||||
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
|
||||
~OpusDecoder();
|
||||
|
||||
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||
u64 transfer_memory_size);
|
||||
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||
u64 transfer_memory_size);
|
||||
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
|
||||
std::span<const u8> input_data, std::span<u8> output_data, bool reset);
|
||||
Result SetContext([[maybe_unused]] std::span<const u8> context);
|
||||
Result DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken,
|
||||
u32* out_sample_count, std::span<const u8> input_data,
|
||||
std::span<u8> output_data, bool reset);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
HardwareOpus& hardware_opus;
|
||||
std::unique_ptr<u8[]> shared_buffer{};
|
||||
u64 shared_buffer_size;
|
||||
std::span<u8> in_data{};
|
||||
std::span<u8> out_data{};
|
||||
u64 buffer_size{};
|
||||
s32 sample_rate{};
|
||||
s32 channel_count{};
|
||||
bool use_large_frame_size{false};
|
||||
s32 total_stream_count{};
|
||||
s32 stereo_stream_count{};
|
||||
bool shared_memory_mapped{false};
|
||||
bool decode_object_initialized{false};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "audio_core/opus/parameters.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
class HardwareOpus;
|
||||
|
||||
class OpusDecoder {
|
||||
public:
|
||||
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
|
||||
~OpusDecoder();
|
||||
|
||||
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||
u64 transfer_memory_size);
|
||||
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
|
||||
u64 transfer_memory_size);
|
||||
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
|
||||
std::span<const u8> input_data, std::span<u8> output_data, bool reset);
|
||||
Result SetContext([[maybe_unused]] std::span<const u8> context);
|
||||
Result DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken,
|
||||
u32* out_sample_count, std::span<const u8> input_data,
|
||||
std::span<u8> output_data, bool reset);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
HardwareOpus& hardware_opus;
|
||||
std::unique_ptr<u8[]> shared_buffer{};
|
||||
u64 shared_buffer_size;
|
||||
std::span<u8> in_data{};
|
||||
std::span<u8> out_data{};
|
||||
u64 buffer_size{};
|
||||
s32 sample_rate{};
|
||||
s32 channel_count{};
|
||||
bool use_large_frame_size{false};
|
||||
s32 total_stream_count{};
|
||||
s32 stereo_stream_count{};
|
||||
bool shared_memory_mapped{false};
|
||||
bool decode_object_initialized{false};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
|
||||
@@ -1,102 +1,102 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_decoder.h"
|
||||
#include "audio_core/opus/decoder_manager.h"
|
||||
#include "common/alignment.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
using namespace Service::Audio;
|
||||
|
||||
namespace {
|
||||
bool IsValidChannelCount(u32 channel_count) {
|
||||
return channel_count == 1 || channel_count == 2;
|
||||
}
|
||||
|
||||
bool IsValidMultiStreamChannelCount(u32 channel_count) {
|
||||
return channel_count > 0 && channel_count <= OpusStreamCountMax;
|
||||
}
|
||||
|
||||
bool IsValidSampleRate(u32 sample_rate) {
|
||||
return sample_rate == 8'000 || sample_rate == 12'000 || sample_rate == 16'000 ||
|
||||
sample_rate == 24'000 || sample_rate == 48'000;
|
||||
}
|
||||
|
||||
bool IsValidStreamCount(u32 channel_count, u32 total_stream_count, u32 stereo_stream_count) {
|
||||
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
|
||||
stereo_stream_count <= total_stream_count &&
|
||||
total_stream_count + stereo_stream_count <= channel_count;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
OpusDecoderManager::OpusDecoderManager(Core::System& system_)
|
||||
: system{system_}, hardware_opus{system} {
|
||||
for (u32 i = 0; i < MaxChannels; i++) {
|
||||
required_workbuffer_sizes[i] = hardware_opus.GetWorkBufferSize(1 + i);
|
||||
}
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
|
||||
OpusParametersEx ex{
|
||||
.sample_rate = params.sample_rate,
|
||||
.channel_count = params.channel_count,
|
||||
.use_large_frame_size = false,
|
||||
};
|
||||
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
|
||||
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
|
||||
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
||||
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
||||
|
||||
auto work_buffer_size{required_workbuffer_sizes[params.channel_count - 1]};
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
work_buffer_size +=
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64);
|
||||
out_size = work_buffer_size + 0x600;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
|
||||
u64& out_size) {
|
||||
OpusMultiStreamParametersEx ex{
|
||||
.sample_rate = params.sample_rate,
|
||||
.channel_count = params.channel_count,
|
||||
.total_stream_count = params.total_stream_count,
|
||||
.stereo_stream_count = params.stereo_stream_count,
|
||||
.use_large_frame_size = false,
|
||||
.mappings = {},
|
||||
};
|
||||
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
|
||||
u64& out_size) {
|
||||
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
|
||||
u64& out_size) {
|
||||
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
||||
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
||||
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,
|
||||
params.stereo_stream_count),
|
||||
ResultInvalidOpusSampleRate);
|
||||
|
||||
auto work_buffer_size{hardware_opus.GetWorkBufferSizeForMultiStream(
|
||||
params.total_stream_count, params.stereo_stream_count)};
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
work_buffer_size += Common::AlignUp(1500 * params.total_stream_count, 64);
|
||||
work_buffer_size +=
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64);
|
||||
out_size = work_buffer_size;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_decoder.h"
|
||||
#include "audio_core/opus/decoder_manager.h"
|
||||
#include "common/alignment.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
using namespace Service::Audio;
|
||||
|
||||
namespace {
|
||||
bool IsValidChannelCount(u32 channel_count) {
|
||||
return channel_count == 1 || channel_count == 2;
|
||||
}
|
||||
|
||||
bool IsValidMultiStreamChannelCount(u32 channel_count) {
|
||||
return channel_count > 0 && channel_count <= OpusStreamCountMax;
|
||||
}
|
||||
|
||||
bool IsValidSampleRate(u32 sample_rate) {
|
||||
return sample_rate == 8'000 || sample_rate == 12'000 || sample_rate == 16'000 ||
|
||||
sample_rate == 24'000 || sample_rate == 48'000;
|
||||
}
|
||||
|
||||
bool IsValidStreamCount(u32 channel_count, u32 total_stream_count, u32 stereo_stream_count) {
|
||||
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
|
||||
stereo_stream_count <= total_stream_count &&
|
||||
total_stream_count + stereo_stream_count <= channel_count;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
OpusDecoderManager::OpusDecoderManager(Core::System& system_)
|
||||
: system{system_}, hardware_opus{system} {
|
||||
for (u32 i = 0; i < MaxChannels; i++) {
|
||||
required_workbuffer_sizes[i] = hardware_opus.GetWorkBufferSize(1 + i);
|
||||
}
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
|
||||
OpusParametersEx ex{
|
||||
.sample_rate = params.sample_rate,
|
||||
.channel_count = params.channel_count,
|
||||
.use_large_frame_size = false,
|
||||
};
|
||||
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
|
||||
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
|
||||
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
||||
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
||||
|
||||
auto work_buffer_size{required_workbuffer_sizes[params.channel_count - 1]};
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
work_buffer_size +=
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64);
|
||||
out_size = work_buffer_size + 0x600;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
|
||||
u64& out_size) {
|
||||
OpusMultiStreamParametersEx ex{
|
||||
.sample_rate = params.sample_rate,
|
||||
.channel_count = params.channel_count,
|
||||
.total_stream_count = params.total_stream_count,
|
||||
.stereo_stream_count = params.stereo_stream_count,
|
||||
.use_large_frame_size = false,
|
||||
.mappings = {},
|
||||
};
|
||||
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
|
||||
u64& out_size) {
|
||||
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
|
||||
}
|
||||
|
||||
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
|
||||
u64& out_size) {
|
||||
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
|
||||
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
|
||||
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,
|
||||
params.stereo_stream_count),
|
||||
ResultInvalidOpusSampleRate);
|
||||
|
||||
auto work_buffer_size{hardware_opus.GetWorkBufferSizeForMultiStream(
|
||||
params.total_stream_count, params.stereo_stream_count)};
|
||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||
work_buffer_size += Common::AlignUp(1500 * params.total_stream_count, 64);
|
||||
work_buffer_size +=
|
||||
Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64);
|
||||
out_size = work_buffer_size;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "audio_core/opus/hardware_opus.h"
|
||||
#include "audio_core/opus/parameters.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
|
||||
class OpusDecoderManager {
|
||||
public:
|
||||
OpusDecoderManager(Core::System& system);
|
||||
|
||||
HardwareOpus& GetHardwareOpus() {
|
||||
return hardware_opus;
|
||||
}
|
||||
|
||||
Result GetWorkBufferSize(OpusParameters& params, u64& out_size);
|
||||
Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size);
|
||||
Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size);
|
||||
Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size);
|
||||
Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size);
|
||||
Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
HardwareOpus hardware_opus;
|
||||
std::array<u64, MaxChannels> required_workbuffer_sizes{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "audio_core/opus/hardware_opus.h"
|
||||
#include "audio_core/opus/parameters.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
|
||||
class OpusDecoderManager {
|
||||
public:
|
||||
OpusDecoderManager(Core::System& system);
|
||||
|
||||
HardwareOpus& GetHardwareOpus() {
|
||||
return hardware_opus;
|
||||
}
|
||||
|
||||
Result GetWorkBufferSize(OpusParameters& params, u64& out_size);
|
||||
Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size);
|
||||
Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size);
|
||||
Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size);
|
||||
Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size);
|
||||
Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
HardwareOpus hardware_opus;
|
||||
std::array<u64, MaxChannels> required_workbuffer_sizes{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
|
||||
@@ -1,241 +1,241 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/audio_core.h"
|
||||
#include "audio_core/opus/hardware_opus.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
namespace {
|
||||
using namespace Service::Audio;
|
||||
|
||||
static constexpr Result ResultCodeFromLibOpusErrorCode(u64 error_code) {
|
||||
s32 error{static_cast<s32>(error_code)};
|
||||
ASSERT(error <= OPUS_OK);
|
||||
switch (error) {
|
||||
case OPUS_ALLOC_FAIL:
|
||||
R_THROW(ResultLibOpusAllocFail);
|
||||
case OPUS_INVALID_STATE:
|
||||
R_THROW(ResultLibOpusInvalidState);
|
||||
case OPUS_UNIMPLEMENTED:
|
||||
R_THROW(ResultLibOpusUnimplemented);
|
||||
case OPUS_INVALID_PACKET:
|
||||
R_THROW(ResultLibOpusInvalidPacket);
|
||||
case OPUS_INTERNAL_ERROR:
|
||||
R_THROW(ResultLibOpusInternalError);
|
||||
case OPUS_BUFFER_TOO_SMALL:
|
||||
R_THROW(ResultBufferTooSmall);
|
||||
case OPUS_BAD_ARG:
|
||||
R_THROW(ResultLibOpusBadArg);
|
||||
case OPUS_OK:
|
||||
R_RETURN(ResultSuccess);
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
HardwareOpus::HardwareOpus(Core::System& system_)
|
||||
: system{system_}, opus_decoder{system.AudioCore().ADSP().OpusDecoder()} {
|
||||
opus_decoder.SetSharedMemory(shared_memory);
|
||||
}
|
||||
|
||||
u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
|
||||
if (!opus_decoder.IsRunning()) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = channel;
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::GetWorkBufferSize);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
|
||||
return 0;
|
||||
}
|
||||
return shared_memory.dsp_return_data[0];
|
||||
}
|
||||
|
||||
u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = total_stream_count;
|
||||
shared_memory.host_send_data[1] = stereo_stream_count;
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStream);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
|
||||
return 0;
|
||||
}
|
||||
return shared_memory.dsp_return_data[0];
|
||||
}
|
||||
|
||||
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
||||
u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
shared_memory.host_send_data[2] = sample_rate;
|
||||
shared_memory.host_send_data[3] = channel_count;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::InitializeDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::InitializeDecodeObjectOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::InitializeDecodeObjectOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
||||
u32 total_stream_count,
|
||||
u32 stereo_stream_count, void* mappings,
|
||||
void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
shared_memory.host_send_data[2] = sample_rate;
|
||||
shared_memory.host_send_data[3] = channel_count;
|
||||
shared_memory.host_send_data[4] = total_stream_count;
|
||||
shared_memory.host_send_data[5] = stereo_stream_count;
|
||||
|
||||
ASSERT(channel_count <= MaxChannels);
|
||||
std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::ShutdownDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK,
|
||||
"Expected Opus shutdown code {}, got {}",
|
||||
ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, msg);
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK,
|
||||
"Expected Opus shutdown code {}, got {}",
|
||||
ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, msg);
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data,
|
||||
u64 output_data_size, u32 channel_count, void* input_data,
|
||||
u64 input_data_size, void* buffer, u64& out_time_taken,
|
||||
bool reset) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = (u64)input_data;
|
||||
shared_memory.host_send_data[2] = input_data_size;
|
||||
shared_memory.host_send_data[3] = (u64)output_data;
|
||||
shared_memory.host_send_data[4] = output_data_size;
|
||||
shared_memory.host_send_data[5] = 0;
|
||||
shared_memory.host_send_data[6] = reset;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::DecodeInterleaved);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::DecodeInterleavedOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])};
|
||||
if (error_code == OPUS_OK) {
|
||||
out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]);
|
||||
out_time_taken = 1000 * shared_memory.dsp_return_data[2];
|
||||
}
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(error_code));
|
||||
}
|
||||
|
||||
Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data,
|
||||
u64 output_data_size, u32 channel_count,
|
||||
void* input_data, u64 input_data_size,
|
||||
void* buffer, u64& out_time_taken,
|
||||
bool reset) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = (u64)input_data;
|
||||
shared_memory.host_send_data[2] = input_data_size;
|
||||
shared_memory.host_send_data[3] = (u64)output_data;
|
||||
shared_memory.host_send_data[4] = output_data_size;
|
||||
shared_memory.host_send_data[5] = 0;
|
||||
shared_memory.host_send_data[6] = reset;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStream);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])};
|
||||
if (error_code == OPUS_OK) {
|
||||
out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]);
|
||||
out_time_taken = 1000 * shared_memory.dsp_return_data[2];
|
||||
}
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(error_code));
|
||||
}
|
||||
|
||||
Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::MapMemory);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::MapMemoryOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::MapMemoryOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result HardwareOpus::UnmapMemory(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::UnmapMemory);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::UnmapMemoryOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::UnmapMemoryOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/audio_core.h"
|
||||
#include "audio_core/opus/hardware_opus.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
namespace {
|
||||
using namespace Service::Audio;
|
||||
|
||||
static constexpr Result ResultCodeFromLibOpusErrorCode(u64 error_code) {
|
||||
s32 error{static_cast<s32>(error_code)};
|
||||
ASSERT(error <= OPUS_OK);
|
||||
switch (error) {
|
||||
case OPUS_ALLOC_FAIL:
|
||||
R_THROW(ResultLibOpusAllocFail);
|
||||
case OPUS_INVALID_STATE:
|
||||
R_THROW(ResultLibOpusInvalidState);
|
||||
case OPUS_UNIMPLEMENTED:
|
||||
R_THROW(ResultLibOpusUnimplemented);
|
||||
case OPUS_INVALID_PACKET:
|
||||
R_THROW(ResultLibOpusInvalidPacket);
|
||||
case OPUS_INTERNAL_ERROR:
|
||||
R_THROW(ResultLibOpusInternalError);
|
||||
case OPUS_BUFFER_TOO_SMALL:
|
||||
R_THROW(ResultBufferTooSmall);
|
||||
case OPUS_BAD_ARG:
|
||||
R_THROW(ResultLibOpusBadArg);
|
||||
case OPUS_OK:
|
||||
R_RETURN(ResultSuccess);
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
HardwareOpus::HardwareOpus(Core::System& system_)
|
||||
: system{system_}, opus_decoder{system.AudioCore().ADSP().OpusDecoder()} {
|
||||
opus_decoder.SetSharedMemory(shared_memory);
|
||||
}
|
||||
|
||||
u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
|
||||
if (!opus_decoder.IsRunning()) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = channel;
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::GetWorkBufferSize);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
|
||||
return 0;
|
||||
}
|
||||
return shared_memory.dsp_return_data[0];
|
||||
}
|
||||
|
||||
u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = total_stream_count;
|
||||
shared_memory.host_send_data[1] = stereo_stream_count;
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStream);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
|
||||
return 0;
|
||||
}
|
||||
return shared_memory.dsp_return_data[0];
|
||||
}
|
||||
|
||||
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
||||
u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
shared_memory.host_send_data[2] = sample_rate;
|
||||
shared_memory.host_send_data[3] = channel_count;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::InitializeDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::InitializeDecodeObjectOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::InitializeDecodeObjectOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
||||
u32 total_stream_count,
|
||||
u32 stereo_stream_count, void* mappings,
|
||||
void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
shared_memory.host_send_data[2] = sample_rate;
|
||||
shared_memory.host_send_data[3] = channel_count;
|
||||
shared_memory.host_send_data[4] = total_stream_count;
|
||||
shared_memory.host_send_data[5] = stereo_stream_count;
|
||||
|
||||
ASSERT(channel_count <= MaxChannels);
|
||||
std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::ShutdownDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK,
|
||||
"Expected Opus shutdown code {}, got {}",
|
||||
ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, msg);
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObject);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK,
|
||||
"Expected Opus shutdown code {}, got {}",
|
||||
ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, msg);
|
||||
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
|
||||
}
|
||||
|
||||
Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data,
|
||||
u64 output_data_size, u32 channel_count, void* input_data,
|
||||
u64 input_data_size, void* buffer, u64& out_time_taken,
|
||||
bool reset) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = (u64)input_data;
|
||||
shared_memory.host_send_data[2] = input_data_size;
|
||||
shared_memory.host_send_data[3] = (u64)output_data;
|
||||
shared_memory.host_send_data[4] = output_data_size;
|
||||
shared_memory.host_send_data[5] = 0;
|
||||
shared_memory.host_send_data[6] = reset;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::DecodeInterleaved);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::DecodeInterleavedOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])};
|
||||
if (error_code == OPUS_OK) {
|
||||
out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]);
|
||||
out_time_taken = 1000 * shared_memory.dsp_return_data[2];
|
||||
}
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(error_code));
|
||||
}
|
||||
|
||||
Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data,
|
||||
u64 output_data_size, u32 channel_count,
|
||||
void* input_data, u64 input_data_size,
|
||||
void* buffer, u64& out_time_taken,
|
||||
bool reset) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = (u64)input_data;
|
||||
shared_memory.host_send_data[2] = input_data_size;
|
||||
shared_memory.host_send_data[3] = (u64)output_data;
|
||||
shared_memory.host_send_data[4] = output_data_size;
|
||||
shared_memory.host_send_data[5] = 0;
|
||||
shared_memory.host_send_data[6] = reset;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP,
|
||||
ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStream);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
|
||||
auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])};
|
||||
if (error_code == OPUS_OK) {
|
||||
out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]);
|
||||
out_time_taken = 1000 * shared_memory.dsp_return_data[2];
|
||||
}
|
||||
R_RETURN(ResultCodeFromLibOpusErrorCode(error_code));
|
||||
}
|
||||
|
||||
Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::MapMemory);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::MapMemoryOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::MapMemoryOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result HardwareOpus::UnmapMemory(void* buffer, u64 buffer_size) {
|
||||
std::scoped_lock l{mutex};
|
||||
shared_memory.host_send_data[0] = (u64)buffer;
|
||||
shared_memory.host_send_data[1] = buffer_size;
|
||||
|
||||
opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::UnmapMemory);
|
||||
auto msg = opus_decoder.Receive(ADSP::Direction::Host);
|
||||
if (msg != ADSP::OpusDecoder::Message::UnmapMemoryOK) {
|
||||
LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
|
||||
ADSP::OpusDecoder::Message::UnmapMemoryOK, msg);
|
||||
R_THROW(ResultInvalidOpusDSPReturnCode);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <opus.h>
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_decoder.h"
|
||||
#include "audio_core/adsp/apps/opus/shared_memory.h"
|
||||
#include "audio_core/adsp/mailbox.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
class HardwareOpus {
|
||||
public:
|
||||
HardwareOpus(Core::System& system);
|
||||
|
||||
u64 GetWorkBufferSize(u32 channel);
|
||||
u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
|
||||
|
||||
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
||||
u64 buffer_size);
|
||||
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
||||
u32 totaL_stream_count, u32 stereo_stream_count,
|
||||
void* mappings, void* buffer, u64 buffer_size);
|
||||
Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
|
||||
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
|
||||
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,
|
||||
u32 channel_count, void* input_data, u64 input_data_size, void* buffer,
|
||||
u64& out_time_taken, bool reset);
|
||||
Result DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data,
|
||||
u64 output_data_size, u32 channel_count,
|
||||
void* input_data, u64 input_data_size, void* buffer,
|
||||
u64& out_time_taken, bool reset);
|
||||
Result MapMemory(void* buffer, u64 buffer_size);
|
||||
Result UnmapMemory(void* buffer, u64 buffer_size);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
std::mutex mutex;
|
||||
ADSP::OpusDecoder::OpusDecoder& opus_decoder;
|
||||
ADSP::OpusDecoder::SharedMemory shared_memory;
|
||||
};
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <opus.h>
|
||||
|
||||
#include "audio_core/adsp/apps/opus/opus_decoder.h"
|
||||
#include "audio_core/adsp/apps/opus/shared_memory.h"
|
||||
#include "audio_core/adsp/mailbox.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace AudioCore::OpusDecoder {
|
||||
class HardwareOpus {
|
||||
public:
|
||||
HardwareOpus(Core::System& system);
|
||||
|
||||
u64 GetWorkBufferSize(u32 channel);
|
||||
u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
|
||||
|
||||
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
|
||||
u64 buffer_size);
|
||||
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
|
||||
u32 totaL_stream_count, u32 stereo_stream_count,
|
||||
void* mappings, void* buffer, u64 buffer_size);
|
||||
Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
|
||||
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
|
||||
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,
|
||||
u32 channel_count, void* input_data, u64 input_data_size, void* buffer,
|
||||
u64& out_time_taken, bool reset);
|
||||
Result DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data,
|
||||
u64 output_data_size, u32 channel_count,
|
||||
void* input_data, u64 input_data_size, void* buffer,
|
||||
u64& out_time_taken, bool reset);
|
||||
Result MapMemory(void* buffer, u64 buffer_size);
|
||||
Result UnmapMemory(void* buffer, u64 buffer_size);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
std::mutex mutex;
|
||||
ADSP::OpusDecoder::OpusDecoder& opus_decoder;
|
||||
ADSP::OpusDecoder::SharedMemory shared_memory;
|
||||
};
|
||||
} // namespace AudioCore::OpusDecoder
|
||||
|
||||
@@ -252,7 +252,6 @@ file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
|
||||
if (ENABLE_QT_TRANSLATION)
|
||||
set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
|
||||
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
|
||||
option(WORKAROUND_BROKEN_LUPDATE "Run lupdate directly through CMake if Qt's convenience wrappers don't work" OFF)
|
||||
|
||||
# Update source TS file if enabled
|
||||
if (GENERATE_QT_TRANSLATION)
|
||||
@@ -260,51 +259,19 @@ if (ENABLE_QT_TRANSLATION)
|
||||
# these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals
|
||||
# so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm
|
||||
set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
|
||||
if (WORKAROUND_BROKEN_LUPDATE)
|
||||
add_custom_command(OUTPUT ${YUZU_QT_LANGUAGES}/en.ts
|
||||
COMMAND lupdate
|
||||
-source-language en_US
|
||||
-target-language en_US
|
||||
${SRCS}
|
||||
${UIS}
|
||||
-ts ${YUZU_QT_LANGUAGES}/en.ts
|
||||
DEPENDS
|
||||
${SRCS}
|
||||
${UIS}
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
else()
|
||||
qt_create_translation(QM_FILES
|
||||
${SRCS}
|
||||
${UIS}
|
||||
${YUZU_QT_LANGUAGES}/en.ts
|
||||
OPTIONS
|
||||
-source-language en_US
|
||||
-target-language en_US
|
||||
)
|
||||
endif()
|
||||
qt_create_translation(QM_FILES
|
||||
${SRCS}
|
||||
${UIS}
|
||||
${YUZU_QT_LANGUAGES}/en.ts
|
||||
OPTIONS
|
||||
-source-language en_US
|
||||
-target-language en_US
|
||||
)
|
||||
|
||||
# Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts
|
||||
set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts)
|
||||
set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals")
|
||||
if (WORKAROUND_BROKEN_LUPDATE)
|
||||
add_custom_command(OUTPUT ${GENERATED_PLURALS_FILE}
|
||||
COMMAND lupdate
|
||||
-source-language en_US
|
||||
-target-language en_US
|
||||
${SRCS}
|
||||
${UIS}
|
||||
-ts ${GENERATED_PLURALS_FILE}
|
||||
DEPENDS
|
||||
${SRCS}
|
||||
${UIS}
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
else()
|
||||
qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
|
||||
endif()
|
||||
qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
|
||||
|
||||
add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE})
|
||||
endif()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Text : Copyright 2022 yuzu Emulator Project
|
||||
// Text : Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/time_zone.h"
|
||||
#include "yuzu/configuration/shared_translation.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <QCoreApplication>
|
||||
#include <QWidget>
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "common/settings_setting.h"
|
||||
#include "common/time_zone.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
|
||||
namespace ConfigurationShared {
|
||||
@@ -22,135 +21,123 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
||||
const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); };
|
||||
|
||||
#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \
|
||||
translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}})
|
||||
translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{tr((NAME)), tr((TOOLTIP))}})
|
||||
|
||||
// A setting can be ignored by giving it a blank name
|
||||
|
||||
// Audio
|
||||
INSERT(Settings, sink_id, tr("Output Engine:"), QStringLiteral());
|
||||
INSERT(Settings, audio_output_device_id, tr("Output Device:"), QStringLiteral());
|
||||
INSERT(Settings, audio_input_device_id, tr("Input Device:"), QStringLiteral());
|
||||
INSERT(Settings, audio_muted, tr("Mute audio"), QStringLiteral());
|
||||
INSERT(Settings, volume, tr("Volume:"), QStringLiteral());
|
||||
INSERT(Settings, dump_audio_commands, QStringLiteral(), QStringLiteral());
|
||||
INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"),
|
||||
QStringLiteral());
|
||||
INSERT(Settings, sink_id, "Output Engine:", "");
|
||||
INSERT(Settings, audio_output_device_id, "Output Device:", "");
|
||||
INSERT(Settings, audio_input_device_id, "Input Device:", "");
|
||||
INSERT(Settings, audio_muted, "Mute audio", "");
|
||||
INSERT(Settings, volume, "Volume:", "");
|
||||
INSERT(Settings, dump_audio_commands, "", "");
|
||||
INSERT(UISettings, mute_when_in_background, "Mute audio when in background", "");
|
||||
|
||||
// Core
|
||||
INSERT(Settings, use_multi_core, tr("Multicore CPU Emulation"), QStringLiteral());
|
||||
INSERT(Settings, memory_layout_mode, tr("Memory Layout"), QStringLiteral());
|
||||
INSERT(Settings, use_speed_limit, QStringLiteral(), QStringLiteral());
|
||||
INSERT(Settings, speed_limit, tr("Limit Speed Percent"), QStringLiteral());
|
||||
INSERT(Settings, use_multi_core, "Multicore CPU Emulation", "");
|
||||
INSERT(Settings, memory_layout_mode, "Memory Layout", "");
|
||||
INSERT(Settings, use_speed_limit, "", "");
|
||||
INSERT(Settings, speed_limit, "Limit Speed Percent", "");
|
||||
|
||||
// Cpu
|
||||
INSERT(Settings, cpu_accuracy, tr("Accuracy:"), QStringLiteral());
|
||||
INSERT(Settings, cpu_accuracy, "Accuracy:", "");
|
||||
|
||||
// Cpu Debug
|
||||
|
||||
// Cpu Unsafe
|
||||
INSERT(Settings, cpuopt_unsafe_unfuse_fma,
|
||||
"Unfuse FMA (improve performance on CPUs without FMA)",
|
||||
"This option improves speed by reducing accuracy of fused-multiply-add instructions on "
|
||||
"CPUs without native FMA support.");
|
||||
INSERT(Settings, cpuopt_unsafe_reduce_fp_error, "Faster FRSQRTE and FRECPE",
|
||||
"This option improves the speed of some approximate floating-point functions by using "
|
||||
"less accurate native approximations.");
|
||||
INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, "Faster ASIMD instructions (32 bits only)",
|
||||
"This option improves the speed of 32 bits ASIMD floating-point functions by running "
|
||||
"with incorrect rounding modes.");
|
||||
INSERT(Settings, cpuopt_unsafe_inaccurate_nan, "Inaccurate NaN handling",
|
||||
"This option improves speed by removing NaN checking. Please note this also reduces "
|
||||
"accuracy of certain floating-point instructions.");
|
||||
INSERT(
|
||||
Settings, cpuopt_unsafe_unfuse_fma,
|
||||
tr("Unfuse FMA (improve performance on CPUs without FMA)"),
|
||||
tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on "
|
||||
"CPUs without native FMA support."));
|
||||
INSERT(
|
||||
Settings, cpuopt_unsafe_reduce_fp_error, tr("Faster FRSQRTE and FRECPE"),
|
||||
tr("This option improves the speed of some approximate floating-point functions by using "
|
||||
"less accurate native approximations."));
|
||||
INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr,
|
||||
tr("Faster ASIMD instructions (32 bits only)"),
|
||||
tr("This option improves the speed of 32 bits ASIMD floating-point functions by running "
|
||||
"with incorrect rounding modes."));
|
||||
INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"),
|
||||
tr("This option improves speed by removing NaN checking. Please note this also reduces "
|
||||
"accuracy of certain floating-point instructions."));
|
||||
INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"),
|
||||
tr("This option improves speed by eliminating a safety check before every memory "
|
||||
"read/write "
|
||||
"in guest. Disabling it may allow a game to read/write the emulator's memory."));
|
||||
INSERT(
|
||||
Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"),
|
||||
tr("This option improves speed by relying only on the semantics of cmpxchg to ensure "
|
||||
Settings, cpuopt_unsafe_fastmem_check, "Disable address space checks",
|
||||
"This option improves speed by eliminating a safety check before every memory read/write "
|
||||
"in guest. Disabling it may allow a game to read/write the emulator's memory.");
|
||||
INSERT(Settings, cpuopt_unsafe_ignore_global_monitor, "Ignore global monitor",
|
||||
"This option improves speed by relying only on the semantics of cmpxchg to ensure "
|
||||
"safety of exclusive access instructions. Please note this may result in deadlocks and "
|
||||
"other race conditions."));
|
||||
"other race conditions.");
|
||||
|
||||
// Renderer
|
||||
INSERT(Settings, renderer_backend, tr("API:"), QStringLiteral());
|
||||
INSERT(Settings, vulkan_device, tr("Device:"), QStringLiteral());
|
||||
INSERT(Settings, shader_backend, tr("Shader Backend:"), QStringLiteral());
|
||||
INSERT(Settings, resolution_setup, tr("Resolution:"), QStringLiteral());
|
||||
INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral());
|
||||
INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), QStringLiteral());
|
||||
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), QStringLiteral());
|
||||
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), QStringLiteral());
|
||||
INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), QStringLiteral());
|
||||
INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), QStringLiteral());
|
||||
INSERT(Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"),
|
||||
QStringLiteral());
|
||||
INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), QStringLiteral());
|
||||
INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), QStringLiteral());
|
||||
INSERT(Settings, astc_recompression, tr("ASTC Recompression Method:"), QStringLiteral());
|
||||
INSERT(
|
||||
Settings, vsync_mode, tr("VSync Mode:"),
|
||||
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
||||
INSERT(Settings, renderer_backend, "API:", "");
|
||||
INSERT(Settings, vulkan_device, "Device:", "");
|
||||
INSERT(Settings, shader_backend, "Shader Backend:", "");
|
||||
INSERT(Settings, resolution_setup, "Resolution:", "");
|
||||
INSERT(Settings, scaling_filter, "Window Adapting Filter:", "");
|
||||
INSERT(Settings, fsr_sharpening_slider, "FSR Sharpness:", "");
|
||||
INSERT(Settings, anti_aliasing, "Anti-Aliasing Method:", "");
|
||||
INSERT(Settings, fullscreen_mode, "Fullscreen Mode:", "");
|
||||
INSERT(Settings, aspect_ratio, "Aspect Ratio:", "");
|
||||
INSERT(Settings, use_disk_shader_cache, "Use disk pipeline cache", "");
|
||||
INSERT(Settings, use_asynchronous_gpu_emulation, "Use asynchronous GPU emulation", "");
|
||||
INSERT(Settings, nvdec_emulation, "NVDEC emulation:", "");
|
||||
INSERT(Settings, accelerate_astc, "ASTC Decoding Method:", "");
|
||||
INSERT(Settings, astc_recompression, "ASTC Recompression Method:", "");
|
||||
INSERT(Settings, vsync_mode, "VSync Mode:",
|
||||
"FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
||||
"refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from "
|
||||
"a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop "
|
||||
"frames.\nImmediate (no synchronization) just presents whatever is available and can "
|
||||
"exhibit tearing."));
|
||||
INSERT(Settings, bg_red, QStringLiteral(), QStringLiteral());
|
||||
INSERT(Settings, bg_green, QStringLiteral(), QStringLiteral());
|
||||
INSERT(Settings, bg_blue, QStringLiteral(), QStringLiteral());
|
||||
"exhibit tearing.");
|
||||
INSERT(Settings, bg_red, "", "");
|
||||
INSERT(Settings, bg_green, "", "");
|
||||
INSERT(Settings, bg_blue, "", "");
|
||||
|
||||
// Renderer (Advanced Graphics)
|
||||
INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"),
|
||||
QStringLiteral());
|
||||
INSERT(
|
||||
Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"),
|
||||
tr("Runs work in the background while waiting for graphics commands to keep the GPU from "
|
||||
"lowering its clock speed."));
|
||||
INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"), QStringLiteral());
|
||||
INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), QStringLiteral());
|
||||
INSERT(
|
||||
Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"),
|
||||
tr("Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
|
||||
"is experimental."));
|
||||
INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"),
|
||||
tr("Enables Fast GPU Time. This option will force most games to run at their highest "
|
||||
"native resolution."));
|
||||
INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"),
|
||||
tr("Enables GPU vendor-specific pipeline cache. This option can improve shader loading "
|
||||
"time significantly in cases where the Vulkan driver does not store pipeline cache "
|
||||
"files internally."));
|
||||
INSERT(
|
||||
Settings, enable_compute_pipelines, tr("Enable Compute Pipelines (Intel Vulkan Only)"),
|
||||
tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
|
||||
INSERT(Settings, async_presentation, "Enable asynchronous presentation (Vulkan only)", "");
|
||||
INSERT(Settings, renderer_force_max_clock, "Force maximum clocks (Vulkan only)",
|
||||
"Runs work in the background while waiting for graphics commands to keep the GPU from "
|
||||
"lowering its clock speed.");
|
||||
INSERT(Settings, max_anisotropy, "Anisotropic Filtering:", "");
|
||||
INSERT(Settings, gpu_accuracy, "Accuracy Level:", "");
|
||||
INSERT(Settings, use_asynchronous_shaders, "Use asynchronous shader building (Hack)",
|
||||
"Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
|
||||
"is experimental.");
|
||||
INSERT(Settings, use_fast_gpu_time, "Use Fast GPU Time (Hack)",
|
||||
"Enables Fast GPU Time. This option will force most games to run at their highest "
|
||||
"native resolution.");
|
||||
INSERT(Settings, use_vulkan_driver_pipeline_cache, "Use Vulkan pipeline cache",
|
||||
"Enables GPU vendor-specific pipeline cache. This option can improve shader loading "
|
||||
"time significantly in cases where the Vulkan driver does not store pipeline cache "
|
||||
"files internally.");
|
||||
INSERT(Settings, enable_compute_pipelines, "Enable Compute Pipelines (Intel Vulkan Only)",
|
||||
"Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
|
||||
"proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled "
|
||||
"on all other drivers."));
|
||||
INSERT(
|
||||
Settings, use_reactive_flushing, tr("Enable Reactive Flushing"),
|
||||
tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
|
||||
"syncing."));
|
||||
INSERT(Settings, use_video_framerate, tr("Sync to framerate of video playback"),
|
||||
tr("Run the game at normal speed during video playback, even when the framerate is "
|
||||
"unlocked."));
|
||||
INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"),
|
||||
tr("Improves rendering of transparency effects in specific games."));
|
||||
"on all other drivers.");
|
||||
INSERT(Settings, use_reactive_flushing, "Enable Reactive Flushing",
|
||||
"Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
|
||||
"syncing.");
|
||||
INSERT(Settings, use_video_framerate, "Sync to framerate of video playback",
|
||||
"Run the game at normal speed during video playback, even when the framerate is "
|
||||
"unlocked.");
|
||||
INSERT(Settings, barrier_feedback_loops, "Barrier feedback loops",
|
||||
"Improves rendering of transparency effects in specific games.");
|
||||
|
||||
// Renderer (Debug)
|
||||
|
||||
// System
|
||||
INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral());
|
||||
INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral());
|
||||
INSERT(Settings, device_name, tr("Device Name"), QStringLiteral());
|
||||
INSERT(Settings, custom_rtc, tr("Custom RTC"), QStringLiteral());
|
||||
INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral());
|
||||
INSERT(Settings, language_index, tr("Language:"),
|
||||
tr("Note: this can be overridden when region setting is auto-select"));
|
||||
INSERT(Settings, region_index, tr("Region:"), QStringLiteral());
|
||||
INSERT(Settings, time_zone_index, tr("Time Zone:"), QStringLiteral());
|
||||
INSERT(Settings, sound_index, tr("Sound Output Mode:"), QStringLiteral());
|
||||
INSERT(Settings, use_docked_mode, tr("Console Mode:"), QStringLiteral());
|
||||
INSERT(Settings, current_user, QStringLiteral(), QStringLiteral());
|
||||
INSERT(Settings, rng_seed, "RNG Seed", "");
|
||||
INSERT(Settings, rng_seed_enabled, "", "");
|
||||
INSERT(Settings, device_name, "Device Name", "");
|
||||
INSERT(Settings, custom_rtc, "Custom RTC", "");
|
||||
INSERT(Settings, custom_rtc_enabled, "", "");
|
||||
INSERT(Settings, language_index,
|
||||
"Language:", "Note: this can be overridden when region setting is auto-select");
|
||||
INSERT(Settings, region_index, "Region:", "");
|
||||
INSERT(Settings, time_zone_index, "Time Zone:", "");
|
||||
INSERT(Settings, sound_index, "Sound Output Mode:", "");
|
||||
INSERT(Settings, use_docked_mode, "Console Mode:", "");
|
||||
INSERT(Settings, current_user, "", "");
|
||||
|
||||
// Controls
|
||||
|
||||
@@ -167,14 +154,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
||||
// Ui
|
||||
|
||||
// Ui General
|
||||
INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), QStringLiteral());
|
||||
INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"),
|
||||
QStringLiteral());
|
||||
INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"),
|
||||
QStringLiteral());
|
||||
INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral());
|
||||
INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
|
||||
QStringLiteral());
|
||||
INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
|
||||
INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
|
||||
INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", "");
|
||||
INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
|
||||
INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");
|
||||
|
||||
// Ui Debugging
|
||||
|
||||
@@ -194,141 +178,140 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||
return parent->tr(text, context);
|
||||
};
|
||||
|
||||
#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast<u32>(Settings::ENUM::VALUE), (TRANSLATION)}
|
||||
#define PAIR(ENUM, VALUE, TRANSLATION) \
|
||||
{ static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION) }
|
||||
#define CTX_PAIR(ENUM, VALUE, TRANSLATION, CONTEXT) \
|
||||
{ static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION, CONTEXT) }
|
||||
|
||||
// Intentionally skipping VSyncMode to let the UI fill that one out
|
||||
|
||||
translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
|
||||
{
|
||||
PAIR(AstcDecodeMode, Cpu, tr("CPU")),
|
||||
PAIR(AstcDecodeMode, Gpu, tr("GPU")),
|
||||
PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")),
|
||||
PAIR(AstcDecodeMode, Cpu, "CPU"),
|
||||
PAIR(AstcDecodeMode, Gpu, "GPU"),
|
||||
PAIR(AstcDecodeMode, CpuAsynchronous, "CPU Asynchronous"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
|
||||
{
|
||||
PAIR(AstcRecompression, Uncompressed, "Uncompressed (Best quality)"),
|
||||
PAIR(AstcRecompression, Bc1, "BC1 (Low quality)"),
|
||||
PAIR(AstcRecompression, Bc3, "BC3 (Medium quality)"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
|
||||
{
|
||||
PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")),
|
||||
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
|
||||
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
|
||||
{
|
||||
#ifdef HAS_OPENGL
|
||||
PAIR(RendererBackend, OpenGL, tr("OpenGL")),
|
||||
PAIR(RendererBackend, OpenGL, "OpenGL"),
|
||||
#endif
|
||||
PAIR(RendererBackend, Vulkan, tr("Vulkan")),
|
||||
PAIR(RendererBackend, Null, tr("Null")),
|
||||
PAIR(RendererBackend, Vulkan, "Vulkan"),
|
||||
PAIR(RendererBackend, Null, "Null"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
|
||||
{
|
||||
PAIR(ShaderBackend, Glsl, "GLSL"),
|
||||
PAIR(ShaderBackend, Glasm, "GLASM (Assembly Shaders, NVIDIA Only)"),
|
||||
PAIR(ShaderBackend, SpirV, "SPIR-V (Experimental, Mesa Only)"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
|
||||
{
|
||||
PAIR(ShaderBackend, Glsl, tr("GLSL")),
|
||||
PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")),
|
||||
PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, Mesa Only)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
|
||||
{
|
||||
PAIR(GpuAccuracy, Normal, tr("Normal")),
|
||||
PAIR(GpuAccuracy, High, tr("High")),
|
||||
PAIR(GpuAccuracy, Extreme, tr("Extreme")),
|
||||
PAIR(GpuAccuracy, Normal, "Normal"),
|
||||
PAIR(GpuAccuracy, High, "High"),
|
||||
PAIR(GpuAccuracy, Extreme, "Extreme"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
|
||||
{
|
||||
PAIR(CpuAccuracy, Auto, "Auto"),
|
||||
PAIR(CpuAccuracy, Accurate, "Accurate"),
|
||||
PAIR(CpuAccuracy, Unsafe, "Unsafe"),
|
||||
PAIR(CpuAccuracy, Paranoid, "Paranoid (disables most optimizations)"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
|
||||
{
|
||||
PAIR(CpuAccuracy, Auto, tr("Auto")),
|
||||
PAIR(CpuAccuracy, Accurate, tr("Accurate")),
|
||||
PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
|
||||
PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(),
|
||||
{
|
||||
PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")),
|
||||
PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")),
|
||||
PAIR(FullscreenMode, Borderless, "Borderless Windowed"),
|
||||
PAIR(FullscreenMode, Exclusive, "Exclusive Fullscreen"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(),
|
||||
{
|
||||
PAIR(NvdecEmulation, Off, tr("No Video Output")),
|
||||
PAIR(NvdecEmulation, Cpu, tr("CPU Video Decoding")),
|
||||
PAIR(NvdecEmulation, Gpu, tr("GPU Video Decoding (Default)")),
|
||||
PAIR(NvdecEmulation, Off, "No Video Output"),
|
||||
PAIR(NvdecEmulation, Cpu, "CPU Video Decoding"),
|
||||
PAIR(NvdecEmulation, Gpu, "GPU Video Decoding (Default)"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
|
||||
{
|
||||
PAIR(ResolutionSetup, Res1_2X, "0.5X (360p/540p) [EXPERIMENTAL]"),
|
||||
PAIR(ResolutionSetup, Res3_4X, "0.75X (540p/810p) [EXPERIMENTAL]"),
|
||||
PAIR(ResolutionSetup, Res1X, "1X (720p/1080p)"),
|
||||
PAIR(ResolutionSetup, Res3_2X, "1.5X (1080p/1620p) [EXPERIMENTAL]"),
|
||||
PAIR(ResolutionSetup, Res2X, "2X (1440p/2160p)"),
|
||||
PAIR(ResolutionSetup, Res3X, "3X (2160p/3240p)"),
|
||||
PAIR(ResolutionSetup, Res4X, "4X (2880p/4320p)"),
|
||||
PAIR(ResolutionSetup, Res5X, "5X (3600p/5400p)"),
|
||||
PAIR(ResolutionSetup, Res6X, "6X (4320p/6480p)"),
|
||||
PAIR(ResolutionSetup, Res7X, "7X (5040p/7560p)"),
|
||||
PAIR(ResolutionSetup, Res8X, "8X (5760p/8640p)"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
|
||||
{
|
||||
PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")),
|
||||
PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")),
|
||||
PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")),
|
||||
PAIR(ResolutionSetup, Res4X, tr("4X (2880p/4320p)")),
|
||||
PAIR(ResolutionSetup, Res5X, tr("5X (3600p/5400p)")),
|
||||
PAIR(ResolutionSetup, Res6X, tr("6X (4320p/6480p)")),
|
||||
PAIR(ResolutionSetup, Res7X, tr("7X (5040p/7560p)")),
|
||||
PAIR(ResolutionSetup, Res8X, tr("8X (5760p/8640p)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(),
|
||||
{
|
||||
PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")),
|
||||
PAIR(ScalingFilter, Bilinear, tr("Bilinear")),
|
||||
PAIR(ScalingFilter, Bicubic, tr("Bicubic")),
|
||||
PAIR(ScalingFilter, Gaussian, tr("Gaussian")),
|
||||
PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")),
|
||||
PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")),
|
||||
PAIR(ScalingFilter, NearestNeighbor, "Nearest Neighbor"),
|
||||
PAIR(ScalingFilter, Bilinear, "Bilinear"),
|
||||
PAIR(ScalingFilter, Bicubic, "Bicubic"),
|
||||
PAIR(ScalingFilter, Gaussian, "Gaussian"),
|
||||
PAIR(ScalingFilter, ScaleForce, "ScaleForce"),
|
||||
PAIR(ScalingFilter, Fsr, "AMD FidelityFX™️ Super Resolution"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
|
||||
{
|
||||
PAIR(AntiAliasing, None, tr("None")),
|
||||
PAIR(AntiAliasing, Fxaa, tr("FXAA")),
|
||||
PAIR(AntiAliasing, Smaa, tr("SMAA")),
|
||||
PAIR(AntiAliasing, None, "None"),
|
||||
PAIR(AntiAliasing, Fxaa, "FXAA"),
|
||||
PAIR(AntiAliasing, Smaa, "SMAA"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(),
|
||||
{
|
||||
PAIR(AspectRatio, R16_9, tr("Default (16:9)")),
|
||||
PAIR(AspectRatio, R4_3, tr("Force 4:3")),
|
||||
PAIR(AspectRatio, R21_9, tr("Force 21:9")),
|
||||
PAIR(AspectRatio, R16_10, tr("Force 16:10")),
|
||||
PAIR(AspectRatio, Stretch, tr("Stretch to Window")),
|
||||
PAIR(AspectRatio, R16_9, "Default (16:9)"),
|
||||
PAIR(AspectRatio, R4_3, "Force 4:3"),
|
||||
PAIR(AspectRatio, R21_9, "Force 21:9"),
|
||||
PAIR(AspectRatio, R16_10, "Force 16:10"),
|
||||
PAIR(AspectRatio, Stretch, "Stretch to Window"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(),
|
||||
{
|
||||
PAIR(AnisotropyMode, Automatic, tr("Automatic")),
|
||||
PAIR(AnisotropyMode, Default, tr("Default")),
|
||||
PAIR(AnisotropyMode, X2, tr("2x")),
|
||||
PAIR(AnisotropyMode, X4, tr("4x")),
|
||||
PAIR(AnisotropyMode, X8, tr("8x")),
|
||||
PAIR(AnisotropyMode, X16, tr("16x")),
|
||||
PAIR(AnisotropyMode, Automatic, "Automatic"),
|
||||
PAIR(AnisotropyMode, Default, "Default"),
|
||||
PAIR(AnisotropyMode, X2, "2x"),
|
||||
PAIR(AnisotropyMode, X4, "4x"),
|
||||
PAIR(AnisotropyMode, X8, "8x"),
|
||||
PAIR(AnisotropyMode, X16, "16x"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::Language>::Index(),
|
||||
{
|
||||
PAIR(Language, Japanese, tr("Japanese (日本語)")),
|
||||
PAIR(Language, EnglishAmerican, tr("American English")),
|
||||
PAIR(Language, French, tr("French (français)")),
|
||||
PAIR(Language, German, tr("German (Deutsch)")),
|
||||
PAIR(Language, Italian, tr("Italian (italiano)")),
|
||||
PAIR(Language, Spanish, tr("Spanish (español)")),
|
||||
PAIR(Language, Chinese, tr("Chinese")),
|
||||
PAIR(Language, Korean, tr("Korean (한국어)")),
|
||||
PAIR(Language, Dutch, tr("Dutch (Nederlands)")),
|
||||
PAIR(Language, Portuguese, tr("Portuguese (português)")),
|
||||
PAIR(Language, Russian, tr("Russian (Русский)")),
|
||||
PAIR(Language, Taiwanese, tr("Taiwanese")),
|
||||
PAIR(Language, EnglishBritish, tr("British English")),
|
||||
PAIR(Language, FrenchCanadian, tr("Canadian French")),
|
||||
PAIR(Language, SpanishLatin, tr("Latin American Spanish")),
|
||||
PAIR(Language, ChineseSimplified, tr("Simplified Chinese")),
|
||||
PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")),
|
||||
PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")),
|
||||
PAIR(Language, Japanese, "Japanese (日本語)"),
|
||||
PAIR(Language, EnglishAmerican, "American English"),
|
||||
PAIR(Language, French, "French (français)"),
|
||||
PAIR(Language, German, "German (Deutsch)"),
|
||||
PAIR(Language, Italian, "Italian (italiano)"),
|
||||
PAIR(Language, Spanish, "Spanish (español)"),
|
||||
PAIR(Language, Chinese, "Chinese"),
|
||||
PAIR(Language, Korean, "Korean (한국어)"),
|
||||
PAIR(Language, Dutch, "Dutch (Nederlands)"),
|
||||
PAIR(Language, Portuguese, "Portuguese (português)"),
|
||||
PAIR(Language, Russian, "Russian (Русский)"),
|
||||
PAIR(Language, Taiwanese, "Taiwanese"),
|
||||
PAIR(Language, EnglishBritish, "British English"),
|
||||
PAIR(Language, FrenchCanadian, "Canadian French"),
|
||||
PAIR(Language, SpanishLatin, "Latin American Spanish"),
|
||||
PAIR(Language, ChineseSimplified, "Simplified Chinese"),
|
||||
PAIR(Language, ChineseTraditional, "Traditional Chinese (正體中文)"),
|
||||
PAIR(Language, PortugueseBrazilian, "Brazilian Portuguese (português do Brasil)"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
|
||||
{
|
||||
PAIR(Region, Japan, tr("Japan")),
|
||||
PAIR(Region, Usa, tr("USA")),
|
||||
PAIR(Region, Europe, tr("Europe")),
|
||||
PAIR(Region, Australia, tr("Australia")),
|
||||
PAIR(Region, China, tr("China")),
|
||||
PAIR(Region, Korea, tr("Korea")),
|
||||
PAIR(Region, Taiwan, tr("Taiwan")),
|
||||
PAIR(Region, Japan, "Japan"),
|
||||
PAIR(Region, Usa, "USA"),
|
||||
PAIR(Region, Europe, "Europe"),
|
||||
PAIR(Region, Australia, "Australia"),
|
||||
PAIR(Region, China, "China"),
|
||||
PAIR(Region, Korea, "Korea"),
|
||||
PAIR(Region, Taiwan, "Taiwan"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::TimeZone>::Index(),
|
||||
@@ -340,74 +323,72 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||
{static_cast<u32>(Settings::TimeZone::Default),
|
||||
tr("Default (%1)", "Default time zone")
|
||||
.arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))},
|
||||
PAIR(TimeZone, Cet, tr("CET")),
|
||||
PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")),
|
||||
PAIR(TimeZone, Cuba, tr("Cuba")),
|
||||
PAIR(TimeZone, Eet, tr("EET")),
|
||||
PAIR(TimeZone, Egypt, tr("Egypt")),
|
||||
PAIR(TimeZone, Eire, tr("Eire")),
|
||||
PAIR(TimeZone, Est, tr("EST")),
|
||||
PAIR(TimeZone, Est5Edt, tr("EST5EDT")),
|
||||
PAIR(TimeZone, Gb, tr("GB")),
|
||||
PAIR(TimeZone, GbEire, tr("GB-Eire")),
|
||||
PAIR(TimeZone, Gmt, tr("GMT")),
|
||||
PAIR(TimeZone, GmtPlusZero, tr("GMT+0")),
|
||||
PAIR(TimeZone, GmtMinusZero, tr("GMT-0")),
|
||||
PAIR(TimeZone, GmtZero, tr("GMT0")),
|
||||
PAIR(TimeZone, Greenwich, tr("Greenwich")),
|
||||
PAIR(TimeZone, Hongkong, tr("Hongkong")),
|
||||
PAIR(TimeZone, Hst, tr("HST")),
|
||||
PAIR(TimeZone, Iceland, tr("Iceland")),
|
||||
PAIR(TimeZone, Iran, tr("Iran")),
|
||||
PAIR(TimeZone, Israel, tr("Israel")),
|
||||
PAIR(TimeZone, Jamaica, tr("Jamaica")),
|
||||
PAIR(TimeZone, Japan, tr("Japan")),
|
||||
PAIR(TimeZone, Kwajalein, tr("Kwajalein")),
|
||||
PAIR(TimeZone, Libya, tr("Libya")),
|
||||
PAIR(TimeZone, Met, tr("MET")),
|
||||
PAIR(TimeZone, Mst, tr("MST")),
|
||||
PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")),
|
||||
PAIR(TimeZone, Navajo, tr("Navajo")),
|
||||
PAIR(TimeZone, Nz, tr("NZ")),
|
||||
PAIR(TimeZone, NzChat, tr("NZ-CHAT")),
|
||||
PAIR(TimeZone, Poland, tr("Poland")),
|
||||
PAIR(TimeZone, Portugal, tr("Portugal")),
|
||||
PAIR(TimeZone, Prc, tr("PRC")),
|
||||
PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")),
|
||||
PAIR(TimeZone, Roc, tr("ROC")),
|
||||
PAIR(TimeZone, Rok, tr("ROK")),
|
||||
PAIR(TimeZone, Singapore, tr("Singapore")),
|
||||
PAIR(TimeZone, Turkey, tr("Turkey")),
|
||||
PAIR(TimeZone, Uct, tr("UCT")),
|
||||
PAIR(TimeZone, Universal, tr("Universal")),
|
||||
PAIR(TimeZone, Utc, tr("UTC")),
|
||||
PAIR(TimeZone, WSu, tr("W-SU")),
|
||||
PAIR(TimeZone, Wet, tr("WET")),
|
||||
PAIR(TimeZone, Zulu, tr("Zulu")),
|
||||
PAIR(TimeZone, Cet, "CET"),
|
||||
PAIR(TimeZone, Cst6Cdt, "CST6CDT"),
|
||||
PAIR(TimeZone, Cuba, "Cuba"),
|
||||
PAIR(TimeZone, Eet, "EET"),
|
||||
PAIR(TimeZone, Egypt, "Egypt"),
|
||||
PAIR(TimeZone, Eire, "Eire"),
|
||||
PAIR(TimeZone, Est, "EST"),
|
||||
PAIR(TimeZone, Est5Edt, "EST5EDT"),
|
||||
PAIR(TimeZone, Gb, "GB"),
|
||||
PAIR(TimeZone, GbEire, "GB-Eire"),
|
||||
PAIR(TimeZone, Gmt, "GMT"),
|
||||
PAIR(TimeZone, GmtPlusZero, "GMT+0"),
|
||||
PAIR(TimeZone, GmtMinusZero, "GMT-0"),
|
||||
PAIR(TimeZone, GmtZero, "GMT0"),
|
||||
PAIR(TimeZone, Greenwich, "Greenwich"),
|
||||
PAIR(TimeZone, Hongkong, "Hongkong"),
|
||||
PAIR(TimeZone, Hst, "HST"),
|
||||
PAIR(TimeZone, Iceland, "Iceland"),
|
||||
PAIR(TimeZone, Iran, "Iran"),
|
||||
PAIR(TimeZone, Israel, "Israel"),
|
||||
PAIR(TimeZone, Jamaica, "Jamaica"),
|
||||
PAIR(TimeZone, Japan, "Japan"),
|
||||
PAIR(TimeZone, Kwajalein, "Kwajalein"),
|
||||
PAIR(TimeZone, Libya, "Libya"),
|
||||
PAIR(TimeZone, Met, "MET"),
|
||||
PAIR(TimeZone, Mst, "MST"),
|
||||
PAIR(TimeZone, Mst7Mdt, "MST7MDT"),
|
||||
PAIR(TimeZone, Navajo, "Navajo"),
|
||||
PAIR(TimeZone, Nz, "NZ"),
|
||||
PAIR(TimeZone, NzChat, "NZ-CHAT"),
|
||||
PAIR(TimeZone, Poland, "Poland"),
|
||||
PAIR(TimeZone, Portugal, "Portugal"),
|
||||
PAIR(TimeZone, Prc, "PRC"),
|
||||
PAIR(TimeZone, Pst8Pdt, "PST8PDT"),
|
||||
PAIR(TimeZone, Roc, "ROC"),
|
||||
PAIR(TimeZone, Rok, "ROK"),
|
||||
PAIR(TimeZone, Singapore, "Singapore"),
|
||||
PAIR(TimeZone, Turkey, "Turkey"),
|
||||
PAIR(TimeZone, Uct, "UCT"),
|
||||
PAIR(TimeZone, Universal, "Universal"),
|
||||
PAIR(TimeZone, Utc, "UTC"),
|
||||
PAIR(TimeZone, WSu, "W-SU"),
|
||||
PAIR(TimeZone, Wet, "WET"),
|
||||
PAIR(TimeZone, Zulu, "Zulu"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(),
|
||||
{
|
||||
PAIR(AudioMode, Mono, tr("Mono")),
|
||||
PAIR(AudioMode, Stereo, tr("Stereo")),
|
||||
PAIR(AudioMode, Surround, tr("Surround")),
|
||||
PAIR(AudioMode, Mono, "Mono"),
|
||||
PAIR(AudioMode, Stereo, "Stereo"),
|
||||
PAIR(AudioMode, Surround, "Surround"),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
|
||||
{
|
||||
PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
|
||||
PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")),
|
||||
PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
|
||||
{
|
||||
PAIR(ConsoleMode, Docked, tr("Docked")),
|
||||
PAIR(ConsoleMode, Handheld, tr("Handheld")),
|
||||
PAIR(MemoryLayout, Memory_4Gb, "4GB DRAM (Default)"),
|
||||
PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"),
|
||||
PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
|
||||
{PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ConfirmStop>::Index(),
|
||||
{
|
||||
PAIR(ConfirmStop, Ask_Always, tr("Always ask (Default)")),
|
||||
PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")),
|
||||
PAIR(ConfirmStop, Ask_Never, tr("Never ask")),
|
||||
PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"),
|
||||
PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"),
|
||||
PAIR(ConfirmStop, Ask_Never, "Never ask"),
|
||||
}});
|
||||
|
||||
#undef PAIR
|
||||
|
||||
Reference in New Issue
Block a user