|
|
@ -66,7 +66,7 @@ void ServerVoiceInfo::Initialize() {
|
|
|
|
in_params.last_volume = 0.0f;
|
|
|
|
in_params.last_volume = 0.0f;
|
|
|
|
in_params.biquad_filter.fill({});
|
|
|
|
in_params.biquad_filter.fill({});
|
|
|
|
in_params.wave_buffer_count = 0;
|
|
|
|
in_params.wave_buffer_count = 0;
|
|
|
|
in_params.wave_bufffer_head = 0;
|
|
|
|
in_params.wave_buffer_head = 0;
|
|
|
|
in_params.mix_id = AudioCommon::NO_MIX;
|
|
|
|
in_params.mix_id = AudioCommon::NO_MIX;
|
|
|
|
in_params.splitter_info_id = AudioCommon::NO_SPLITTER;
|
|
|
|
in_params.splitter_info_id = AudioCommon::NO_SPLITTER;
|
|
|
|
in_params.additional_params_address = 0;
|
|
|
|
in_params.additional_params_address = 0;
|
|
|
@ -75,7 +75,7 @@ void ServerVoiceInfo::Initialize() {
|
|
|
|
out_params.played_sample_count = 0;
|
|
|
|
out_params.played_sample_count = 0;
|
|
|
|
out_params.wave_buffer_consumed = 0;
|
|
|
|
out_params.wave_buffer_consumed = 0;
|
|
|
|
in_params.voice_drop_flag = false;
|
|
|
|
in_params.voice_drop_flag = false;
|
|
|
|
in_params.buffer_mapped = false;
|
|
|
|
in_params.buffer_mapped = true;
|
|
|
|
in_params.wave_buffer_flush_request_count = 0;
|
|
|
|
in_params.wave_buffer_flush_request_count = 0;
|
|
|
|
in_params.was_biquad_filter_enabled.fill(false);
|
|
|
|
in_params.was_biquad_filter_enabled.fill(false);
|
|
|
|
|
|
|
|
|
|
|
@ -126,7 +126,7 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
|
|
|
|
in_params.volume = voice_in.volume;
|
|
|
|
in_params.volume = voice_in.volume;
|
|
|
|
in_params.biquad_filter = voice_in.biquad_filter;
|
|
|
|
in_params.biquad_filter = voice_in.biquad_filter;
|
|
|
|
in_params.wave_buffer_count = voice_in.wave_buffer_count;
|
|
|
|
in_params.wave_buffer_count = voice_in.wave_buffer_count;
|
|
|
|
in_params.wave_bufffer_head = voice_in.wave_buffer_head;
|
|
|
|
in_params.wave_buffer_head = voice_in.wave_buffer_head;
|
|
|
|
if (behavior_info.IsFlushVoiceWaveBuffersSupported()) {
|
|
|
|
if (behavior_info.IsFlushVoiceWaveBuffersSupported()) {
|
|
|
|
const auto in_request_count = in_params.wave_buffer_flush_request_count;
|
|
|
|
const auto in_request_count = in_params.wave_buffer_flush_request_count;
|
|
|
|
const auto voice_request_count = voice_in.wave_buffer_flush_request_count;
|
|
|
|
const auto voice_request_count = voice_in.wave_buffer_flush_request_count;
|
|
|
@ -185,14 +185,16 @@ void ServerVoiceInfo::UpdateWaveBuffers(
|
|
|
|
wave_buffer.buffer_size = 0;
|
|
|
|
wave_buffer.buffer_size = 0;
|
|
|
|
wave_buffer.context_address = 0;
|
|
|
|
wave_buffer.context_address = 0;
|
|
|
|
wave_buffer.context_size = 0;
|
|
|
|
wave_buffer.context_size = 0;
|
|
|
|
|
|
|
|
wave_buffer.loop_start_sample = 0;
|
|
|
|
|
|
|
|
wave_buffer.loop_end_sample = 0;
|
|
|
|
wave_buffer.sent_to_dsp = true;
|
|
|
|
wave_buffer.sent_to_dsp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Mark all our wave buffers as invalid
|
|
|
|
// Mark all our wave buffers as invalid
|
|
|
|
for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count);
|
|
|
|
for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count);
|
|
|
|
channel++) {
|
|
|
|
channel++) {
|
|
|
|
for (auto& is_valid : voice_states[channel]->is_wave_buffer_valid) {
|
|
|
|
for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; ++i) {
|
|
|
|
is_valid = false;
|
|
|
|
voice_states[channel]->is_wave_buffer_valid[i] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -211,7 +213,7 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
|
|
|
|
const WaveBuffer& in_wave_buffer, SampleFormat sample_format,
|
|
|
|
const WaveBuffer& in_wave_buffer, SampleFormat sample_format,
|
|
|
|
bool is_buffer_valid,
|
|
|
|
bool is_buffer_valid,
|
|
|
|
[[maybe_unused]] BehaviorInfo& behavior_info) {
|
|
|
|
[[maybe_unused]] BehaviorInfo& behavior_info) {
|
|
|
|
if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) {
|
|
|
|
if (!is_buffer_valid && out_wavebuffer.sent_to_dsp && out_wavebuffer.buffer_address != 0) {
|
|
|
|
out_wavebuffer.buffer_address = 0;
|
|
|
|
out_wavebuffer.buffer_address = 0;
|
|
|
|
out_wavebuffer.buffer_size = 0;
|
|
|
|
out_wavebuffer.buffer_size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -219,11 +221,40 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
|
|
|
|
if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) {
|
|
|
|
if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) {
|
|
|
|
// Validate sample offset sizings
|
|
|
|
// Validate sample offset sizings
|
|
|
|
if (sample_format == SampleFormat::Pcm16) {
|
|
|
|
if (sample_format == SampleFormat::Pcm16) {
|
|
|
|
const auto buffer_size = in_wave_buffer.buffer_size;
|
|
|
|
const s64 buffer_size = static_cast<s64>(in_wave_buffer.buffer_size);
|
|
|
|
if (in_wave_buffer.start_sample_offset < 0 || in_wave_buffer.end_sample_offset < 0 ||
|
|
|
|
const s64 start = sizeof(s16) * in_wave_buffer.start_sample_offset;
|
|
|
|
(buffer_size < (sizeof(s16) * in_wave_buffer.start_sample_offset)) ||
|
|
|
|
const s64 end = sizeof(s16) * in_wave_buffer.end_sample_offset;
|
|
|
|
(buffer_size < (sizeof(s16) * in_wave_buffer.end_sample_offset))) {
|
|
|
|
if (0 > start || start > buffer_size || 0 > end || end > buffer_size) {
|
|
|
|
// TODO(ogniK): Write error info
|
|
|
|
// TODO(ogniK): Write error info
|
|
|
|
|
|
|
|
LOG_ERROR(Audio,
|
|
|
|
|
|
|
|
"PCM16 wavebuffer has an invalid size. Buffer has size 0x{:08X}, but "
|
|
|
|
|
|
|
|
"offsets were "
|
|
|
|
|
|
|
|
"{:08X} - 0x{:08X}",
|
|
|
|
|
|
|
|
buffer_size, sizeof(s16) * in_wave_buffer.start_sample_offset,
|
|
|
|
|
|
|
|
sizeof(s16) * in_wave_buffer.end_sample_offset);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (sample_format == SampleFormat::Adpcm) {
|
|
|
|
|
|
|
|
const s64 buffer_size = static_cast<s64>(in_wave_buffer.buffer_size);
|
|
|
|
|
|
|
|
const s64 start_frames = in_wave_buffer.start_sample_offset / 14;
|
|
|
|
|
|
|
|
const s64 start_extra = in_wave_buffer.start_sample_offset % 14 == 0
|
|
|
|
|
|
|
|
? 0
|
|
|
|
|
|
|
|
: (in_wave_buffer.start_sample_offset % 14) / 2 + 1 +
|
|
|
|
|
|
|
|
(in_wave_buffer.start_sample_offset % 2);
|
|
|
|
|
|
|
|
const s64 start = start_frames * 8 + start_extra;
|
|
|
|
|
|
|
|
const s64 end_frames = in_wave_buffer.end_sample_offset / 14;
|
|
|
|
|
|
|
|
const s64 end_extra = in_wave_buffer.end_sample_offset % 14 == 0
|
|
|
|
|
|
|
|
? 0
|
|
|
|
|
|
|
|
: (in_wave_buffer.end_sample_offset % 14) / 2 + 1 +
|
|
|
|
|
|
|
|
(in_wave_buffer.end_sample_offset % 2);
|
|
|
|
|
|
|
|
const s64 end = end_frames * 8 + end_extra;
|
|
|
|
|
|
|
|
if (in_wave_buffer.start_sample_offset < 0 || start > buffer_size ||
|
|
|
|
|
|
|
|
in_wave_buffer.end_sample_offset < 0 || end > buffer_size) {
|
|
|
|
|
|
|
|
LOG_ERROR(Audio,
|
|
|
|
|
|
|
|
"ADPMC wavebuffer has an invalid size. Buffer has size 0x{:08X}, but "
|
|
|
|
|
|
|
|
"offsets were "
|
|
|
|
|
|
|
|
"{:08X} - 0x{:08X}",
|
|
|
|
|
|
|
|
in_wave_buffer.buffer_size, start, end);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -239,29 +270,34 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
|
|
|
|
out_wavebuffer.buffer_size = in_wave_buffer.buffer_size;
|
|
|
|
out_wavebuffer.buffer_size = in_wave_buffer.buffer_size;
|
|
|
|
out_wavebuffer.context_address = in_wave_buffer.context_address;
|
|
|
|
out_wavebuffer.context_address = in_wave_buffer.context_address;
|
|
|
|
out_wavebuffer.context_size = in_wave_buffer.context_size;
|
|
|
|
out_wavebuffer.context_size = in_wave_buffer.context_size;
|
|
|
|
|
|
|
|
out_wavebuffer.loop_start_sample = in_wave_buffer.loop_start_sample;
|
|
|
|
|
|
|
|
out_wavebuffer.loop_end_sample = in_wave_buffer.loop_end_sample;
|
|
|
|
in_params.buffer_mapped =
|
|
|
|
in_params.buffer_mapped =
|
|
|
|
in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0;
|
|
|
|
in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0;
|
|
|
|
// TODO(ogniK): Pool mapper attachment
|
|
|
|
// TODO(ogniK): Pool mapper attachment
|
|
|
|
// TODO(ogniK): IsAdpcmLoopContextBugFixed
|
|
|
|
// TODO(ogniK): IsAdpcmLoopContextBugFixed
|
|
|
|
|
|
|
|
if (sample_format == SampleFormat::Adpcm && in_wave_buffer.context_address != 0 &&
|
|
|
|
|
|
|
|
in_wave_buffer.context_size != 0 && behavior_info.IsAdpcmLoopContextBugFixed()) {
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
out_wavebuffer.context_address = 0;
|
|
|
|
|
|
|
|
out_wavebuffer.context_size = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ServerVoiceInfo::WriteOutStatus(
|
|
|
|
void ServerVoiceInfo::WriteOutStatus(
|
|
|
|
VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in,
|
|
|
|
VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in,
|
|
|
|
std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) {
|
|
|
|
std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) {
|
|
|
|
if (voice_in.is_new) {
|
|
|
|
if (voice_in.is_new || in_params.is_new) {
|
|
|
|
in_params.is_new = true;
|
|
|
|
in_params.is_new = true;
|
|
|
|
voice_out.wave_buffer_consumed = 0;
|
|
|
|
voice_out.wave_buffer_consumed = 0;
|
|
|
|
voice_out.played_sample_count = 0;
|
|
|
|
voice_out.played_sample_count = 0;
|
|
|
|
voice_out.voice_dropped = false;
|
|
|
|
voice_out.voice_dropped = false;
|
|
|
|
} else if (!in_params.is_new) {
|
|
|
|
|
|
|
|
voice_out.wave_buffer_consumed = voice_states[0]->wave_buffer_consumed;
|
|
|
|
|
|
|
|
voice_out.played_sample_count = voice_states[0]->played_sample_count;
|
|
|
|
|
|
|
|
voice_out.voice_dropped = in_params.voice_drop_flag;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
voice_out.wave_buffer_consumed = 0;
|
|
|
|
const auto& state = voice_states[0];
|
|
|
|
voice_out.played_sample_count = 0;
|
|
|
|
voice_out.wave_buffer_consumed = state->wave_buffer_consumed;
|
|
|
|
voice_out.voice_dropped = false;
|
|
|
|
voice_out.played_sample_count = state->played_sample_count;
|
|
|
|
|
|
|
|
voice_out.voice_dropped = state->voice_dropped;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -283,7 +319,8 @@ ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() {
|
|
|
|
|
|
|
|
|
|
|
|
bool ServerVoiceInfo::ShouldSkip() const {
|
|
|
|
bool ServerVoiceInfo::ShouldSkip() const {
|
|
|
|
// TODO(ogniK): Handle unmapped wave buffers or parameters
|
|
|
|
// TODO(ogniK): Handle unmapped wave buffers or parameters
|
|
|
|
return !in_params.in_use || (in_params.wave_buffer_count == 0) || in_params.voice_drop_flag;
|
|
|
|
return !in_params.in_use || in_params.wave_buffer_count == 0 || !in_params.buffer_mapped ||
|
|
|
|
|
|
|
|
in_params.voice_drop_flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) {
|
|
|
|
bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) {
|
|
|
@ -381,7 +418,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration(
|
|
|
|
void ServerVoiceInfo::FlushWaveBuffers(
|
|
|
|
void ServerVoiceInfo::FlushWaveBuffers(
|
|
|
|
u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states,
|
|
|
|
u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states,
|
|
|
|
s32 channel_count) {
|
|
|
|
s32 channel_count) {
|
|
|
|
auto wave_head = in_params.wave_bufffer_head;
|
|
|
|
auto wave_head = in_params.wave_buffer_head;
|
|
|
|
|
|
|
|
|
|
|
|
for (u8 i = 0; i < flush_count; i++) {
|
|
|
|
for (u8 i = 0; i < flush_count; i++) {
|
|
|
|
in_params.wave_buffer[wave_head].sent_to_dsp = true;
|
|
|
|
in_params.wave_buffer[wave_head].sent_to_dsp = true;
|
|
|
@ -401,6 +438,17 @@ bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const {
|
|
|
|
return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end();
|
|
|
|
return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ServerVoiceInfo::SetWaveBufferCompleted(VoiceState& dsp_state,
|
|
|
|
|
|
|
|
const ServerWaveBuffer& wave_buffer) {
|
|
|
|
|
|
|
|
dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index] = false;
|
|
|
|
|
|
|
|
dsp_state.wave_buffer_consumed++;
|
|
|
|
|
|
|
|
dsp_state.wave_buffer_index = (dsp_state.wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
|
|
|
|
|
|
|
|
dsp_state.loop_count = 0;
|
|
|
|
|
|
|
|
if (wave_buffer.end_of_stream) {
|
|
|
|
|
|
|
|
dsp_state.played_sample_count = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} {
|
|
|
|
VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} {
|
|
|
|
for (std::size_t i = 0; i < voice_count; i++) {
|
|
|
|
for (std::size_t i = 0; i < voice_count; i++) {
|
|
|
|
voice_channel_resources.emplace_back(static_cast<s32>(i));
|
|
|
|
voice_channel_resources.emplace_back(static_cast<s32>(i));
|
|
|
|