MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SamplingPipeline.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "BufferPipeline.hpp"
4
7
9
10namespace MayaFlux::Kakshya {
11class DynamicSoundStream;
12}
13
14namespace MayaFlux::Buffers {
15class AudioBuffer;
16class BufferManager;
17}
18
19namespace MayaFlux::Kriya {
20
21/**
22 * @class SamplingPipeline
23 * @brief Pipeline-coordinated polyphonic playback of a bounded audio stream.
24 *
25 * Owns a private AudioBuffer with a StreamSliceProcessor as its default
26 * processor. The buffer is supplied to an output channel via BufferManager.
27 * A BufferPipeline captures from the buffer at buffer rate with ON_CAPTURE
28 * processing, driving process_default() each cycle. The root buffer's
29 * ChannelProcessor mixes the result into output.
30 *
31 * Voices are activated and deactivated via play() and stop(), which
32 * delegate to StreamSliceProcessor::bind/unbind. The pipeline runs
33 * for the lifetime of the SamplingPipeline. Inactive voices contribute
34 * silence with no read overhead. One-shot voices self-deactivate via
35 * the processor's on_end callback.
36 *
37 * The pipeline and capture operation are exposed for further chaining:
38 * lifecycle callbacks, branching, data-ready hooks, and strategy
39 * selection are available through the standard BufferPipeline and
40 * CaptureBuilder fluent interfaces before calling build().
41 */
42class MAYAFLUX_API SamplingPipeline {
43public:
44 /**
45 * @brief Begin construction with a loaded stream and output channel.
46 * @param stream Loaded DynamicSoundStream.
47 * @param mgr BufferManager for channel supply.
48 * @param scheduler Scheduler for the internal BufferPipeline.
49 * @param channel Output channel index.
50 * @param buf_size Engine buffer size in frames.
51 *
52 * After construction, optionally call pipeline() and capture() to
53 * configure the fluent chain, then call build() to start processing.
54 * If build() is never called, the destructor is a no-op.
55 */
57 std::shared_ptr<Kakshya::DynamicSoundStream> stream,
59 Vruta::TaskScheduler& scheduler,
60 uint32_t channel,
61 uint32_t buf_size);
62
64
67
68 /**
69 * @brief Access the internal pipeline for fluent configuration.
70 *
71 * Allows lifecycle callbacks, branching, strategy selection, and
72 * additional operations before build().
73 *
74 * @code
75 * sampler.pipeline()
76 * .with_strategy(ExecutionStrategy::STREAMING)
77 * .with_lifecycle(on_start, on_end)
78 * .branch_if(every_16, snapshot_branch);
79 * @endcode
80 */
81 [[nodiscard]] BufferPipeline& pipeline();
82
83 /**
84 * @brief Access the capture operation builder for fluent configuration.
85 *
86 * Allows data-ready callbacks, windowed/circular modes, tagging,
87 * and metadata before build().
88 *
89 * @code
90 * sampler.capture()
91 * .on_data_ready([](auto& data, uint32_t cycle) { analyze(data); })
92 * .with_tag("lead_sampler");
93 * @endcode
94 */
95 [[nodiscard]] CaptureBuilder& capture();
96
97 /**
98 * @brief Load a StreamSlice into a voice slot for later playback.
99 *
100 * Must be called after build(). Replaces any existing slice in the slot.
101 * Use slice() to mutate parameters of an already-loaded slot in place.
102 *
103 * @param index Voice index.
104 * @param slice StreamSlice to load.
105 * @return Reference to the loaded StreamSlice for further configuration.
106 */
108 {
109 m_processor->load(index, std::move(slice));
110 return m_processor->slice(index);
111 }
112
113 /**
114 * @brief Finalize configuration and start processing.
115 *
116 * Supplies the buffer to the output channel, chains the capture
117 * operation into the pipeline, and starts execution at buffer rate.
118 * Must be called before play(). Calling build() more than once
119 * has no effect.
120 */
121 void build();
122
123 /**
124 * @brief Finalize configuration and start processing for a bounded duration.
125 *
126 * Converts milliseconds to pipeline cycles via sample rate and buffer size,
127 * then starts execution for exactly that many cycles. When the cycle count
128 * exhausts, the pipeline stops unconditionally regardless of voice state.
129 * Any active voice is cut immediately with no fade or drain.
130 *
131 * Must not be called if build() has already been called.
132 *
133 * @param milliseconds Duration in milliseconds.
134 */
135 void build_for(uint64_t milliseconds);
136
137 /**
138 * @brief Stop and restart pipeline execution for a bounded duration.
139 *
140 * Stops any running pipeline execution, resets the cycle counter, and
141 * restarts for the given duration. Hard-cuts all active voices at the
142 * point of restart. Document as a destructive operation.
143 *
144 * @param milliseconds Duration in milliseconds.
145 */
146 void rebuild_for(uint64_t milliseconds);
147
148 /**
149 * @brief Activate a voice, resetting its cursor to loop_start.
150 * @param index Voice index.
151 */
152 void play(size_t index = 0);
153
154 /**
155 * @brief Load a slice into a voice slot and activate it immediately.
156 *
157 * Equivalent to load(index, slice) followed by play(index).
158 * Requires build() to have been called first.
159 *
160 * @param index Voice index.
161 * @param slice StreamSlice to load and activate.
162 */
163 void play(size_t index, Kakshya::StreamSlice slice);
164
165 /**
166 * @brief Activate a voice with looping enabled.
167 * @param index Voice index.
168 */
169 void play_continuous(size_t index = 0);
170
171 /**
172 * @brief Load a slice into a voice slot and activate it with looping enabled.
173 *
174 * Sets looping on the slice before loading. Equivalent to setting
175 * slice.looping = true, calling load(index, slice), then play_continuous(index).
176 * Requires build() to have been called first.
177 *
178 * @param index Voice index.
179 * @param slice StreamSlice to load and activate with looping.
180 */
181 void play_continuous(size_t index, Kakshya::StreamSlice slice);
182
183 /**
184 * @brief Deactivate a voice.
185 * @param index Voice index.
186 */
187 void stop(size_t index = 0);
188
189 /**
190 * @brief Construct a slice spanning the full stream.
191 * @param index Slot identity.
192 */
193 [[nodiscard]] Kakshya::StreamSlice slice_from_stream(uint8_t index = 0) const
194 {
195 if (!m_stream) {
196 MF_ERROR(Journal::Component::Kriya, Journal::Context::Configuration,
197 "SamplingPipeline::slice_from_stream called with null stream");
198 return {};
199 }
200 return Kakshya::StreamSlice::from_stream(m_stream, index);
201 }
202
203 /**
204 * @brief Construct a slice spanning a frame sub-region.
205 * @param start_frame Inclusive start frame.
206 * @param end_frame Inclusive end frame.
207 * @param index Slot identity.
208 */
210 uint64_t start_frame, uint64_t end_frame, uint8_t index = 0) const
211 {
212
213 if (!m_stream) {
214 MF_ERROR(Journal::Component::Kriya, Journal::Context::Configuration,
215 "SamplingPipeline::slice_from_range called with null stream");
216 return {};
217 }
218 return Kakshya::StreamSlice::from_frame_range(m_stream, start_frame, end_frame, index);
219 }
220
221 /**
222 * @brief Direct access to a voice's StreamSlice for configuration.
223 *
224 * Configure stream, loop_start, loop_end, speed, scale before play().
225 *
226 * @code
227 * sampler.slice(0).speed = 0.5;
228 * sampler.slice(0).loop_start = 48000;
229 * sampler.slice(0).loop_end = 96000;
230 * sampler.play(0);
231 * @endcode
232 *
233 * @param index Voice index.
234 */
235 [[nodiscard]] Kakshya::StreamSlice& slice(size_t index);
236
237 /**
238 * @brief Get the internal AudioBuffer for direct manipulation.
239 *
240 * The buffer is supplied to the output channel and processed by the
241 * pipeline. External processing or inspection is possible but should
242 * be done with care to avoid conflicts with the pipeline's operations.
243 *
244 * @return Shared pointer to the internal AudioBuffer.
245 */
246 std::shared_ptr<Buffers::AudioBuffer> get_buffer() const { return m_buffer; }
247
248 /**
249 * @brief Get the underlying DynamicSoundStream.
250 *
251 * Exposes stream properties and allows construction of custom slices
252 * outside of the provided StreamSliceProcessor interface.
253 *
254 * @return Shared pointer to the DynamicSoundStream.
255 */
256 std::shared_ptr<Kakshya::DynamicSoundStream> get_stream() const { return m_stream; }
257
258private:
259 std::shared_ptr<Kakshya::DynamicSoundStream> m_stream;
260 std::shared_ptr<Buffers::AudioBuffer> m_buffer;
261 std::shared_ptr<Buffers::StreamSliceProcessor> m_processor;
264 uint32_t m_channel;
265 uint32_t m_buf_size;
266
267 std::shared_ptr<BufferPipeline> m_pipeline;
269 bool m_built { false };
270
271 [[nodiscard]] bool any_active() const;
272};
273
274} // namespace MayaFlux::Kriya
#define MF_ERROR(comp, ctx,...)
uint32_t channel
Token-based multimodal buffer management system for unified data stream processing.
Coroutine-based execution engine for composable, multi-strategy buffer processing.
Fluent builder interface for constructing BufferCapture configurations.
Definition Capture.hpp:231
std::shared_ptr< Buffers::AudioBuffer > m_buffer
std::shared_ptr< Kakshya::DynamicSoundStream > m_stream
Kakshya::StreamSlice slice_from_stream(uint8_t index=0) const
Construct a slice spanning the full stream.
SamplingPipeline & operator=(const SamplingPipeline &)=delete
std::shared_ptr< Buffers::StreamSliceProcessor > m_processor
Kakshya::StreamSlice slice_from_range(uint64_t start_frame, uint64_t end_frame, uint8_t index=0) const
Construct a slice spanning a frame sub-region.
std::shared_ptr< BufferPipeline > m_pipeline
SamplingPipeline(const SamplingPipeline &)=delete
std::shared_ptr< Kakshya::DynamicSoundStream > get_stream() const
Get the underlying DynamicSoundStream.
std::shared_ptr< Buffers::AudioBuffer > get_buffer() const
Get the internal AudioBuffer for direct manipulation.
Kakshya::StreamSlice & load(size_t index, Kakshya::StreamSlice slice)
Load a StreamSlice into a voice slot for later playback.
Pipeline-coordinated polyphonic playback of a bounded audio stream.
Token-based multimodal task scheduling system for unified coroutine processing.
Definition Scheduler.hpp:51
A bounded region of a DynamicSoundStream with associated playback parameters.