early-access version 2833
This commit is contained in:
parent
23cb074b8a
commit
75f8ee434e
5 changed files with 103 additions and 52 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 2832.
|
This is the source code for early-access 2833.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,6 @@ void AudioRenderer::CreateSinkStreams() {
|
||||||
std::string name{fmt::format("ADSP_RenderStream-{}", i)};
|
std::string name{fmt::format("ADSP_RenderStream-{}", i)};
|
||||||
streams[i] =
|
streams[i] =
|
||||||
sink.AcquireSinkStream(system, channels, name, ::AudioCore::Sink::StreamType::Render);
|
sink.AcquireSinkStream(system, channels, name, ::AudioCore::Sink::StreamType::Render);
|
||||||
streams[i]->SetSystemChannels(streams[i]->GetDeviceChannels());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,16 +24,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
constexpr s32 max = std::numeric_limits<s16>::max();
|
constexpr s32 max = std::numeric_limits<s16>::max();
|
||||||
|
|
||||||
auto stream{processor.GetOutputSinkStream()};
|
auto stream{processor.GetOutputSinkStream()};
|
||||||
const auto num_out_channels{stream->GetDeviceChannels()};
|
stream->SetSystemChannels(input_count);
|
||||||
|
|
||||||
auto system_channels{6U};
|
|
||||||
for (u32 i = 0; i < inputs.size(); i++) {
|
|
||||||
if (inputs[i] == 0) {
|
|
||||||
system_channels = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto num_in_channels{std::min(system_channels, stream->GetDeviceChannels())};
|
|
||||||
|
|
||||||
Sink::SinkBuffer out_buffer{
|
Sink::SinkBuffer out_buffer{
|
||||||
.frames{TargetSampleCount},
|
.frames{TargetSampleCount},
|
||||||
|
@ -42,13 +33,13 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
.consumed{false},
|
.consumed{false},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<s16> samples(out_buffer.frames * num_out_channels, 0);
|
std::vector<s16> samples(out_buffer.frames * input_count);
|
||||||
|
|
||||||
for (u32 channel = 0; channel < num_in_channels; channel++) {
|
for (u32 channel = 0; channel < input_count; channel++) {
|
||||||
const auto offset{inputs[channel] * out_buffer.frames};
|
const auto offset{inputs[channel] * out_buffer.frames};
|
||||||
|
|
||||||
for (u32 index = 0; index < out_buffer.frames; index++) {
|
for (u32 index = 0; index < out_buffer.frames; index++) {
|
||||||
samples[index * num_out_channels + channel] =
|
samples[index * input_count + channel] =
|
||||||
static_cast<s16>(std::clamp(sample_buffer[offset + index], min, max));
|
static_cast<s16>(std::clamp(sample_buffer[offset + index], min, max));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,36 +181,67 @@ public:
|
||||||
queue.enqueue(buffer);
|
queue.enqueue(buffer);
|
||||||
queued_buffers++;
|
queued_buffers++;
|
||||||
} else {
|
} else {
|
||||||
static constexpr s32 min = std::numeric_limits<s16>::min();
|
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||||
static constexpr s32 max = std::numeric_limits<s16>::max();
|
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||||
|
|
||||||
auto yuzu_volume{Settings::Volume()};
|
auto yuzu_volume{Settings::Volume()};
|
||||||
auto volume{system_volume * device_volume * yuzu_volume};
|
auto volume{system_volume * device_volume * yuzu_volume};
|
||||||
|
|
||||||
if (system_channels == 6 && device_channels == 2) {
|
if (system_channels == 6 && device_channels == 2) {
|
||||||
std::array<f32, 4> down_mix_coeff{1.0f, 0.707f, 0.251f, 0.707f};
|
// We're given 6 channels, but our device only outputs 2, so downmix.
|
||||||
|
constexpr std::array<f32, 4> down_mix_coeff{1.0f, 0.707f, 0.251f, 0.707f};
|
||||||
|
|
||||||
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||||
read_index += system_channels, write_index += device_channels) {
|
read_index += system_channels, write_index += device_channels) {
|
||||||
const auto left_sample =
|
const auto left_sample{
|
||||||
((Common::FixedPoint<49, 15>(samples[read_index + 0]) * down_mix_coeff[0] +
|
((Common::FixedPoint<49, 15>(
|
||||||
samples[read_index + 2] * down_mix_coeff[1] +
|
samples[read_index + static_cast<u32>(Channels::FrontLeft)]) *
|
||||||
samples[read_index + 3] * down_mix_coeff[2] +
|
down_mix_coeff[0] +
|
||||||
samples[read_index + 4] * down_mix_coeff[3]) *
|
samples[read_index + static_cast<u32>(Channels::Center)] *
|
||||||
|
down_mix_coeff[1] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::LFE)] *
|
||||||
|
down_mix_coeff[2] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::BackLeft)] *
|
||||||
|
down_mix_coeff[3]) *
|
||||||
volume)
|
volume)
|
||||||
.to_int();
|
.to_int()};
|
||||||
|
|
||||||
const auto right_sample =
|
const auto right_sample{
|
||||||
((Common::FixedPoint<49, 15>(samples[read_index + 1]) * down_mix_coeff[0] +
|
((Common::FixedPoint<49, 15>(
|
||||||
samples[read_index + 2] * down_mix_coeff[1] +
|
samples[read_index + static_cast<u32>(Channels::FrontRight)]) *
|
||||||
samples[read_index + 3] * down_mix_coeff[2] +
|
down_mix_coeff[0] +
|
||||||
samples[read_index + 5] * down_mix_coeff[3]) *
|
samples[read_index + static_cast<u32>(Channels::Center)] *
|
||||||
|
down_mix_coeff[1] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::LFE)] *
|
||||||
|
down_mix_coeff[2] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::BackRight)] *
|
||||||
|
down_mix_coeff[3]) *
|
||||||
volume)
|
volume)
|
||||||
.to_int();
|
.to_int()};
|
||||||
|
|
||||||
samples[write_index + 0] = static_cast<s16>(std::clamp(left_sample, min, max));
|
samples[write_index + static_cast<u32>(Channels::FrontLeft)] =
|
||||||
samples[write_index + 1] = static_cast<s16>(std::clamp(right_sample, min, max));
|
static_cast<s16>(std::clamp(left_sample, min, max));
|
||||||
|
samples[write_index + static_cast<u32>(Channels::FrontRight)] =
|
||||||
|
static_cast<s16>(std::clamp(right_sample, min, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
samples.resize(samples.size() / system_channels * device_channels);
|
samples.resize(samples.size() / system_channels * device_channels);
|
||||||
|
|
||||||
|
} else if (system_channels == 2 && device_channels == 6) {
|
||||||
|
// We need moar samples! Not all games will provide 6 channel audio.
|
||||||
|
// TODO: Implement some upmixing here. Currently just passthrough, with other
|
||||||
|
// channels left as silence.
|
||||||
|
std::vector<s16> new_samples(samples.size() / system_channels * device_channels, 0);
|
||||||
|
|
||||||
|
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||||
|
read_index += system_channels, write_index += device_channels) {
|
||||||
|
new_samples[write_index + static_cast<u32>(Channels::FrontLeft)] =
|
||||||
|
samples[read_index + static_cast<u32>(Channels::FrontLeft)];
|
||||||
|
new_samples[write_index + static_cast<u32>(Channels::FrontRight)] =
|
||||||
|
samples[read_index + static_cast<u32>(Channels::FrontRight)];
|
||||||
|
}
|
||||||
|
samples = std::move(new_samples);
|
||||||
|
|
||||||
} else if (volume != 1.0f) {
|
} else if (volume != 1.0f) {
|
||||||
for (u32 i = 0; i < samples.size(); i++) {
|
for (u32 i = 0; i < samples.size(); i++) {
|
||||||
samples[i] = static_cast<s16>(std::clamp(
|
samples[i] = static_cast<s16>(std::clamp(
|
||||||
|
@ -499,7 +530,6 @@ CubebSink::CubebSink(std::string_view target_device_name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement upmixing, not all games will provide 6 channel audio.
|
|
||||||
cubeb_get_max_channel_count(ctx, &device_channels);
|
cubeb_get_max_channel_count(ctx, &device_channels);
|
||||||
device_channels = std::clamp(device_channels, 2U, 6U);
|
device_channels = std::clamp(device_channels, 2U, 6U);
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,40 +154,71 @@ public:
|
||||||
queue.enqueue(buffer);
|
queue.enqueue(buffer);
|
||||||
queued_buffers++;
|
queued_buffers++;
|
||||||
} else {
|
} else {
|
||||||
static constexpr s32 min = std::numeric_limits<s16>::min();
|
constexpr s32 min = std::numeric_limits<s16>::min();
|
||||||
static constexpr s32 max = std::numeric_limits<s16>::max();
|
constexpr s32 max = std::numeric_limits<s16>::max();
|
||||||
|
|
||||||
auto yuzu_volume{Settings::Volume()};
|
auto yuzu_volume{Settings::Volume()};
|
||||||
auto volume{system_volume * device_volume * yuzu_volume};
|
auto volume{system_volume * device_volume * yuzu_volume};
|
||||||
|
|
||||||
if (system_channels == 6 && device_channels == 2) {
|
if (system_channels == 6 && device_channels == 2) {
|
||||||
std::array<f32, 4> down_mix_coeff{1.0f, 0.707f, 0.251f, 0.707f};
|
// We're given 6 channels, but our device only outputs 2, so downmix.
|
||||||
|
constexpr std::array<f32, 4> down_mix_coeff{1.0f, 0.707f, 0.251f, 0.707f};
|
||||||
|
|
||||||
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||||
read_index += system_channels, write_index += device_channels) {
|
read_index += system_channels, write_index += device_channels) {
|
||||||
const auto left_sample =
|
const auto left_sample{
|
||||||
((Common::FixedPoint<49, 15>(samples[read_index + 0]) * down_mix_coeff[0] +
|
((Common::FixedPoint<49, 15>(
|
||||||
samples[read_index + 2] * down_mix_coeff[1] +
|
samples[read_index + static_cast<u32>(Channels::FrontLeft)]) *
|
||||||
samples[read_index + 3] * down_mix_coeff[2] +
|
down_mix_coeff[0] +
|
||||||
samples[read_index + 4] * down_mix_coeff[3]) *
|
samples[read_index + static_cast<u32>(Channels::Center)] *
|
||||||
|
down_mix_coeff[1] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::LFE)] *
|
||||||
|
down_mix_coeff[2] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::BackLeft)] *
|
||||||
|
down_mix_coeff[3]) *
|
||||||
volume)
|
volume)
|
||||||
.to_int();
|
.to_int()};
|
||||||
|
|
||||||
const auto right_sample =
|
const auto right_sample{
|
||||||
((Common::FixedPoint<49, 15>(samples[read_index + 1]) * down_mix_coeff[0] +
|
((Common::FixedPoint<49, 15>(
|
||||||
samples[read_index + 2] * down_mix_coeff[1] +
|
samples[read_index + static_cast<u32>(Channels::FrontRight)]) *
|
||||||
samples[read_index + 3] * down_mix_coeff[2] +
|
down_mix_coeff[0] +
|
||||||
samples[read_index + 5] * down_mix_coeff[3]) *
|
samples[read_index + static_cast<u32>(Channels::Center)] *
|
||||||
|
down_mix_coeff[1] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::LFE)] *
|
||||||
|
down_mix_coeff[2] +
|
||||||
|
samples[read_index + static_cast<u32>(Channels::BackRight)] *
|
||||||
|
down_mix_coeff[3]) *
|
||||||
volume)
|
volume)
|
||||||
.to_int();
|
.to_int()};
|
||||||
|
|
||||||
samples[write_index + 0] = static_cast<s16>(std::clamp(left_sample, min, max));
|
samples[write_index + static_cast<u32>(Channels::FrontLeft)] =
|
||||||
samples[write_index + 1] = static_cast<s16>(std::clamp(right_sample, min, max));
|
static_cast<s16>(std::clamp(left_sample, min, max));
|
||||||
|
samples[write_index + static_cast<u32>(Channels::FrontRight)] =
|
||||||
|
static_cast<s16>(std::clamp(right_sample, min, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
samples.resize(samples.size() / system_channels * device_channels);
|
samples.resize(samples.size() / system_channels * device_channels);
|
||||||
|
|
||||||
|
} else if (system_channels == 2 && device_channels == 6) {
|
||||||
|
// We need moar samples! Not all games will provide 6 channel audio.
|
||||||
|
// TODO: Implement some upmixing here. Currently just passthrough, with other
|
||||||
|
// channels left as silence.
|
||||||
|
std::vector<s16> new_samples(samples.size() / system_channels * device_channels, 0);
|
||||||
|
|
||||||
|
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||||
|
read_index += system_channels, write_index += device_channels) {
|
||||||
|
new_samples[write_index + static_cast<u32>(Channels::FrontLeft)] =
|
||||||
|
samples[read_index + static_cast<u32>(Channels::FrontLeft)];
|
||||||
|
new_samples[write_index + static_cast<u32>(Channels::FrontRight)] =
|
||||||
|
samples[read_index + static_cast<u32>(Channels::FrontRight)];
|
||||||
|
}
|
||||||
|
samples = std::move(new_samples);
|
||||||
|
|
||||||
} else if (volume != 1.0f) {
|
} else if (volume != 1.0f) {
|
||||||
for (u32 i = 0; i < samples.size(); i++) {
|
for (u32 i = 0; i < samples.size(); i++) {
|
||||||
auto sample{Common::FixedPoint<49, 15>(samples[i]) * volume};
|
samples[i] = static_cast<s16>(std::clamp(
|
||||||
samples[i] = static_cast<s16>(std::clamp(sample.to_int(), min, max));
|
static_cast<s32>(static_cast<f32>(samples[i]) * volume), min, max));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue