MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GranularWorkflow.hpp
Go to the documentation of this file.
1#pragma once
2
5
10
12
13namespace MayaFlux::Kakshya {
14class SoundFileContainer;
15class DynamicSoundStream;
16}
17
19
20/**
21 * @brief Datum specialisation for granular processing pipelines.
22 */
24
25/**
26 * @brief Datum specialisation for container-output granular pipelines.
27 */
29
30/**
31 * @enum GranularOutput
32 * @brief Selects the terminal output type produced by make_granular_matrix.
33 *
34 * REGION_GROUP — pipeline terminates with a sorted RegionGroup (default).
35 * Use when you need to inspect, analyse, or further transform
36 * the grain pool before committing to audio.
37 *
38 * CONTAINER — appends a reconstruct rule that stitches sorted grains into
39 * a SoundFileContainer. Use for the offline playback workflow
40 * where container-in container-out is all that is needed.
41 *
42 * CONTAINER_ADDITIVE — overlap-add reconstruct: grains accumulated at hop_size
43 * intervals with optional per-grain tapering.
44
45 * STREAM — appends a reconstruct rule that stitches sorted grains into
46 * a DynamicSoundStream. Use for sampling pipelines, StreamSlicing
47 * and similar real-time workflows
48 *
49 * STREAM_ADDITIVE — overlap-add reconstruct into a DynamicSoundStream.
50 * grains accumulated at hop_size intervals with optional per-grain tapering.
51 */
52enum class GranularOutput : uint8_t {
56 STREAM,
58
59};
60
61/**
62 * @brief Matrix type used throughout the granular subsystem.
63 */
65
66/**
67 * @brief Span-level escape hatch for fully custom per-grain feature computation.
68 *
69 * Receives the raw grain samples and the current ExecutionContext.
70 * Returns a single double that is written as a named Region attribute.
71 * For common attribution tasks prefer the AnalysisType + qualifier path
72 * via make_granular_context.
73 */
74using AttributeExecutor = std::function<double(std::span<const double>, const ExecutionContext&)>;
75
76/**
77 * @brief Per-grain taper applied before accumulation in OLA reconstruction.
78 *
79 * Receives a mutable span covering exactly one grain's samples for one channel.
80 * Applied in-place before the grain is added to the output buffer.
81 * Pass {} or nullptr to skip tapering entirely.
82 *
83 * Common use:
84 * [](std::span<double> g){ Kinesis::Discrete::apply_hann(g); }
85 * [](std::span<double> g){ Kinesis::Discrete::apply_trapezoid(g, g.size() / 8); }
86 */
88
89/// @brief Grammar rule executor for the reconstruction step.
91
92/// @brief Grammar rule executor for additive grain reconstruction.
94
95/// @brief Grammar rule executor — concatenative reconstruct into DynamicSoundStream.
97
98/// @brief Grammar rule executor — OLA reconstruct into DynamicSoundStream.
100
101// ============================================================================
102// Concrete operations
103// ============================================================================
104
105/**
106 * @class SegmentOp
107 * @brief Segments container audio into fixed hop-size grain windows.
108 *
109 * Reads parameters from set_parameter or ExecutionContext:
110 * - grain_size uint32_t samples per grain (default 1024)
111 * - hop_size uint32_t hop between grains (default 512)
112 * - channel uint32_t source channel index (default 0)
113 */
114class MAYAFLUX_API SegmentOp final
115 : public FeatureExtractor<Kakshya::RegionGroup, Kakshya::RegionGroup> {
116public:
118 : FeatureExtractor<Kakshya::RegionGroup, Kakshya::RegionGroup>(
120 {
121 }
122
123 [[nodiscard]] ExtractionType get_extraction_type() const override
124 {
125 return ExtractionType::FEATURE_GUIDED;
126 }
127
128protected:
129 [[nodiscard]] std::string get_extractor_name() const override
130 {
131 return "Granular::SegmentOp";
132 }
133
134 Datum<Kakshya::RegionGroup> extract_implementation(
135 const Datum<Kakshya::RegionGroup>& input) override;
136};
137
138/**
139 * @class AttributeOp
140 * @brief Computes a scalar attribute per grain and writes it onto each Region.
141 *
142 * Attribution is resolved in the following priority order:
143 *
144 * 1. Span lambda : set via set_parameter("attribute_executor", AttributeExecutor)
145 * or present in ExecutionContext. For fully custom math.
146 *
147 * 2. Direct analyzer : set via set_parameter("analyzer", shared_ptr<UniversalAnalyzer<...>>)
148 * paired with set_parameter("analyzer_qualifier", std::string).
149 * Any existing concrete analyzer can be supplied pre-configured.
150 *
151 * 3. Analysis type : set via set_parameter("analysis_type", AnalysisType) with
152 * optional set_parameter("analyzer_qualifier", std::string). AttributeOp
153 * constructs a default-configured analyzer internally.
154 *
155 * Parameters common to all paths:
156 * - feature_key std::string attribute name written on each grain (default "feature")
157 * - channel uint32_t source channel index (default 0)
158 *
159 * Qualifier strings map directly to scalar fields of the analysis result struct.
160 * The alias "rms" is accepted for FEATURE and resolves to "mean_energy".
161 * The alias "mean" is accepted for STATISTICAL and resolves to "mean_stat".
162 *
163 * FEATURE qualifiers (EnergyAnalysis):
164 * - "mean_energy" (default, alias: "rms")
165 * - "max_energy"
166 * - "min_energy"
167 * - "variance"
168 * - "dynamic_range"
169 * - "event_count"
170 * - "window_count"
171 *
172 * STATISTICAL qualifiers (StatisticalAnalysis):
173 * - "mean_stat" (default, alias: "mean")
174 * - "max_stat"
175 * - "min_stat"
176 * - "variance"
177 * - "std_dev"
178 * - "skewness"
179 * - "kurtosis"
180 * - "median"
181 * - "window_count"
182 */
183class MAYAFLUX_API AttributeOp final
184 : public RegionGroupAnalyzer<Kakshya::RegionGroup> {
185public:
186 [[nodiscard]] AnalysisType get_analysis_type() const override
187 {
188 return AnalysisType::FEATURE;
189 }
190
191protected:
192 [[nodiscard]] std::string get_analyzer_name() const override
193 {
194 return "Granular::AttributeOp";
195 }
196
197 Datum<Kakshya::RegionGroup> analyze_implementation(
198 const Datum<Kakshya::RegionGroup>& input) override;
199
200private:
201 /**
202 * @brief Resolve and execute attribution for a single grain.
203 * @param grain Source region defining the grain boundaries.
204 * @param container Signal data source.
205 * @param channel Channel index to extract samples from.
206 * @param ctx Current execution context carrying parameters.
207 * @return Scalar attribute value for this grain.
208 */
209 double compute_grain_attribute(
210 const Kakshya::Region& grain,
211 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
212 uint32_t channel,
213 const ExecutionContext& ctx) const;
214
215 /**
216 * @brief Construct a default-configured analyzer for the given AnalysisType.
217 * @param type Analysis category.
218 * @return Heap-allocated analyzer with sensible defaults.
219 */
220 static std::shared_ptr<RegionGroupAnalyzer<Kakshya::RegionGroup>>
221 make_default_analyzer(AnalysisType type);
222
223 /**
224 * @brief Extract a named scalar from a typed analysis result.
225 * @param analysis_result std::any holding the concrete analysis struct.
226 * @param type Analysis category used to select the correct cast path.
227 * @param qualifier Names the specific scalar to extract.
228 * @return Extracted double value.
229 */
230 static double extract_scalar(const std::any& analysis_result,
231 AnalysisType type,
232 const std::string& qualifier);
233
236};
237
238/**
239 * @class SortOp
240 * @brief Sorts grains by a named attribute key, with optional GPU dispatch.
241 *
242 * Parameters (via set_parameter or ExecutionContext):
243 * - feature_key std::string attribute to sort on
244 * - ascending bool sort direction (default true)
245 * - gpu_sort_threshold uint32_t grain count threshold for GPU path (default 0 = CPU only)
246 */
247class MAYAFLUX_API SortOp final
248 : public StandardSorter<Kakshya::RegionGroup, Kakshya::RegionGroup> {
249public:
250 [[nodiscard]] SortingType get_sorting_type() const override
251 {
252 return SortingType::ALGORITHMIC;
253 }
254
255protected:
256 [[nodiscard]] std::string get_sorter_name() const override
257 {
258 return "Granular::SortOp";
259 }
260
261 Datum<Kakshya::RegionGroup> sort_implementation(
262 const Datum<Kakshya::RegionGroup>& input) override;
263};
264
265// ============================================================================
266// Grammar rule executors
267// ============================================================================
268
269/// @brief Grammar rule executor for the segmentation step.
271
272/// @brief Grammar rule executor for the attribution step.
274
275/// @brief Grammar rule executor for the sort step.
277
278// ============================================================================
279// Context construction
280// ============================================================================
281
282/**
283 * @struct GranularConfig
284 * @brief Scalar parameters shared across all granular pipeline entry points.
285 *
286 * Replaces the repeated positional argument lists on process, process_to_container,
287 * and their async variants. Attribution type and output mode are kept as explicit
288 * parameters since they affect overload resolution and return type respectively.
289 */
291 uint32_t grain_size = 1024;
292 uint32_t hop_size = 512;
293 std::string feature_key = "feature";
294 uint32_t channel = 0;
295 bool ascending = true;
296 uint32_t gpu_sort_threshold = 0;
299};
300
301/**
302 * @brief Construct an ExecutionContext for the granular pipeline using a built-in AnalysisType.
303 *
304 * @param config Pipeline scalar parameters.
305 * @param analysis_type Attribution category. Supported: FEATURE, STATISTICAL.
306 * @param qualifier Scalar to extract. Empty uses type default.
307 * @return Populated ExecutionContext.
308 */
310 const GranularConfig& config,
311 AnalysisType analysis_type,
312 const std::string& qualifier = {})
313{
315 ctx.execution_metadata["grain_size"] = config.grain_size;
316 ctx.execution_metadata["hop_size"] = config.hop_size;
317 ctx.execution_metadata["channel"] = config.channel;
318 ctx.execution_metadata["feature_key"] = config.feature_key;
319 ctx.execution_metadata["ascending"] = config.ascending;
320 ctx.execution_metadata["gpu_sort_threshold"] = config.gpu_sort_threshold;
321 ctx.execution_metadata["analysis_type"] = analysis_type;
322 ctx.execution_metadata["analyzer_qualifier"] = qualifier;
323 return ctx;
324}
325
326/**
327 * @brief Construct an ExecutionContext supplying a pre-configured analyzer instance directly.
328 *
329 * @tparam InputType Analyzer input data type.
330 * @tparam OutputType Analyzer output data type.
331 * @param config Pipeline scalar parameters.
332 * @param analyzer Pre-configured analyzer instance.
333 * @param qualifier Scalar to extract. Empty uses type default.
334 * @return Populated ExecutionContext.
335 */
336template <ComputeData InputType, ComputeData OutputType>
338 const GranularConfig& config,
339 std::shared_ptr<UniversalAnalyzer<InputType, OutputType>> analyzer,
340 const std::string& qualifier = {})
341{
343 ctx.execution_metadata["grain_size"] = config.grain_size;
344 ctx.execution_metadata["hop_size"] = config.hop_size;
345 ctx.execution_metadata["channel"] = config.channel;
346 ctx.execution_metadata["feature_key"] = config.feature_key;
347 ctx.execution_metadata["ascending"] = config.ascending;
348 ctx.execution_metadata["gpu_sort_threshold"] = config.gpu_sort_threshold;
349 ctx.execution_metadata["analyzer"] = std::static_pointer_cast<void>(analyzer);
350 ctx.execution_metadata["analyzer_qualifier"] = qualifier;
351 return ctx;
352}
353
354/**
355 * @brief Construct an ExecutionContext using a span-level lambda for fully custom attribution.
356 *
357 * @param config Pipeline scalar parameters.
358 * @param executor Lambda receiving grain samples and context, returning a scalar.
359 * @return Populated ExecutionContext.
360 */
362 const GranularConfig& config,
363 AttributeExecutor executor)
364{
366 ctx.execution_metadata["grain_size"] = config.grain_size;
367 ctx.execution_metadata["hop_size"] = config.hop_size;
368 ctx.execution_metadata["channel"] = config.channel;
369 ctx.execution_metadata["feature_key"] = config.feature_key;
370 ctx.execution_metadata["ascending"] = config.ascending;
371 ctx.execution_metadata["gpu_sort_threshold"] = config.gpu_sort_threshold;
372 ctx.execution_metadata["attribute_executor"] = std::move(executor);
373 return ctx;
374}
375
376// ============================================================================
377// Input construction
378// ============================================================================
379
380/**
381 * @brief Construct the initial GranularDatum from a container.
382 * @param container Source signal data.
383 * @param group_name Name assigned to the RegionGroup. Defaults to "grains".
384 * @return GranularDatum ready for pipeline input.
385 */
387 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
388 const std::string& group_name = "grains")
389{
390 return GranularDatum { Kakshya::RegionGroup { group_name }, container };
391}
392
393// ============================================================================
394// Matrix factory
395// ============================================================================
396
397/**
398 * @brief Construct a GranularMatrix with grammar rules appropriate for the
399 * requested output type.
400 *
401 * REGION_GROUP: registers segment, attribute, sort (existing behaviour).
402 * CONTAINER: registers segment, attribute, sort, then appends reconstruct.
403 * The reconstruct rule reads the source container from
404 * ExecutionContext::execution_metadata["container"] and writes
405 * stitched per-channel audio into a SoundFileContainer.
406 * CONTAINER_ADDITIVE: same as CONTAINER but uses an overlap-add reconstruct rule
407 *
408 * @param attribution_context ComputationContext assigned to the attribution rule.
409 * @param output Terminal output type for this pipeline.
410 * @param taper Optional per-grain taper for OLA output.
411 * @return Configured GranularMatrix instance.
412 */
413[[nodiscard]] MAYAFLUX_API std::shared_ptr<GranularMatrix> make_granular_matrix(
416
417// ============================================================================
418// Free process function
419// ============================================================================
420
421/**
422 * @brief Run segment -> attribute -> sort and return the attributed RegionGroup.
423 *
424 * @param container Source signal data.
425 * @param analysis_type Attribution category.
426 * @param config Pipeline scalar parameters.
427 * @param qualifier Scalar to extract. Empty uses type default.
428 * @return GranularDatum containing the attributed, sorted RegionGroup.
429 */
430[[nodiscard]] MAYAFLUX_API GranularDatum process(
431 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
432 AnalysisType analysis_type,
433 const GranularConfig& config = {},
434 const std::string& qualifier = {});
435
436/**
437 * @brief Run segment -> attribute -> sort using a span-level attribution lambda.
438 *
439 * @param container Source signal data.
440 * @param executor Lambda receiving grain samples and context, returning a scalar.
441 * @param config Pipeline scalar parameters.
442 * @return GranularDatum containing the attributed, sorted RegionGroup.
443 */
444[[nodiscard]] MAYAFLUX_API GranularDatum process(
445 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
446 AttributeExecutor executor,
447 const GranularConfig& config = {});
448
449/**
450 * @brief Offline granular pipeline terminating in a SoundFileContainer.
451 *
452 * @param container Source signal data.
453 * @param analysis_type Attribution category.
454 * @param config Pipeline scalar parameters.
455 * @param qualifier Scalar to extract. Empty uses type default.
456 * @param output CONTAINER for concatenative, CONTAINER_ADDITIVE for OLA.
457 * @return Populated SoundFileContainer.
458 */
459[[nodiscard]] MAYAFLUX_API std::shared_ptr<Kakshya::SoundFileContainer> process_to_container(
460 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
461 AnalysisType analysis_type,
462 const GranularConfig& config = {},
463 const std::string& qualifier = {},
465
466/**
467 * @brief Offline granular pipeline using a span-level attribution lambda.
468 *
469 * @param container Source signal data.
470 * @param executor Lambda receiving grain samples and context, returning a scalar.
471 * @param config Pipeline scalar parameters.
472 * @param output CONTAINER for concatenative, CONTAINER_ADDITIVE for OLA.
473 * @return Populated SoundFileContainer.
474 */
475[[nodiscard]] MAYAFLUX_API std::shared_ptr<Kakshya::SoundFileContainer> process_to_container(
476 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
477 AttributeExecutor executor,
478 const GranularConfig& config = {},
480
481/**
482 * @brief Offline granular pipeline terminating in a DynamicSoundStream.
483 *
484 * Reconstructed grains are written channel-by-channel via
485 * DynamicSoundStream::write_frames. The result is ready for direct use
486 * as a SamplingPipeline source.
487 *
488 * @param container Source signal data.
489 * @param analysis_type Attribution category.
490 * @param config Pipeline scalar parameters.
491 * @param qualifier Scalar to extract. Empty uses type default.
492 * @param output STREAM for concatenative, STREAM_ADDITIVE for OLA.
493 * @return Populated DynamicSoundStream.
494 */
495[[nodiscard]] MAYAFLUX_API std::shared_ptr<Kakshya::DynamicSoundStream> process_to_stream(
496 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
497 AnalysisType analysis_type,
498 const GranularConfig& config = {},
499 const std::string& qualifier = {},
501
502/**
503 * @brief Offline granular pipeline using a span-level attribution lambda,
504 * terminating in a DynamicSoundStream.
505 *
506 * @param container Source signal data.
507 * @param executor Lambda receiving grain samples and context, returning a scalar.
508 * @param config Pipeline scalar parameters.
509 * @param output STREAM for concatenative, STREAM_ADDITIVE for OLA.
510 * @return Populated DynamicSoundStream.
511 */
512[[nodiscard]] MAYAFLUX_API std::shared_ptr<Kakshya::DynamicSoundStream> process_to_stream(
513 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
514 AttributeExecutor executor,
515 const GranularConfig& config = {},
517
518/**
519 * @brief Async offline granular pipeline (AnalysisType path).
520 *
521 * Runs the full pipeline on a background thread owned by @p matrix and
522 * invokes @p on_complete with the result. Returns immediately.
523 *
524 * @param matrix ComputeMatrix that owns the async future.
525 * @param container Source signal data.
526 * @param analysis_type Attribution category.
527 * @param on_complete Called on the worker thread with the finished container.
528 * @param config Pipeline scalar parameters.
529 * @param qualifier Scalar to extract. Empty uses type default.
530 * @param output CONTAINER for concatenative, CONTAINER_ADDITIVE for OLA.
531 */
532template <typename CompleteFn>
534 const std::shared_ptr<GranularMatrix>& matrix,
535 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
536 AnalysisType analysis_type,
537 CompleteFn&& on_complete,
538 const GranularConfig& config = {},
539 const std::string& qualifier = {},
541{
542 auto ctx = make_granular_context(config, analysis_type, qualifier);
543
544 ctx.execution_metadata["container"] = container;
545 if (config.taper)
546 ctx.execution_metadata["grain_taper"] = config.taper;
547
548 auto seg_op = matrix->get_operation<SegmentOp>("segment");
549 auto attr_op = matrix->get_operation<AttributeOp>("attribute");
550 auto sort_op = matrix->get_operation<SortOp>("sort");
551 apply_context_parameters(seg_op, ctx);
552 apply_context_parameters(attr_op, ctx);
553 apply_context_parameters(sort_op, ctx);
554
555 matrix->with_async(make_granular_input(container), [seg_op, attr_op, sort_op, ctx, output](auto chain) {
556 auto sorted = chain
557 .template then<SegmentOp>("segment")
558 .template then<AttributeOp>("attribute")
559 .template then<SortOp>("sort")
560 .to_io();
562 return safe_any_cast_or_throw<
563 Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>>(
564 reconstruct_grains_additive(std::any(sorted), ctx));
565 }
566 return safe_any_cast_or_throw<
567 Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>>(
568 reconstruct_grains(std::any(sorted), ctx)); }, std::forward<CompleteFn>(on_complete));
569}
570
571/**
572 * @brief Async offline granular pipeline (AttributeExecutor path).
573 *
574 * @param matrix ComputeMatrix that owns the async future.
575 * @param container Source signal data.
576 * @param executor Lambda receiving grain samples and context, returning a scalar.
577 * @param on_complete Called on the worker thread with the finished container.
578 * @param config Pipeline scalar parameters.
579 * @param output CONTAINER for concatenative, CONTAINER_ADDITIVE for OLA.
580 */
581template <typename CompleteFn>
583 const std::shared_ptr<GranularMatrix>& matrix,
584 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
585 AttributeExecutor executor,
586 CompleteFn&& on_complete,
587 const GranularConfig& config = {},
589{
590 auto ctx = make_granular_context(config, std::move(executor));
591
592 ctx.execution_metadata["container"] = container;
593 if (config.taper)
594 ctx.execution_metadata["grain_taper"] = config.taper;
595
596 auto seg_op = matrix->get_operation<SegmentOp>("segment");
597 auto attr_op = matrix->get_operation<AttributeOp>("attribute");
598 auto sort_op = matrix->get_operation<SortOp>("sort");
599 apply_context_parameters(seg_op, ctx);
600 apply_context_parameters(attr_op, ctx);
601 apply_context_parameters(sort_op, ctx);
602
603 matrix->with_async(make_granular_input(container), [seg_op, attr_op, sort_op, ctx, output](auto chain) {
604 auto sorted = chain
605 .template then<SegmentOp>("segment")
606 .template then<AttributeOp>("attribute")
607 .template then<SortOp>("sort")
608 .to_io();
610 return safe_any_cast_or_throw<
612 reconstruct_grains_additive(std::any(sorted), ctx));
613 }
614 return safe_any_cast_or_throw<
615 Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>>(
616 reconstruct_grains(std::any(sorted), ctx)); }, std::forward<CompleteFn>(on_complete));
617}
618
619/**
620 * @brief Async offline granular pipeline terminating in a DynamicSoundStream
621 * (AnalysisType path).
622 *
623 * Runs the full pipeline on a background thread owned by @p matrix and
624 * invokes @p on_complete with the finished stream. Returns immediately.
625 *
626 * The callback receives a @c shared_ptr<DynamicSoundStream> which is null
627 * if reconstruction produced an unexpected type. The caller is responsible
628 * for thread-safe installation of the stream into any downstream pipeline.
629 *
630 * @param matrix ComputeMatrix that owns the async future.
631 * @param container Source signal data.
632 * @param analysis_type Attribution category.
633 * @param on_complete Called on the worker thread with the finished stream.
634 * @param config Pipeline scalar parameters.
635 * @param qualifier Scalar to extract. Empty uses type default.
636 * @param output STREAM for concatenative, STREAM_ADDITIVE for OLA.
637 */
638template <typename CompleteFn>
640 const std::shared_ptr<GranularMatrix>& matrix,
641 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
642 AnalysisType analysis_type,
643 CompleteFn&& on_complete,
644 const GranularConfig& config = {},
645 const std::string& qualifier = {},
647{
648 auto ctx = make_granular_context(config, analysis_type, qualifier);
649 ctx.execution_metadata["container"] = container;
650 if (config.taper)
651 ctx.execution_metadata["grain_taper"] = config.taper;
652
653 auto seg_op = matrix->get_operation<SegmentOp>("segment");
654 auto attr_op = matrix->get_operation<AttributeOp>("attribute");
655 auto sort_op = matrix->get_operation<SortOp>("sort");
656 apply_context_parameters(seg_op, ctx);
657 apply_context_parameters(attr_op, ctx);
658 apply_context_parameters(sort_op, ctx);
659
660 matrix->with_async(
661 make_granular_input(container),
662 [ctx, output](auto chain) {
663 auto sorted = chain
664 .template then<SegmentOp>("segment")
665 .template then<AttributeOp>("attribute")
666 .template then<SortOp>("sort")
667 .to_io();
668 if (output == GranularOutput::STREAM_ADDITIVE) {
669 return safe_any_cast_or_throw<
670 Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>>(
671 reconstruct_grains_additive_stream(std::any(sorted), ctx));
672 }
673 return safe_any_cast_or_throw<
674 Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>>(
675 reconstruct_grains_stream(std::any(sorted), ctx));
676 },
677 [on_complete = std::forward<CompleteFn>(on_complete)](
678 const Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>& result) {
679 on_complete(std::dynamic_pointer_cast<Kakshya::DynamicSoundStream>(result.data));
680 });
681}
682
683/**
684 * @brief Async offline granular pipeline terminating in a DynamicSoundStream
685 * (AttributeExecutor path).
686 *
687 * @param matrix ComputeMatrix that owns the async future.
688 * @param container Source signal data.
689 * @param executor Lambda receiving grain samples and context, returning a scalar.
690 * @param on_complete Called on the worker thread with the finished stream.
691 * @param config Pipeline scalar parameters.
692 * @param output STREAM for concatenative, STREAM_ADDITIVE for OLA.
693 */
694template <typename CompleteFn>
696 const std::shared_ptr<GranularMatrix>& matrix,
697 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
698 AttributeExecutor executor,
699 CompleteFn&& on_complete,
700 const GranularConfig& config = {},
702{
703 auto ctx = make_granular_context(config, std::move(executor));
704 ctx.execution_metadata["container"] = container;
705 if (config.taper)
706 ctx.execution_metadata["grain_taper"] = config.taper;
707
708 auto seg_op = matrix->get_operation<SegmentOp>("segment");
709 auto attr_op = matrix->get_operation<AttributeOp>("attribute");
710 auto sort_op = matrix->get_operation<SortOp>("sort");
711 apply_context_parameters(seg_op, ctx);
712 apply_context_parameters(attr_op, ctx);
713 apply_context_parameters(sort_op, ctx);
714
715 matrix->with_async(
716 make_granular_input(container),
717 [ctx, output](auto chain) {
718 auto sorted = chain
719 .template then<SegmentOp>("segment")
720 .template then<AttributeOp>("attribute")
721 .template then<SortOp>("sort")
722 .to_io();
723 if (output == GranularOutput::STREAM_ADDITIVE) {
724 return safe_any_cast_or_throw<
726 reconstruct_grains_additive_stream(std::any(sorted), ctx));
727 }
728 return safe_any_cast_or_throw<
729 Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>>(
730 reconstruct_grains_stream(std::any(sorted), ctx));
731 },
732 [on_complete = std::forward<CompleteFn>(on_complete)](
733 const Datum<std::shared_ptr<Kakshya::SignalSourceContainer>>& result) {
734 on_complete(std::dynamic_pointer_cast<Kakshya::DynamicSoundStream>(result.data));
735 });
736}
737
738} // namespace MayaFlux::Yantra::Granular
Span-based energy analysis for digital signals in Maya Flux.
Concrete feature extractor using analyzer-guided extraction.
Example concrete implementation of UniversalSorter.
uint32_t channel
Analyzer-guided feature extractor with enum-based configuration.
ComputeMatrix extension that integrates grammar-based operation selection.
AnalysisType get_analysis_type() const override
Gets the analysis type category for this analyzer.
std::string get_analyzer_name() const override
Get analyzer-specific name (derived classes override this)
Computes a scalar attribute per grain and writes it onto each Region.
std::string get_extractor_name() const override
Get extractor name.
ExtractionType get_extraction_type() const override
Get extraction type category.
Segments container audio into fixed hop-size grain windows.
std::string get_sorter_name() const override
Get sorter-specific name (derived classes override this)
SortingType get_sorting_type() const override
Gets the sorting type category for this sorter.
Sorts grains by a named attribute key, with optional GPU dispatch.
Concrete implementation for standard comparison-based sorting.
Template-flexible analyzer base with instance-defined I/O types.
std::function< void(std::span< double >)> RegionTaper
Per-region taper applied in-place before the write callback is invoked.
const ComputationGrammar::Rule::Executor sort_grains
Grammar rule executor for the sort step.
const ComputationGrammar::Rule::Executor reconstruct_grains_stream
Grammar rule executor — concatenative reconstruct into DynamicSoundStream.
Datum< Kakshya::RegionGroup > GranularDatum
Datum specialisation for granular processing pipelines.
const ComputationGrammar::Rule::Executor attribute_grains
Grammar rule executor for the attribution step.
GranularOutput
Selects the terminal output type produced by make_granular_matrix.
std::function< double(std::span< const double >, const ExecutionContext &)> AttributeExecutor
Span-level escape hatch for fully custom per-grain feature computation.
void process_to_container_async(const std::shared_ptr< GranularMatrix > &matrix, const std::shared_ptr< Kakshya::SignalSourceContainer > &container, AnalysisType analysis_type, CompleteFn &&on_complete, const GranularConfig &config={}, const std::string &qualifier={}, GranularOutput output=GranularOutput::CONTAINER)
Async offline granular pipeline (AnalysisType path).
ExecutionContext make_granular_context(const GranularConfig &config, AnalysisType analysis_type, const std::string &qualifier={})
Construct an ExecutionContext for the granular pipeline using a built-in AnalysisType.
GranularDatum make_granular_input(const std::shared_ptr< Kakshya::SignalSourceContainer > &container, const std::string &group_name="grains")
Construct the initial GranularDatum from a container.
std::shared_ptr< GranularMatrix > make_granular_matrix(ComputationContext attribution_context, GranularOutput output, GrainTaper taper)
Construct a GranularMatrix with grammar rules appropriate for the requested output type.
const ComputationGrammar::Rule::Executor segment_grains
Grammar rule executor for the segmentation step.
const ComputationGrammar::Rule::Executor reconstruct_grains_additive_stream
Grammar rule executor — OLA reconstruct into DynamicSoundStream.
Kakshya::RegionTaper GrainTaper
Per-grain taper applied before accumulation in OLA reconstruction.
GranularDatum process(const std::shared_ptr< Kakshya::SignalSourceContainer > &container, AnalysisType analysis_type, const GranularConfig &config, const std::string &qualifier)
Run segment -> attribute -> sort and return the attributed RegionGroup.
const ComputationGrammar::Rule::Executor reconstruct_grains_additive
Grammar rule executor for additive grain reconstruction.
std::shared_ptr< Kakshya::SoundFileContainer > process_to_container(const std::shared_ptr< Kakshya::SignalSourceContainer > &container, AnalysisType analysis_type, const GranularConfig &config, const std::string &qualifier, GranularOutput output)
Offline granular pipeline terminating in a SoundFileContainer.
const ComputationGrammar::Rule::Executor reconstruct_grains
Grammar rule executor for the reconstruction step.
void process_to_stream_async(const std::shared_ptr< GranularMatrix > &matrix, const std::shared_ptr< Kakshya::SignalSourceContainer > &container, AnalysisType analysis_type, CompleteFn &&on_complete, const GranularConfig &config={}, const std::string &qualifier={}, GranularOutput output=GranularOutput::STREAM)
Async offline granular pipeline terminating in a DynamicSoundStream (AnalysisType path).
std::shared_ptr< Kakshya::DynamicSoundStream > process_to_stream(const std::shared_ptr< Kakshya::SignalSourceContainer > &container, AnalysisType analysis_type, const GranularConfig &config, const std::string &qualifier, GranularOutput output)
Offline granular pipeline terminating in a DynamicSoundStream.
AnalysisType
Categories of analysis operations for discovery and organization.
ExtractionType
Categories of extraction operations for discovery and organization.
void apply_context_parameters(std::shared_ptr< OperationType > operation, const ExecutionContext &ctx)
Applies context parameters to an operation.
ComputationContext
Defines the computational contexts in which rules can be applied.
@ SPECTRAL
Frequency-domain operations.
ExtractionMethod
Supported extraction methods for FeatureExtractor.
@ OVERLAPPING_WINDOWS
Extract overlapping windowed data.
SortingType
Categories of sorting operations for discovery and organization.
Organizes related signal regions into a categorized collection.
Represents a point or span in N-dimensional space.
Definition Region.hpp:67
std::function< std::any(const std::any &, const ExecutionContext &)> Executor
Type alias for matcher functions used in computation rules.
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:24
std::unordered_map< std::string, std::any > execution_metadata
Arbitrary metadata parameters used by operations.
Context information controlling how a compute operation executes.
Scalar parameters shared across all granular pipeline entry points.