Add simulator audio support
This commit is contained in:
@@ -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);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user