audio_core: Use s16 where possible for audio samples.
This commit is contained in:
parent
f1cb3903ac
commit
1dee8ceda1
|
@ -51,7 +51,7 @@ void AudioOut::StopStream(StreamPtr stream) {
|
||||||
stream->Stop();
|
stream->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioOut::QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<u8>&& data) {
|
bool AudioOut::QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<s16>&& data) {
|
||||||
return stream->QueueBuffer(std::make_shared<Buffer>(tag, std::move(data)));
|
return stream->QueueBuffer(std::make_shared<Buffer>(tag, std::move(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
void StopStream(StreamPtr stream);
|
void StopStream(StreamPtr stream);
|
||||||
|
|
||||||
/// Queues a buffer into the specified audio stream, returns true on success
|
/// Queues a buffer into the specified audio stream, returns true on success
|
||||||
bool QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<u8>&& data);
|
bool QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<s16>&& data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SinkPtr sink;
|
SinkPtr sink;
|
||||||
|
|
|
@ -18,11 +18,16 @@ class Buffer {
|
||||||
public:
|
public:
|
||||||
using Tag = u64;
|
using Tag = u64;
|
||||||
|
|
||||||
Buffer(Tag tag, std::vector<u8>&& data) : tag{tag}, data{std::move(data)} {}
|
Buffer(Tag tag, std::vector<s16>&& samples) : tag{tag}, samples{std::move(samples)} {}
|
||||||
|
|
||||||
/// Returns the raw audio data for the buffer
|
/// Returns the raw audio data for the buffer
|
||||||
const std::vector<u8>& GetData() const {
|
std::vector<s16>& Samples() {
|
||||||
return data;
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the raw audio data for the buffer
|
||||||
|
const std::vector<s16>& GetSamples() const {
|
||||||
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the buffer tag, this is provided by the game to the audout service
|
/// Returns the buffer tag, this is provided by the game to the audout service
|
||||||
|
@ -32,7 +37,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Tag tag;
|
Tag tag;
|
||||||
std::vector<u8> data;
|
std::vector<s16> samples;
|
||||||
};
|
};
|
||||||
|
|
||||||
using BufferPtr = std::shared_ptr<Buffer>;
|
using BufferPtr = std::shared_ptr<Buffer>;
|
||||||
|
|
|
@ -61,25 +61,24 @@ public:
|
||||||
cubeb_stream_destroy(stream_backend);
|
cubeb_stream_destroy(stream_backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnqueueSamples(u32 num_channels, const s16* samples, size_t sample_count) override {
|
void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) override {
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.reserve(queue.size() + sample_count * GetNumChannels());
|
queue.reserve(queue.size() + samples.size() * GetNumChannels());
|
||||||
|
|
||||||
if (is_6_channel) {
|
if (is_6_channel) {
|
||||||
// Downsample 6 channels to 2
|
// Downsample 6 channels to 2
|
||||||
const size_t sample_count_copy_size = sample_count * num_channels * 2;
|
const size_t sample_count_copy_size = samples.size() * 2;
|
||||||
queue.reserve(sample_count_copy_size);
|
queue.reserve(sample_count_copy_size);
|
||||||
for (size_t i = 0; i < sample_count * num_channels; i += num_channels) {
|
for (size_t i = 0; i < samples.size(); i += num_channels) {
|
||||||
queue.push_back(samples[i]);
|
queue.push_back(samples[i]);
|
||||||
queue.push_back(samples[i + 1]);
|
queue.push_back(samples[i + 1]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Copy as-is
|
// Copy as-is
|
||||||
std::copy(samples, samples + sample_count * GetNumChannels(),
|
std::copy(samples.begin(), samples.end(), std::back_inserter(queue));
|
||||||
std::back_inserter(queue));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct NullSinkStreamImpl final : SinkStream {
|
struct NullSinkStreamImpl final : SinkStream {
|
||||||
void EnqueueSamples(u32 /*num_channels*/, const s16* /*samples*/,
|
void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {}
|
||||||
size_t /*sample_count*/) override {}
|
|
||||||
} null_sink_stream;
|
} null_sink_stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
@ -22,9 +23,8 @@ public:
|
||||||
* Feed stereo samples to sink.
|
* Feed stereo samples to sink.
|
||||||
* @param num_channels Number of channels used.
|
* @param num_channels Number of channels used.
|
||||||
* @param samples Samples in interleaved stereo PCM16 format.
|
* @param samples Samples in interleaved stereo PCM16 format.
|
||||||
* @param sample_count Number of samples.
|
|
||||||
*/
|
*/
|
||||||
virtual void EnqueueSamples(u32 num_channels, const s16* samples, size_t sample_count) = 0;
|
virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SinkStreamPtr = std::unique_ptr<SinkStream>;
|
using SinkStreamPtr = std::unique_ptr<SinkStream>;
|
||||||
|
|
|
@ -32,10 +32,6 @@ u32 Stream::GetNumChannels() const {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Stream::GetSampleSize() const {
|
|
||||||
return GetNumChannels() * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback,
|
Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback,
|
||||||
SinkStream& sink_stream, std::string&& name_)
|
SinkStream& sink_stream, std::string&& name_)
|
||||||
: sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)},
|
: sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)},
|
||||||
|
@ -55,17 +51,15 @@ void Stream::Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
|
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
|
||||||
const size_t num_samples{buffer.GetData().size() / GetSampleSize()};
|
const size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
|
||||||
return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
|
return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<s16> GetVolumeAdjustedSamples(const std::vector<u8>& data) {
|
static void VolumeAdjustSamples(std::vector<s16>& samples) {
|
||||||
std::vector<s16> samples(data.size() / sizeof(s16));
|
|
||||||
std::memcpy(samples.data(), data.data(), data.size());
|
|
||||||
const float volume{std::clamp(Settings::values.volume, 0.0f, 1.0f)};
|
const float volume{std::clamp(Settings::values.volume, 0.0f, 1.0f)};
|
||||||
|
|
||||||
if (volume == 1.0f) {
|
if (volume == 1.0f) {
|
||||||
return samples;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of a volume slider with a dynamic range of 60 dB
|
// Implementation of a volume slider with a dynamic range of 60 dB
|
||||||
|
@ -73,8 +67,6 @@ static std::vector<s16> GetVolumeAdjustedSamples(const std::vector<u8>& data) {
|
||||||
for (auto& sample : samples) {
|
for (auto& sample : samples) {
|
||||||
sample = static_cast<s16>(sample * volume_scale_factor);
|
sample = static_cast<s16>(sample * volume_scale_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return samples;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::PlayNextBuffer() {
|
void Stream::PlayNextBuffer() {
|
||||||
|
@ -96,9 +88,8 @@ void Stream::PlayNextBuffer() {
|
||||||
active_buffer = queued_buffers.front();
|
active_buffer = queued_buffers.front();
|
||||||
queued_buffers.pop();
|
queued_buffers.pop();
|
||||||
|
|
||||||
const size_t sample_count{active_buffer->GetData().size() / GetSampleSize()};
|
VolumeAdjustSamples(active_buffer->Samples());
|
||||||
sink_stream.EnqueueSamples(
|
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
|
||||||
GetNumChannels(), GetVolumeAdjustedSamples(active_buffer->GetData()).data(), sample_count);
|
|
||||||
|
|
||||||
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
|
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,9 +69,6 @@ public:
|
||||||
/// Gets the number of channels
|
/// Gets the number of channels
|
||||||
u32 GetNumChannels() const;
|
u32 GetNumChannels() const;
|
||||||
|
|
||||||
/// Gets the sample size in bytes
|
|
||||||
u32 GetSampleSize() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Current state of the stream
|
/// Current state of the stream
|
||||||
enum class State {
|
enum class State {
|
||||||
|
|
|
@ -113,10 +113,10 @@ private:
|
||||||
std::memcpy(&audio_buffer, input_buffer.data(), sizeof(AudioBuffer));
|
std::memcpy(&audio_buffer, input_buffer.data(), sizeof(AudioBuffer));
|
||||||
const u64 tag{rp.Pop<u64>()};
|
const u64 tag{rp.Pop<u64>()};
|
||||||
|
|
||||||
std::vector<u8> data(audio_buffer.buffer_size);
|
std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
|
||||||
Memory::ReadBlock(audio_buffer.buffer, data.data(), data.size());
|
Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
|
||||||
|
|
||||||
if (!audio_core.QueueBuffer(stream, tag, std::move(data))) {
|
if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded));
|
rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded));
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue