Tabula Sonora 0.1.0
A native C++20 implementation of the Roland Sound Canvas VA synth voice
Loading...
Searching...
No Matches
frame_ring.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <atomic>
4#include <cstddef>
5#include <cstdint>
6#include <span>
7#include <utility>
8#include <vector>
9
10namespace ts {
11
28class FrameRing {
29public:
31 explicit FrameRing(std::size_t frames);
32
34 [[nodiscard]] std::size_t capacity() const noexcept { return capacity_; }
35
37 [[nodiscard]] std::size_t queued() const noexcept
38 {
39 return static_cast<std::size_t>(write_.load(std::memory_order_relaxed)
40 - read_.load(std::memory_order_acquire));
41 }
42
44 [[nodiscard]] std::size_t writable() const noexcept { return capacity_ - queued(); }
45
47 void write(std::span<const float> interleaved) noexcept;
48
55 void request_flush() noexcept { flush_.fetch_add(1, std::memory_order_release); }
56
58 [[nodiscard]] bool flush_pending() const noexcept
59 {
60 return flush_.load(std::memory_order_relaxed) != ack_.load(std::memory_order_acquire);
61 }
62
64 void set_starvation_expected(bool expected) noexcept
65 {
66 expect_starvation_.store(expected, std::memory_order_relaxed);
67 }
68
72 std::size_t read(std::span<float> interleaved) noexcept;
73
78 [[nodiscard]] std::int64_t underruns() const noexcept
79 {
80 return underruns_.load(std::memory_order_relaxed);
81 }
82
84 [[nodiscard]] std::pair<float, float> peak() const noexcept
85 {
86 return {peak_left_.load(std::memory_order_relaxed),
87 peak_right_.load(std::memory_order_relaxed)};
88 }
89
90private:
91 std::vector<float> samples_;
92 std::size_t capacity_;
93 std::size_t mask_;
94
95 alignas(64) std::atomic<std::uint64_t> write_{0};
96 alignas(64) std::atomic<std::uint64_t> read_{0};
97
98 std::atomic<std::uint32_t> flush_{0};
99 std::atomic<std::uint32_t> ack_{0};
100 std::atomic<bool> expect_starvation_{false};
101
102 std::atomic<std::int64_t> underruns_{0};
103 std::atomic<float> peak_left_{0.0F};
104 std::atomic<float> peak_right_{0.0F};
105};
106
107} // namespace ts
std::pair< float, float > peak() const noexcept
Peak absolute level of the last block the consumer handed to the device.
Definition frame_ring.hpp:84
std::size_t queued() const noexcept
Frames currently queued, as the producer sees it.
Definition frame_ring.hpp:37
void request_flush() noexcept
Asks the consumer to drop everything queued.
Definition frame_ring.hpp:55
FrameRing(std::size_t frames)
Creates a ring holding at least this many frames, rounded up to a power of two.
std::size_t capacity() const noexcept
Frames the ring can hold.
Definition frame_ring.hpp:34
bool flush_pending() const noexcept
Whether a requested flush has yet to be performed by the consumer.
Definition frame_ring.hpp:58
void write(std::span< const float > interleaved) noexcept
Writes interleaved stereo frames. The caller must not exceed writable.
std::size_t read(std::span< float > interleaved) noexcept
Fills interleaved stereo frames, zero-padding whatever the ring could not supply.
std::int64_t underruns() const noexcept
How many times the consumer has come up short.
Definition frame_ring.hpp:78
std::size_t writable() const noexcept
Frames the producer can write right now.
Definition frame_ring.hpp:44
void set_starvation_expected(bool expected) noexcept
Whether the consumer should treat an empty ring as intended rather than as an underrun.
Definition frame_ring.hpp:64
Definition control_decode.hpp:7