mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-01 23:12:35 +00:00
audio3d: Convert and retain sample buffers when queued.
This commit is contained in:
parent
46006806c8
commit
0a731b2cc0
@ -83,6 +83,36 @@ int PS4_SYSV_ABI sceAudio3dAudioOutOutputs(AudioOut::OrbisAudioOutOutputParam* p
|
|||||||
return AudioOut::sceAudioOutOutputs(param, num);
|
return AudioOut::sceAudioOutOutputs(param, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static s32 PortQueueAudio(Port& port, const OrbisAudio3dPcm& pcm) {
|
||||||
|
const SDL_AudioSpec src_spec = {
|
||||||
|
.format = pcm.format == ORBIS_AUDIO3D_FORMAT_S16 ? SDL_AUDIO_S16LE : SDL_AUDIO_F32LE,
|
||||||
|
.channels = AUDIO3D_INPUT_NUM_CHANNELS,
|
||||||
|
.freq = AUDIO3D_SAMPLE_RATE,
|
||||||
|
};
|
||||||
|
constexpr SDL_AudioSpec dst_spec = {
|
||||||
|
.format = SDL_AUDIO_S16LE,
|
||||||
|
.channels = AUDIO3D_OUTPUT_NUM_CHANNELS,
|
||||||
|
.freq = AUDIO3D_SAMPLE_RATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto pcm_size = pcm.num_samples * (pcm.format == ORBIS_AUDIO3D_FORMAT_S16 ? 2 : 4) *
|
||||||
|
AUDIO3D_INPUT_NUM_CHANNELS;
|
||||||
|
|
||||||
|
u8* dst_data;
|
||||||
|
int dst_len;
|
||||||
|
if (!SDL_ConvertAudioSamples(&src_spec, static_cast<u8*>(pcm.sample_buffer),
|
||||||
|
static_cast<int>(pcm_size), &dst_spec, &dst_data, &dst_len)) {
|
||||||
|
LOG_ERROR(Lib_Audio3d, "SDL_ConvertAudioSamples failed: {}", SDL_GetError());
|
||||||
|
return ORBIS_AUDIO3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
port.queue.emplace_back(AudioData{
|
||||||
|
.sample_buffer = dst_data,
|
||||||
|
.num_samples = pcm.num_samples,
|
||||||
|
});
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAudio3dBedWrite(const OrbisAudio3dPortId port_id, const u32 num_channels,
|
int PS4_SYSV_ABI sceAudio3dBedWrite(const OrbisAudio3dPortId port_id, const u32 num_channels,
|
||||||
const OrbisAudio3dFormat format, void* buffer,
|
const OrbisAudio3dFormat format, void* buffer,
|
||||||
const u32 num_samples) {
|
const u32 num_samples) {
|
||||||
@ -123,13 +153,12 @@ int PS4_SYSV_ABI sceAudio3dBedWrite2(const OrbisAudio3dPortId port_id, const u32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state->ports[port_id].queue.emplace_back(OrbisAudio3dPcm{
|
const OrbisAudio3dPcm pcm = {
|
||||||
.format = format,
|
.format = format,
|
||||||
.sample_buffer = buffer,
|
.sample_buffer = buffer,
|
||||||
.num_samples = num_samples,
|
.num_samples = num_samples,
|
||||||
});
|
};
|
||||||
|
return PortQueueAudio(state->ports[port_id], pcm);
|
||||||
return ORBIS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||||
@ -227,16 +256,20 @@ int PS4_SYSV_ABI sceAudio3dObjectSetAttributes(const OrbisAudio3dPortId port_id,
|
|||||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& port = state->ports[port_id];
|
||||||
|
|
||||||
for (size_t i = 0; i < num_attributes; i++) {
|
for (size_t i = 0; i < num_attributes; i++) {
|
||||||
const auto& attribute = attribute_array[i];
|
const auto& attribute = attribute_array[i];
|
||||||
|
|
||||||
switch (attribute.attribute_id) {
|
switch (attribute.attribute_id) {
|
||||||
case 0x00000001: { // PCM
|
case 0x00000001: { // PCM
|
||||||
const auto pcm_attribute = static_cast<OrbisAudio3dPcm*>(attribute.value);
|
const auto pcm = static_cast<OrbisAudio3dPcm*>(attribute.value);
|
||||||
state->ports[port_id].queue.emplace_back(*pcm_attribute);
|
if (const auto ret = PortQueueAudio(port, *pcm); ret != ORBIS_OK) {
|
||||||
break;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
LOG_ERROR(Lib_Audio3d, "Unsupported attribute ID: {:#x}", attribute.attribute_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,13 +296,18 @@ int PS4_SYSV_ABI sceAudio3dPortAdvance(const OrbisAudio3dPortId port_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& port = state->ports[port_id];
|
auto& port = state->ports[port_id];
|
||||||
port.has_buffer = !port.queue.empty();
|
if (port.current_buffer.has_value()) {
|
||||||
if (port.has_buffer) {
|
// Free existing buffer before replacing.
|
||||||
|
SDL_free(port.current_buffer->sample_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!port.queue.empty()) {
|
||||||
port.current_buffer = port.queue.front();
|
port.current_buffer = port.queue.front();
|
||||||
port.queue.pop_front();
|
port.queue.pop_front();
|
||||||
} else {
|
} else {
|
||||||
// Nothing to advance to.
|
// Nothing to advance to.
|
||||||
LOG_DEBUG(Lib_Audio3d, "Port advance with no buffer queued");
|
LOG_DEBUG(Lib_Audio3d, "Port advance with no buffer queued");
|
||||||
|
port.current_buffer = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -398,40 +436,15 @@ int PS4_SYSV_ABI sceAudio3dPortPush(const OrbisAudio3dPortId port_id,
|
|||||||
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
|
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!port.has_buffer) {
|
if (!port.current_buffer.has_value()) {
|
||||||
// Nothing to push.
|
// Nothing to push.
|
||||||
LOG_DEBUG(Lib_Audio3d, "Port push with no buffer ready");
|
LOG_DEBUG(Lib_Audio3d, "Port push with no buffer ready");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 src_size =
|
|
||||||
port.current_buffer.num_samples * sizeof(float) * AUDIO3D_INPUT_NUM_CHANNELS;
|
|
||||||
const SDL_AudioSpec src_spec = {
|
|
||||||
.format = port.current_buffer.format == ORBIS_AUDIO3D_FORMAT_S16 ? SDL_AUDIO_S16LE
|
|
||||||
: SDL_AUDIO_F32LE,
|
|
||||||
.channels = AUDIO3D_INPUT_NUM_CHANNELS,
|
|
||||||
.freq = AUDIO3D_SAMPLE_RATE,
|
|
||||||
};
|
|
||||||
constexpr SDL_AudioSpec dst_spec = {
|
|
||||||
.format = SDL_AUDIO_S16LE,
|
|
||||||
.channels = AUDIO3D_OUTPUT_NUM_CHANNELS,
|
|
||||||
.freq = AUDIO3D_SAMPLE_RATE,
|
|
||||||
};
|
|
||||||
|
|
||||||
u8* dst_data;
|
|
||||||
int dst_len;
|
|
||||||
if (!SDL_ConvertAudioSamples(&src_spec,
|
|
||||||
static_cast<const Uint8*>(port.current_buffer.sample_buffer),
|
|
||||||
static_cast<int>(src_size), &dst_spec, &dst_data, &dst_len)) {
|
|
||||||
LOG_ERROR(Lib_Audio3d, "SDL_ConvertAudioSamples failed: {}", SDL_GetError());
|
|
||||||
return ORBIS_AUDIO3D_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement asynchronous blocking mode.
|
// TODO: Implement asynchronous blocking mode.
|
||||||
const auto ret = AudioOut::sceAudioOutOutput(state->audio_out_handle, dst_data);
|
const auto& [sample_buffer, num_samples] = port.current_buffer.value();
|
||||||
SDL_free(dst_data);
|
return AudioOut::sceAudioOutOutput(state->audio_out_handle, sample_buffer);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
|
int PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
@ -62,12 +63,15 @@ struct OrbisAudio3dAttribute {
|
|||||||
size_t value_size;
|
size_t value_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AudioData {
|
||||||
|
u8* sample_buffer;
|
||||||
|
u32 num_samples;
|
||||||
|
};
|
||||||
|
|
||||||
struct Port {
|
struct Port {
|
||||||
OrbisAudio3dOpenParameters parameters{};
|
OrbisAudio3dOpenParameters parameters{};
|
||||||
std::deque<OrbisAudio3dPcm> queue; // Only stores PCM buffers for now
|
std::deque<AudioData> queue; // Only stores PCM buffers for now
|
||||||
|
std::optional<AudioData> current_buffer{};
|
||||||
bool has_buffer{false};
|
|
||||||
OrbisAudio3dPcm current_buffer{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Audio3dState {
|
struct Audio3dState {
|
||||||
|
Loading…
Reference in New Issue
Block a user