Add simulator audio support

This commit is contained in:
Adolfo Reyna
2026-09-23 19:13:39 -04:00
parent 982bba70b2
commit dcfd4e9bcc
15 changed files with 905 additions and 11 deletions
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <algorithm>
#include <array>
#include <atomic>
#include <cstdint>
#include <cstring>
// Single producer / single consumer. The SDL callback is a native thread: it must never
// allocate, block, log, or call FreeRTOS. Unsigned counters also work across wraparound.
class SdlAudioBuffer {
static constexpr uint32_t CAPACITY = 16384; // samples; ~171 ms of 48 kHz stereo
std::array<int16_t, CAPACITY> samples {};
std::atomic<uint32_t> read_position { 0 };
std::atomic<uint32_t> write_position { 0 };
public:
size_t write(const void* source, size_t count) {
const uint32_t write = write_position.load(std::memory_order_relaxed);
const uint32_t read = read_position.load(std::memory_order_acquire);
count = std::min(count, static_cast<size_t>(CAPACITY - (write - read)));
const size_t first = std::min(count, static_cast<size_t>(CAPACITY - write % CAPACITY));
const auto* bytes = static_cast<const uint8_t*>(source);
std::memcpy(samples.data() + write % CAPACITY, bytes, first * sizeof(int16_t));
std::memcpy(samples.data(), bytes + first * sizeof(int16_t), (count - first) * sizeof(int16_t));
write_position.store(write + count, std::memory_order_release);
return count;
}
size_t read(void* destination, size_t count) {
const uint32_t read = read_position.load(std::memory_order_relaxed);
const uint32_t write = write_position.load(std::memory_order_acquire);
count = std::min(count, static_cast<size_t>(write - read));
const size_t first = std::min(count, static_cast<size_t>(CAPACITY - read % CAPACITY));
auto* bytes = static_cast<uint8_t*>(destination);
std::memcpy(bytes, samples.data() + read % CAPACITY, first * sizeof(int16_t));
std::memcpy(bytes + first * sizeof(int16_t), samples.data(), (count - first) * sizeof(int16_t));
read_position.store(read + count, std::memory_order_release);
return count;
}
bool empty() const {
return read_position.load(std::memory_order_acquire) == write_position.load(std::memory_order_acquire);
}
// Only while the SDL device is closed and no caller is doing I/O.
void reset() {
read_position.store(0);
write_position.store(0);
}
};