Small rewrites on how the audio callback works ... no good indication that this solved the problem but who knows ?

This commit is contained in:
Stepland 2023-07-24 01:10:05 +02:00
parent 8515f16d87
commit 2cac1645fa
2 changed files with 99 additions and 72 deletions

View File

@ -2,60 +2,84 @@
#include <limits> #include <limits>
std::optional<Slice> compute_sample_slice(
const std::int64_t buffer_start,
const std::int64_t buffer_size,
const std::int64_t sample_start,
const std::int64_t sample_size,
const std::optional<std::int64_t> next_sample_start
) {
const auto buffer_end = buffer_start + buffer_size;
const auto sample_end = sample_start + sample_size;
const auto sample_deoverlapped_end = [&](){
if (next_sample_start.has_value()) {
return std::min(*next_sample_start, sample_end);
} else {
return sample_end;
}
}();
const auto sample_slice_start = std::max(sample_start, buffer_start);
const auto sample_slice_end = std::min(sample_deoverlapped_end, buffer_end);
const auto slice_size = sample_slice_end - sample_slice_start;
const auto slice_start_relative_to_sample_start = sample_slice_start - sample_start;
const auto slice_start_relative_to_buffer_start = sample_slice_start - buffer_start;
// all the possible error cases I could think of
if (
sample_deoverlapped_end <= buffer_start
or sample_start >= buffer_end
or slice_size <= 0
) {
return {};
} else {
return Slice{
.start_in_sample=slice_start_relative_to_sample_start,
.size=slice_size,
.start_in_buffer=slice_start_relative_to_buffer_start,
.ends_in_this_buffer=sample_deoverlapped_end <= buffer_end
};
}
}
void copy_sample_at_points( void copy_sample_at_points(
const std::shared_ptr<FakePitchedSoundStream::sound_buffer_type>& sample, const std::shared_ptr<FakePitchedSoundStream::sound_buffer_type>& sample,
std::span<sf::Int16> output_buffer, std::span<sf::Int16> output_buffer,
std::set<std::int64_t>& starting_points, std::set<std::int64_t>& starting_points,
std::int64_t absolute_buffer_start std::int64_t buffer_start
) { ) {
std::ranges::fill(output_buffer, 0); std::ranges::fill(output_buffer, 0);
for (auto it = starting_points.begin(); it != starting_points.end();) { for (auto it = starting_points.begin(); it != starting_points.end();) {
const auto absolute_sample_start = *it; const auto next_sample_start = [&]() -> std::optional<std::int64_t> {
const auto absolute_buffer_end = absolute_buffer_start + static_cast<std::int64_t>(output_buffer.size()); const auto next = std::next(it);
const auto absolute_sample_end = absolute_sample_start + static_cast<std::int64_t>(sample->getSampleCount()); if (next == starting_points.end()) {
const auto absolute_sample_deoverlapped_end = std::min( return {};
absolute_sample_end, } else {
[&](const auto& it){ return *next;
const auto next = std::next(it); }
if (next != starting_points.end()) { }();
return *next; const auto slice = compute_sample_slice(
} else { buffer_start,
return INT64_MAX; static_cast<std::int64_t>(output_buffer.size()),
} *it,
}(it) static_cast<std::int64_t>(sample->getSampleCount()),
next_sample_start
); );
const auto absolute_sample_slice_start = std::max(
absolute_sample_start,
absolute_buffer_start
);
const auto absolute_sample_slice_end = std::min(
absolute_sample_deoverlapped_end,
absolute_buffer_end
);
const auto slice_size = absolute_sample_slice_end - absolute_sample_slice_start;
const auto slice_start_relative_to_sample_start = absolute_sample_slice_start - absolute_sample_start;
const auto slice_start_relative_to_buffer_start = absolute_sample_slice_start - absolute_buffer_start;
// Exit early in all the possible error case I could think of // bounds checking failed somehow
if ( if (not slice) {
absolute_sample_deoverlapped_end <= absolute_buffer_start
or absolute_sample_start >= absolute_buffer_end
or slice_size <= 0
) {
it = starting_points.erase(it); it = starting_points.erase(it);
continue; continue;
} }
const auto input_start = sample->getSamples() + slice_start_relative_to_sample_start; const auto input_start = sample->getSamples() + slice->start_in_sample;
const auto input_end = input_start + slice_size; const auto input_end = input_start + slice->size;
const auto output_start = output_buffer.begin() + slice_start_relative_to_buffer_start; const auto output_start = output_buffer.begin() + slice->start_in_buffer;
std::copy( std::copy(
input_start, input_start,
input_end, input_end,
output_start output_start
); );
// has this sample been fully played in this buffer ? // has this sample been fully played in this buffer ?
if (absolute_sample_deoverlapped_end <= absolute_buffer_end) { if (slice->ends_in_this_buffer) {
it = starting_points.erase(it); it = starting_points.erase(it);
} else { } else {
++it; ++it;

View File

@ -3,6 +3,7 @@
#include <cstdint> #include <cstdint>
#include <map> #include <map>
#include <memory> #include <memory>
#include <optional>
#include <set> #include <set>
#include <span> #include <span>
@ -10,6 +11,22 @@
#include <SFML/Config.hpp> #include <SFML/Config.hpp>
#include "fake_pitched_sound_stream.hpp" #include "fake_pitched_sound_stream.hpp"
#include "fmt/core.h"
struct Slice {
std::int64_t start_in_sample;
std::int64_t size;
std::int64_t start_in_buffer;
bool ends_in_this_buffer;
};
std::optional<Slice> compute_sample_slice(
const std::int64_t buffer_start,
const std::int64_t buffer_size,
const std::int64_t sample_start,
const std::int64_t sample_size,
const std::optional<std::int64_t> next_sample_start
);
void copy_sample_at_points( void copy_sample_at_points(
const std::shared_ptr<FakePitchedSoundStream::sound_buffer_type>& sample, const std::shared_ptr<FakePitchedSoundStream::sound_buffer_type>& sample,
@ -23,56 +40,42 @@ void copy_sample_at_points(
const std::shared_ptr<FakePitchedSoundStream::sound_buffer_type>& sample, const std::shared_ptr<FakePitchedSoundStream::sound_buffer_type>& sample,
std::span<sf::Int16> output_buffer, std::span<sf::Int16> output_buffer,
std::map<std::int64_t, T>& starting_points, std::map<std::int64_t, T>& starting_points,
std::int64_t absolute_buffer_start std::int64_t buffer_start
) { ) {
std::ranges::fill(output_buffer, 0); std::ranges::fill(output_buffer, 0);
for (auto it = starting_points.begin(); it != starting_points.end();) { for (auto it = starting_points.begin(); it != starting_points.end();) {
const auto absolute_sample_start = it->first; const auto next_sample_start = [&]() -> std::optional<std::int64_t> {
const auto absolute_buffer_end = absolute_buffer_start + static_cast<std::int64_t>(output_buffer.size()); const auto next = std::next(it);
const auto absolute_sample_end = absolute_sample_start + static_cast<std::int64_t>(sample->getSampleCount()); if (next == starting_points.end()) {
const auto absolute_sample_deoverlapped_end = std::min( return {};
absolute_sample_end, } else {
[&](const auto& it){ return next->first;
const auto next = std::next(it); }
if (next != starting_points.end()) { }();
return next->first; const auto slice = compute_sample_slice(
} else { buffer_start,
return INT64_MAX; static_cast<std::int64_t>(output_buffer.size()),
} it->first,
}(it) static_cast<std::int64_t>(sample->getSampleCount()),
next_sample_start
); );
const auto absolute_sample_slice_start = std::max(
absolute_sample_start,
absolute_buffer_start
);
const auto absolute_sample_slice_end = std::min(
absolute_sample_deoverlapped_end,
absolute_buffer_end
);
const auto slice_size = absolute_sample_slice_end - absolute_sample_slice_start;
const auto slice_start_relative_to_sample_start = absolute_sample_slice_start - absolute_sample_start;
const auto slice_start_relative_to_buffer_start = absolute_sample_slice_start - absolute_buffer_start;
// Exit early in all the possible error cases I could think of // bounds checking failed somehow
if ( if (not slice) {
absolute_sample_deoverlapped_end <= absolute_buffer_start
or absolute_sample_start >= absolute_buffer_end
or slice_size <= 0
) {
it = starting_points.erase(it); it = starting_points.erase(it);
continue; continue;
} }
const auto input_start = sample->getSamples() + slice_start_relative_to_sample_start; const auto input_start = sample->getSamples() + slice->start_in_sample;
const auto input_end = input_start + slice_size; const auto input_end = input_start + slice->size;
const auto output_start = output_buffer.begin() + slice_start_relative_to_buffer_start; const auto output_start = output_buffer.begin() + slice->start_in_buffer;
std::copy( std::copy(
input_start, input_start,
input_end, input_end,
output_start output_start
); );
// has this sample been fully played in this buffer ? // has this sample been fully played in this buffer ?
if (absolute_sample_deoverlapped_end <= absolute_buffer_end) { if (slice->ends_in_this_buffer) {
it = starting_points.erase(it); it = starting_points.erase(it);
} else { } else {
++it; ++it;