Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
audio_stream_handoff.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <atomic>
4#include <cstdint>
5#include <memory>
6#include <vector>
7
12
13namespace pulp::audio {
14
16 std::uint32_t source_channels = 0;
17 std::uint32_t host_channels = 0;
18 double source_sample_rate = 0.0;
19 double host_sample_rate = 0.0;
20 std::uint64_t ring_capacity_frames = 0;
21 std::uint32_t max_source_block_frames = 0;
22 std::uint32_t max_host_block_frames = 0;
23};
24
26 std::uint64_t requested_frames = 0;
27 std::uint64_t rendered_frames = 0;
28 // Host/output frames that were backed by source audio. In resampled
29 // pulls this remains in host frames; source_frames_consumed reports the
30 // source-domain accounting separately.
31 std::uint64_t source_backed_frames = 0;
32 std::uint64_t source_frames_consumed = 0;
33 bool underrun = false;
34};
35
37 std::uint64_t source_frames_pushed = 0;
38 std::uint64_t source_frames_consumed = 0;
39 std::uint64_t output_frames_pulled = 0;
40 std::uint64_t underrun_frames = 0;
41 std::uint64_t overrun_frames = 0;
42 std::uint64_t dropped_source_frames = 0;
43 std::uint64_t queued_source_frames = 0;
48};
49
51public:
52 AudioStreamHandoff() = default;
53
54 // Offline/quiescent only. Allocates ring, pending buffers, and resampler
55 // state. `host_channels` records the intended host output shape; the
56 // destination BufferView controls final channel adaptation in pull().
57 bool prepare(const AudioStreamHandoffConfig& config);
58 void reset() noexcept;
59
60 bool prepared() const noexcept { return prepared_; }
61 bool resampling() const noexcept { return prepared_ && !same_rate_; }
62 std::uint32_t source_channels() const noexcept { return source_channels_; }
63 std::uint32_t host_channels() const noexcept { return host_channels_; }
64 double source_sample_rate() const noexcept { return source_sample_rate_; }
65 double host_sample_rate() const noexcept { return host_sample_rate_; }
66
67 // RT-safe after prepare for one source producer and one host consumer.
68 // Pull preserves resampler fractional state and zero-fills underruns.
69 std::uint64_t push(BufferView<const float> source, std::uint64_t frames) noexcept;
70 std::uint64_t push(BufferView<float> source, std::uint64_t frames) noexcept;
71
73 std::uint64_t frames) noexcept;
74
76
77private:
78 void clear_unprepared() noexcept;
79 bool valid_config(const AudioStreamHandoffConfig& config) const noexcept;
80 void allocate_scratch(std::uint64_t pending_capacity_frames);
81 void refill_pending_from_ring() noexcept;
82 void consume_pending(std::uint64_t frames) noexcept;
83 struct ResampledChunkResult {
84 std::uint64_t output_frames = 0;
85 std::uint64_t source_frames_consumed = 0;
86 };
87 ResampledChunkResult pull_resampled_chunk(BufferView<float> destination,
88 std::uint64_t frames) noexcept;
89 void copy_resampled_to_destination(BufferView<float> destination,
90 std::uint64_t destination_offset,
91 std::uint64_t frames) noexcept;
92 void zero_fill(BufferView<float> destination,
93 std::uint64_t offset,
94 std::uint64_t frames) noexcept;
95
96 template<typename SampleType>
97 std::uint64_t push_impl(BufferView<SampleType> source, std::uint64_t frames) noexcept;
98
100 signal::Resampler resampler_;
101
102 std::vector<std::vector<float>> pending_source_;
103 std::vector<std::vector<float>> resampled_output_;
104 std::vector<float*> pending_write_ptrs_;
105 std::vector<const float*> pending_read_ptrs_;
106 std::vector<float*> resampled_output_ptrs_;
107 std::unique_ptr<runtime::SpscRingIndex> pending_fifo_;
108
109 std::uint32_t source_channels_ = 0;
110 std::uint32_t host_channels_ = 0;
111 double source_sample_rate_ = 0.0;
112 double host_sample_rate_ = 0.0;
113 std::uint64_t pending_capacity_frames_ = 0;
114 std::uint32_t max_host_block_frames_ = 0;
115 bool prepared_ = false;
116 bool same_rate_ = true;
117
118 std::atomic<std::uint64_t> source_frames_pushed_{0};
119 std::atomic<std::uint64_t> source_frames_consumed_{0};
120 std::atomic<std::uint64_t> output_frames_pulled_{0};
121 std::atomic<std::uint64_t> underrun_frames_{0};
122 std::atomic<std::uint64_t> overrun_frames_{0};
123 std::atomic<std::uint64_t> dropped_source_frames_{0};
124 std::atomic<std::uint64_t> pending_source_frames_snapshot_{0};
125};
126
127template<typename SampleType>
128std::uint64_t AudioStreamHandoff::push_impl(BufferView<SampleType> source,
129 std::uint64_t frames) noexcept {
130 if (!prepared_ || frames == 0 || source.num_channels() == 0 ||
131 source.num_samples() == 0) {
132 return 0;
133 }
134
135 const auto requested =
136 std::min(frames, static_cast<std::uint64_t>(source.num_samples()));
137 const auto written = ring_.write(source, requested);
138 source_frames_pushed_.fetch_add(written, std::memory_order_relaxed);
139 if (written < requested) {
140 const auto dropped = requested - written;
141 overrun_frames_.fetch_add(dropped, std::memory_order_relaxed);
142 dropped_source_frames_.fetch_add(dropped, std::memory_order_relaxed);
143 }
144 return written;
145}
146
147} // namespace pulp::audio
std::uint32_t host_channels() const noexcept
Definition audio_stream_handoff.hpp:63
double host_sample_rate() const noexcept
Definition audio_stream_handoff.hpp:65
std::uint64_t push(BufferView< float > source, std::uint64_t frames) noexcept
double source_sample_rate() const noexcept
Definition audio_stream_handoff.hpp:64
bool prepared() const noexcept
Definition audio_stream_handoff.hpp:60
AudioStreamHandoffStats stats() const noexcept
std::uint64_t push(BufferView< const float > source, std::uint64_t frames) noexcept
std::uint32_t source_channels() const noexcept
Definition audio_stream_handoff.hpp:62
bool prepare(const AudioStreamHandoffConfig &config)
bool resampling() const noexcept
Definition audio_stream_handoff.hpp:61
AudioStreamHandoffPullResult pull(BufferView< float > destination, std::uint64_t frames) noexcept
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
Definition planar_audio_ring_buffer.hpp:22
Definition analyzer_provider.hpp:12
ResamplerT< float > Resampler
Definition resampler.hpp:382
STL namespace.
Polyphase-FIR resampler with a Kaiser-window low-pass prototype.
Definition audio_stream_handoff.hpp:15
std::uint32_t source_channels
Definition audio_stream_handoff.hpp:16
double host_sample_rate
Definition audio_stream_handoff.hpp:19
std::uint32_t max_source_block_frames
Definition audio_stream_handoff.hpp:21
std::uint64_t ring_capacity_frames
Definition audio_stream_handoff.hpp:20
std::uint32_t host_channels
Definition audio_stream_handoff.hpp:17
std::uint32_t max_host_block_frames
Definition audio_stream_handoff.hpp:22
double source_sample_rate
Definition audio_stream_handoff.hpp:18
Definition audio_stream_handoff.hpp:25
std::uint64_t source_frames_consumed
Definition audio_stream_handoff.hpp:32
std::uint64_t requested_frames
Definition audio_stream_handoff.hpp:26
bool underrun
Definition audio_stream_handoff.hpp:33
std::uint64_t source_backed_frames
Definition audio_stream_handoff.hpp:31
std::uint64_t rendered_frames
Definition audio_stream_handoff.hpp:27
Definition audio_stream_handoff.hpp:36
double queued_source_seconds
Definition audio_stream_handoff.hpp:44
double estimated_host_latency_frames
Definition audio_stream_handoff.hpp:46
double estimated_latency_seconds
Definition audio_stream_handoff.hpp:47
std::uint64_t queued_source_frames
Definition audio_stream_handoff.hpp:43
std::uint64_t overrun_frames
Definition audio_stream_handoff.hpp:41
std::uint64_t output_frames_pulled
Definition audio_stream_handoff.hpp:39
std::uint64_t source_frames_consumed
Definition audio_stream_handoff.hpp:38
std::uint64_t underrun_frames
Definition audio_stream_handoff.hpp:40
std::uint64_t source_frames_pushed
Definition audio_stream_handoff.hpp:37
std::uint64_t dropped_source_frames
Definition audio_stream_handoff.hpp:42
double estimated_source_latency_frames
Definition audio_stream_handoff.hpp:45