60 void write(
int channel_count,
int frames, F&& channel)
noexcept
64 channel_count = std::clamp(channel_count, 0, max_channels);
65 m_channels.store(channel_count, std::memory_order_relaxed);
67 const uint64_t w = m_written.load(std::memory_order_relaxed);
68 const auto now = clock::now();
69 const double rate = m_rate.load(std::memory_order_relaxed);
70 const auto block = std::chrono::duration<double>(frames / std::max(rate, 1.));
71 if(w > 0 && now - m_last_write > std::max(4 * block, std::chrono::duration<double>(0.05)))
72 m_from.store(w, std::memory_order_relaxed);
76 m_writing.store(w + frames, std::memory_order_relaxed);
77 std::atomic_thread_fence(std::memory_order_release);
79 for(
int c = 0; c < channel_count; c++)
81 float* buf = m_buffers[c].load(std::memory_order_acquire);
86 if(m_since[c].load(std::memory_order_relaxed) == unwritten)
87 m_since[c].store(w, std::memory_order_relaxed);
88 const auto* src = channel(c);
89 for(
int i = 0; i < frames; i++)
90 std::atomic_ref<float>{buf[(w + i) & m_mask]}.store(
91 float(src[i]), std::memory_order_relaxed);
93 for(
int c = channel_count; c < m_written_channels; c++)
94 m_since[c].store(unwritten, std::memory_order_relaxed);
95 m_written_channels = channel_count;
97 m_written.store(w + frames, std::memory_order_release);
111 const int n = m_channels.load(std::memory_order_relaxed);
112 for(
int c = 0; c < n; c++)
114 if(!m_buffers[c].load(std::memory_order_relaxed))
116 m_since[c].store(unwritten, std::memory_order_relaxed);
117 m_buffers[c].store(
new float[m_capacity]{}, std::memory_order_release);
131 bool read(
int c, uint64_t start, std::span<float> dst)
const noexcept
133 if(c < 0 || c >= max_channels || dst.size() > m_capacity / 2)
135 float* buf = m_buffers[c].load(std::memory_order_acquire);
139 const uint64_t end = start + dst.size();
140 if(end > m_written.load(std::memory_order_acquire))
142 if(start < m_from.load(std::memory_order_relaxed)
143 || start < m_since[c].load(std::memory_order_relaxed))
145 if(!untouched(start))
148 for(std::size_t i = 0; i < dst.size(); i++)
149 dst[i] = std::atomic_ref<float>{buf[(start + i) & m_mask]}.load(
150 std::memory_order_relaxed);
154 std::atomic_thread_fence(std::memory_order_acquire);
155 return untouched(start);