From 134682bdc52370cf999d1218a0e54be17c84f316 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 9 Apr 2024 15:54:03 +0200 Subject: [PATCH] Sound loading: Fix issues where ov_read skips samples --- src/client/sound/ogg_file.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/client/sound/ogg_file.cpp b/src/client/sound/ogg_file.cpp index 17bc7be20..11659c706 100644 --- a/src/client/sound/ogg_file.cpp +++ b/src/client/sound/ogg_file.cpp @@ -184,13 +184,15 @@ RAIIALSoundBuffer RAIIOggFile::loadBuffer(const OggFileDecodeInfo &decode_info, assert(pcm_start <= decode_info.length_samples); // seek - if (ov_pcm_tell(&m_file) != pcm_start) { + s64 current_pcm = ov_pcm_tell(&m_file); + if (current_pcm != pcm_start) { if (ov_pcm_seek(&m_file, pcm_start) != 0) { - warningstream << "Audio: Error decoding (could not seek) " + warningstream << "Audio: Error decoding (could not seek): " << decode_info.name_for_logging << std::endl; return RAIIALSoundBuffer(); } assert(ov_pcm_tell(&m_file) == pcm_start); + current_pcm = pcm_start; } const size_t size = static_cast(pcm_end - pcm_start) @@ -199,6 +201,7 @@ RAIIALSoundBuffer RAIIOggFile::loadBuffer(const OggFileDecodeInfo &decode_info, std::unique_ptr snd_buffer(new char[size]); // read size bytes + s64 last_byte_offset = current_pcm * decode_info.bytes_per_sample; size_t read_count = 0; int bitstream; while (read_count < size) { @@ -221,6 +224,25 @@ RAIIALSoundBuffer RAIIOggFile::loadBuffer(const OggFileDecodeInfo &decode_info, return RAIIALSoundBuffer(); } + // This usually doesn't happen, but for some sounds ov_read seems to skip + // some samples, see #14453. + s64 current_byte_offset = ov_pcm_tell(&m_file) * decode_info.bytes_per_sample; + if (current_byte_offset != last_byte_offset + num_bytes) { + infostream << "Audio: ov_read skipped " + << current_byte_offset - (last_byte_offset + num_bytes) + << " bytes, re-seeking: " + << decode_info.name_for_logging << std::endl; + s64 expected_offset = (last_byte_offset + num_bytes) / decode_info.bytes_per_sample; + if (ov_pcm_seek(&m_file, expected_offset) != 0) { + warningstream << "Audio: Error decoding (could not seek): " + << decode_info.name_for_logging << std::endl; + return RAIIALSoundBuffer(); + } + assert(ov_pcm_tell(&m_file) == expected_offset); + current_byte_offset = last_byte_offset + num_bytes; + } + last_byte_offset = current_byte_offset; + read_count += num_bytes; }