MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Yantra.cpp
Go to the documentation of this file.
1#include "Yantra.hpp"
2
7
10
11namespace MayaFlux {
12
13namespace D = Kinesis::Discrete;
14
15namespace {
16 bool is_same_size(const std::vector<std::span<double>>& data)
17 {
18 if (data.empty())
19 return true;
20
21 const auto expected_size = data.front().size();
22 return std::ranges::all_of(data,
23 [&expected_size](const auto& v) { return v.size() == expected_size; });
24 }
25
26 std::vector<double> concat_vectors(const std::vector<std::span<double>>& data)
27 {
28 std::vector<double> result;
29 result.reserve(std::accumulate(
30 data.begin(), data.end(), size_t(0),
31 [](size_t sum, const auto& span) { return sum + span.size(); }));
32
33 for (const auto& span : data) {
34 result.insert(result.end(), span.begin(), span.end());
35 }
36 return result;
37 }
38
39 std::span<double> as_span(std::vector<double>& v) noexcept
40 {
41 return { v.data(), v.size() };
42 }
43
44 std::span<double> as_span(Kakshya::DataVariant& v)
45 {
46 return Yantra::OperationHelper::extract_numeric_data(v);
47 }
48
49}
50
51//=========================================================================
52// STATISTICAL ANALYSIS
53//=========================================================================
54
55double mean(const std::vector<double>& data)
56{
57 static const auto s_op = [] {
58 auto a = std::make_shared<Yantra::StatisticalAnalyzer<>>();
60 return a;
61 }();
62 return s_op->analyze_statistics({ Kakshya::DataVariant(data) }).channel_statistics[0].mean_stat;
63}
64
65double mean(const Kakshya::DataVariant& data)
66{
67 static const auto s_op = [] {
68 auto a = std::make_shared<Yantra::StatisticalAnalyzer<>>();
70 return a;
71 }();
72 return s_op->analyze_statistics({ data }).channel_statistics[0].mean_stat;
73}
74
75std::vector<double> mean_per_channel(const std::vector<Kakshya::DataVariant>& channels)
76{
77 static const auto s_op = [] {
78 auto a = std::make_shared<Yantra::StatisticalAnalyzer<>>();
80 return a;
81 }();
82 auto result = s_op->analyze_statistics(channels);
83
84 std::vector<double> means;
85 means.reserve(result.channel_statistics.size());
86 for (const auto& stats : result.channel_statistics)
87 means.push_back(stats.mean_stat);
88 return means;
89}
90
91double mean_combined(const std::vector<Kakshya::DataVariant>& channels)
92{
94 if (is_same_size(data)) {
95 auto result = mean_per_channel(channels);
96 return std::accumulate(result.begin(), result.end(), 0.0) / (double)result.size();
97 }
98 auto mixed = concat_vectors(data);
99 return mean(mixed);
100}
101
102double rms(const std::vector<double>& data)
103{
104 static const auto s_op = [] {
105 auto a = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
107 return a;
108 }();
109 auto result = s_op->analyze_statistics({ Kakshya::DataVariant(data) });
110 return result.channel_statistics[0].statistical_values.empty() ? 0.0 : result.channel_statistics[0].statistical_values[0];
111}
112
113double rms(const Kakshya::DataVariant& data)
114{
115 static const auto s_op = [] {
116 auto a = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
118 return a;
119 }();
120 auto result = s_op->analyze_statistics({ data });
121 return result.channel_statistics[0].statistical_values.empty() ? 0.0 : result.channel_statistics[0].statistical_values[0];
122}
123
124std::vector<double> rms_per_channel(const std::vector<Kakshya::DataVariant>& channels)
125{
126 static const auto s_op = [] {
127 auto a = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
129 return a;
130 }();
131 auto result = s_op->analyze_statistics(channels);
132 std::vector<double> rms_values;
133 rms_values.reserve(result.channel_statistics.size());
134
135 for (const auto& stats : result.channel_statistics) {
136 rms_values.push_back(stats.statistical_values.empty() ? 0.0 : stats.statistical_values[0]);
137 }
138
139 return rms_values;
140}
141
142double rms_combined(const std::vector<Kakshya::DataVariant>& channels)
143{
145 if (is_same_size(data)) {
146 auto result = rms_per_channel(channels);
147 double sum_squares = 0.0;
148 for (double v : result)
149 sum_squares += v * v;
150 return std::sqrt(sum_squares / (double)result.size());
151 }
152 auto mixed = concat_vectors(data);
153 return rms(mixed);
154}
155
156double std_dev(const std::vector<double>& data)
157{
158 static const auto s_op = [] {
159 auto a = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
161 return a;
162 }();
163 return s_op->analyze_statistics({ Kakshya::DataVariant(data) }).channel_statistics[0].stat_std_dev;
164}
165
166double std_dev(const Kakshya::DataVariant& data)
167{
168 static const auto s_op = [] {
169 auto a = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
171 return a;
172 }();
173 return s_op->analyze_statistics({ data }).channel_statistics[0].stat_std_dev;
174}
175
176std::vector<double> std_dev_per_channel(const std::vector<Kakshya::DataVariant>& channels)
177{
178 static const auto s_op = [] {
179 auto a = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
181 return a;
182 }();
183 auto result = s_op->analyze_statistics(channels);
184 std::vector<double> std_devs;
185
186 std_devs.reserve(result.channel_statistics.size());
187 for (const auto& stats : result.channel_statistics) {
188 std_devs.push_back(stats.stat_std_dev);
189 }
190
191 return std_devs;
192}
193
194double std_dev_combined(const std::vector<Kakshya::DataVariant>& channels)
195{
197 if (is_same_size(data)) {
198 auto result = std_dev_per_channel(channels);
199 return std::accumulate(result.begin(), result.end(), 0.0) / (double)result.size();
200 }
201 auto mixed = concat_vectors(data);
202 return std_dev(mixed);
203}
204
205//=========================================================================
206// ENERGY ANALYSIS
207//=========================================================================
208
209double dynamic_range(const std::vector<double>& data)
210{
211 static const auto s_op = [] {
212 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
213 a->set_energy_method(Yantra::EnergyMethod::DYNAMIC_RANGE);
214 return a;
215 }();
216 auto result = s_op->analyze_energy({ Kakshya::DataVariant(data) });
217 return result.channels.empty() || result.channels[0].energy_values.empty() ? 0.0 : result.channels[0].energy_values[0];
218}
219
221{
222 static const auto s_op = [] {
223 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
224 a->set_energy_method(Yantra::EnergyMethod::DYNAMIC_RANGE);
225 return a;
226 }();
227 auto result = s_op->analyze_energy({ data });
228 return result.channels.empty() || result.channels[0].energy_values.empty() ? 0.0 : result.channels[0].energy_values[0];
229}
230
231std::vector<double> dynamic_range_per_channel(const std::vector<Kakshya::DataVariant>& channels)
232{
233 static const auto s_op = [] {
234 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
235 a->set_energy_method(Yantra::EnergyMethod::DYNAMIC_RANGE);
236 return a;
237 }();
238 auto result = s_op->analyze_energy(channels);
239 std::vector<double> ranges;
240
241 ranges.reserve(result.channels.size());
242 for (const auto& ch : result.channels) {
243 ranges.push_back(ch.energy_values.empty() ? 0.0 : ch.energy_values[0]);
244 }
245
246 return ranges;
247}
248
249double dynamic_range_global(const std::vector<Kakshya::DataVariant>& channels)
250{
252 double global_min = std::numeric_limits<double>::max();
253 double global_max = std::numeric_limits<double>::lowest();
254
255 for (const auto& span : data) {
256 auto [min_it, max_it] = std::ranges::minmax_element(span);
257 if (min_it != span.end()) {
258 global_min = std::min(global_min, *min_it);
259 global_max = std::max(global_max, *max_it);
260 }
261 }
262
263 if (global_min <= 0.0 || global_max <= 0.0)
264 return 0.0;
265 return 20.0 * std::log10(global_max / std::abs(global_min));
266}
267
268double peak(const std::vector<double>& data)
269{
270 static const auto s_op = [] {
271 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
272 a->set_energy_method(Yantra::EnergyMethod::PEAK);
273 return a;
274 }();
275 auto result = s_op->analyze_energy({ Kakshya::DataVariant(data) });
276 return result.channels.empty() ? 0.0 : result.channels[0].max_energy;
277}
278
279double peak(const Kakshya::DataVariant& data)
280{
281 static const auto s_op = [] {
282 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
283 a->set_energy_method(Yantra::EnergyMethod::PEAK);
284 return a;
285 }();
286 auto result = s_op->analyze_energy({ data });
287 return result.channels.empty() ? 0.0 : result.channels[0].max_energy;
288}
289
290double peak(const std::vector<Kakshya::DataVariant>& channels)
291{
292 static const auto s_op = [] {
293 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
294 a->set_energy_method(Yantra::EnergyMethod::PEAK);
295 return a;
296 }();
297 auto result = s_op->analyze_energy(channels);
298 double global_peak = 0.0;
299 for (const auto& ch : result.channels)
300 global_peak = std::max(global_peak, ch.max_energy);
301 return global_peak;
302}
303
304std::vector<double> peak_per_channel(const std::vector<Kakshya::DataVariant>& channels)
305{
306 static const auto s_op = [] {
307 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
308 a->set_energy_method(Yantra::EnergyMethod::PEAK);
309 return a;
310 }();
311 auto result = s_op->analyze_energy(channels);
312 std::vector<double> peaks;
313 peaks.reserve(result.channels.size());
314
315 for (const auto& ch : result.channels)
316 peaks.push_back(ch.max_energy);
317 return peaks;
318}
319
320double peak_channel(const std::vector<Kakshya::DataVariant>& channels, size_t channel_index)
321{
322 if (channel_index >= channels.size()) {
323 error<std::out_of_range>(Journal::Component::API, Journal::Context::API, std::source_location::current(),
324 "Channel index out of range");
325 }
326 return peak(channels[channel_index]);
327}
328
329//=========================================================================
330// FEATURE EXTRACTION
331//=========================================================================
332
333std::vector<size_t> zero_crossings(const std::vector<double>& data, double threshold)
334{
335 static const auto s_op = [] {
336 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
337 a->set_energy_method(Yantra::EnergyMethod::ZERO_CROSSING);
338 return a;
339 }();
340 auto result = s_op->analyze_energy({ Kakshya::DataVariant(data) });
341 if (result.channels.empty())
342 return {};
343
344 const auto& positions = result.channels[0].event_positions;
345 if (threshold <= 0.0)
346 return positions;
347
348 std::vector<size_t> filtered;
349 for (size_t pos : positions) {
350 if (pos < data.size() && std::abs(data[pos]) >= threshold)
351 filtered.push_back(pos);
352 }
353 return filtered;
354}
355
356std::vector<size_t> zero_crossings(const Kakshya::DataVariant& data, double threshold)
357{
358 static const auto s_op = [] {
359 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
360 a->set_energy_method(Yantra::EnergyMethod::ZERO_CROSSING);
361 return a;
362 }();
363 auto result = s_op->analyze_energy({ data });
364 if (result.channels.empty())
365 return {};
366
367 const auto& positions = result.channels[0].event_positions;
368 if (threshold <= 0.0)
369 return positions;
370
371 auto double_data = std::get<std::vector<double>>(data);
372 std::vector<size_t> filtered;
373 for (size_t pos : positions) {
374 if (pos < double_data.size() && std::abs(double_data[pos]) >= threshold)
375 filtered.push_back(pos);
376 }
377 return filtered;
378}
379
380std::vector<std::vector<size_t>> zero_crossings_per_channel(const std::vector<Kakshya::DataVariant>& channels, double threshold)
381{
382 static const auto s_op = [] {
383 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
384 a->set_energy_method(Yantra::EnergyMethod::ZERO_CROSSING);
385 return a;
386 }();
387 auto result = s_op->analyze_energy(channels);
388 std::vector<std::vector<size_t>> all_crossings;
389 all_crossings.reserve(result.channels.size());
390
391 for (size_t ch = 0; ch < result.channels.size(); ++ch) {
392 const auto& positions = result.channels[ch].event_positions;
393 if (threshold <= 0.0) {
394 all_crossings.push_back(positions);
395 continue;
396 }
397 auto double_data = std::get<std::vector<double>>(channels[ch]);
398 std::vector<size_t> filtered;
399 for (size_t pos : positions) {
400 if (pos < double_data.size() && std::abs(double_data[pos]) >= threshold)
401 filtered.push_back(pos);
402 }
403 all_crossings.push_back(filtered);
404 }
405 return all_crossings;
406}
407
408double zero_crossing_rate(const std::vector<double>& data, size_t window_size)
409{
410 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
411 a->set_energy_method(Yantra::EnergyMethod::ZERO_CROSSING);
412 if (window_size > 0)
413 a->set_window_parameters(window_size, window_size / 2);
414 auto result = a->analyze_energy({ Kakshya::DataVariant(data) });
415 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
416}
417
418double zero_crossing_rate(const Kakshya::DataVariant& data, size_t window_size)
419{
420 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
421 a->set_energy_method(Yantra::EnergyMethod::ZERO_CROSSING);
422 if (window_size > 0)
423 a->set_window_parameters(window_size, window_size / 2);
424 auto result = a->analyze_energy({ data });
425 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
426}
427
428std::vector<double> zero_crossing_rate_per_channel(const std::vector<Kakshya::DataVariant>& channels, size_t window_size)
429{
430 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
431 a->set_energy_method(Yantra::EnergyMethod::ZERO_CROSSING);
432 if (window_size > 0)
433 a->set_window_parameters(window_size, window_size / 2);
434 auto result = a->analyze_energy(channels);
435 std::vector<double> rates;
436
437 rates.reserve(result.channels.size());
438 for (const auto& ch : result.channels)
439 rates.push_back(ch.mean_energy);
440 return rates;
441}
442
443double spectral_centroid(const std::vector<double>& data, double sample_rate)
444{
445 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
446 a->set_energy_method(Yantra::EnergyMethod::SPECTRAL);
447 a->set_parameter("sample_rate", sample_rate);
448 auto result = a->analyze_energy({ Kakshya::DataVariant(data) });
449 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
450}
451
452double spectral_centroid(const Kakshya::DataVariant& data, double sample_rate)
453{
454 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
455 a->set_energy_method(Yantra::EnergyMethod::SPECTRAL);
456 a->set_parameter("sample_rate", sample_rate);
457 auto result = a->analyze_energy({ data });
458 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
459}
460
461std::vector<double> spectral_centroid_per_channel(const std::vector<Kakshya::DataVariant>& channels, double sample_rate)
462{
463 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
464 a->set_energy_method(Yantra::EnergyMethod::SPECTRAL);
465 a->set_parameter("sample_rate", sample_rate);
466 auto result = a->analyze_energy(channels);
467 std::vector<double> centroids;
468
469 centroids.reserve(result.channels.size());
470 for (const auto& ch : result.channels)
471 centroids.push_back(ch.mean_energy);
472
473 return centroids;
474}
475
476std::vector<double> detect_onsets(const std::vector<double>& data, double sample_rate, double threshold)
477{
478 auto onset_positions = Kinesis::Discrete::onset_positions(
479 std::span<const double>(data.data(), data.size()), 1024, 512, threshold);
480 std::vector<double> times;
481
482 times.reserve(onset_positions.size());
483 for (size_t pos : onset_positions) {
484 times.push_back(static_cast<double>(pos) / sample_rate);
485 }
486 return times;
487}
488
489std::vector<double> detect_onsets(const Kakshya::DataVariant& data, double sample_rate, double threshold)
490{
491 auto double_data = std::get<std::vector<double>>(data);
492 auto onset_positions = Kinesis::Discrete::onset_positions(
493 std::span<const double>(double_data.data(), double_data.size()), 1024, 512, threshold);
494
495 std::vector<double> times;
496
497 times.reserve(onset_positions.size());
498 for (size_t pos : onset_positions)
499 times.push_back(static_cast<double>(pos) / sample_rate);
500 return times;
501}
502
503std::vector<std::vector<double>> detect_onsets_per_channel(const std::vector<Kakshya::DataVariant>& channels, double sample_rate, double threshold)
504{
505 std::vector<std::vector<double>> all_onsets;
506 all_onsets.reserve(channels.size());
507
508 for (const auto& channel : channels)
509 all_onsets.push_back(detect_onsets(channel, sample_rate, threshold));
510 return all_onsets;
511}
512
513//=========================================================================
514// BASIC TRANSFORMATIONS - Use Kinesis
515//=========================================================================
516
517void apply_gain(std::vector<double>& data, double gain_factor)
518{
519 D::linear(as_span(data), gain_factor, 0.0);
520}
521
522void apply_gain(Kakshya::DataVariant& data, double gain_factor)
523{
524 D::linear(as_span(data), gain_factor, 0.0);
525}
526
527void apply_gain_channels(std::vector<Kakshya::DataVariant>& channels, double gain_factor)
528{
529 for (auto& ch : channels)
530 apply_gain(ch, gain_factor);
531}
532
533void apply_gain_per_channel(std::vector<Kakshya::DataVariant>& channels, const std::vector<double>& gain_factors)
534{
535 if (gain_factors.size() != channels.size()) {
536 error<std::invalid_argument>(Journal::Component::API, Journal::Context::API, std::source_location::current(),
537 "Gain factors size must match channels size");
538 }
539 for (size_t i = 0; i < channels.size(); ++i)
540 apply_gain(channels[i], gain_factors[i]);
541}
542
543std::vector<double> with_gain(const std::vector<double>& data, double gain_factor)
544{
545 auto out = data;
546 D::linear(as_span(out), gain_factor, 0.0);
547 return out;
548}
549
551{
552 auto out = data;
553 D::linear(as_span(out), gain_factor, 0.0);
554 return out;
555}
556
557std::vector<Kakshya::DataVariant> with_gain_channels(const std::vector<Kakshya::DataVariant>& channels, double gain_factor)
558{
559 auto out = channels;
560 for (auto& ch : out)
561 D::linear(as_span(ch), gain_factor, 0.0);
562 return out;
563}
564
565void normalize(std::vector<double>& data, double target_peak)
566{
567 D::normalize(as_span(data), -target_peak, target_peak);
568}
569
570void normalize(Kakshya::DataVariant& data, double target_peak)
571{
572 D::normalize(as_span(data), -target_peak, target_peak);
573}
574
575void normalize_channels(std::vector<Kakshya::DataVariant>& channels, double target_peak)
576{
577 for (auto& ch : channels)
578 normalize(ch, target_peak);
579}
580
581void normalize_together(std::vector<Kakshya::DataVariant>& channels, double target_peak)
582{
583 const double global_peak = peak(channels);
584 if (global_peak > 0.0)
585 apply_gain_channels(channels, target_peak / global_peak);
586}
587
588std::vector<double> normalized(const std::vector<double>& data, double target_peak)
589{
590 auto out = data;
591 D::normalize(as_span(out), -target_peak, target_peak);
592 return out;
593}
594
596{
597 auto out = data;
598 D::normalize(as_span(out), -target_peak, target_peak);
599 return out;
600}
601
602std::vector<Kakshya::DataVariant> normalized_channels(const std::vector<Kakshya::DataVariant>& channels, double target_peak)
603{
604 auto out = channels;
605 for (auto& ch : out)
606 normalize(ch, target_peak);
607 return out;
608}
609
610//=========================================================================
611// TEMPORAL TRANSFORMATIONS
612//=========================================================================
613
614void reverse(std::vector<double>& data)
615{
616 D::reverse(as_span(data));
617}
618
620{
621 D::reverse(as_span(data));
622}
623
624void reverse_channels(std::vector<Kakshya::DataVariant>& channels)
625{
626 for (auto& ch : channels)
627 D::reverse(as_span(ch));
628}
629
630std::vector<double> reversed(const std::vector<double>& data)
631{
632 auto out = data;
633 D::reverse(as_span(out));
634 return out;
635}
636
638{
639 auto out = data;
640 D::reverse(as_span(out));
641 return out;
642}
643
644std::vector<Kakshya::DataVariant> reversed_channels(const std::vector<Kakshya::DataVariant>& channels)
645{
646 auto out = channels;
647 for (auto& ch : out)
648 D::reverse(as_span(ch));
649 return out;
650}
651
652//=========================================================================
653// FREQUENCY DOMAIN
654//=========================================================================
655
656std::vector<double> magnitude_spectrum(const std::vector<double>& data, size_t window_size)
657{
658 auto a = std::make_shared<Yantra::EnergyAnalyzer<>>();
659 a->set_energy_method(Yantra::EnergyMethod::SPECTRAL);
660 if (window_size > 0)
661 a->set_window_parameters(window_size, window_size / 2);
662 return a->analyze_energy({ Kakshya::DataVariant(data) }).channels[0].energy_values;
663}
664
665std::vector<double> magnitude_spectrum(const Kakshya::DataVariant& data, size_t window_size)
666{
667 auto a = std::make_shared<Yantra::EnergyAnalyzer<>>();
668 a->set_energy_method(Yantra::EnergyMethod::SPECTRAL);
669 if (window_size > 0)
670 a->set_window_parameters(window_size, window_size / 2);
671 return a->analyze_energy({ data }).channels[0].energy_values;
672}
673
674std::vector<std::vector<double>> magnitude_spectrum_per_channel(const std::vector<Kakshya::DataVariant>& channels, size_t window_size)
675{
676 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
677 a->set_energy_method(Yantra::EnergyMethod::SPECTRAL);
678 if (window_size > 0)
679 a->set_window_parameters(window_size, window_size / 2);
680 auto result = a->analyze_energy(channels);
681 std::vector<std::vector<double>> spectra;
682
683 spectra.reserve(result.channels.size());
684 for (const auto& ch : result.channels) {
685 spectra.push_back(ch.energy_values);
686 }
687 return spectra;
688}
689
690std::vector<double> power_spectrum(const std::vector<double>& data, size_t window_size)
691{
692 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
693 a->set_energy_method(Yantra::EnergyMethod::POWER);
694 if (window_size > 0)
695 a->set_window_parameters(window_size, window_size / 2);
696 return a->analyze_energy({ Kakshya::DataVariant(data) }).channels[0].energy_values;
697}
698
699std::vector<double> power_spectrum(const Kakshya::DataVariant& data, size_t window_size)
700{
701 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
702 a->set_energy_method(Yantra::EnergyMethod::POWER);
703 if (window_size > 0)
704 a->set_window_parameters(window_size, window_size / 2);
705 return a->analyze_energy({ data }).channels[0].energy_values;
706}
707
708std::vector<std::vector<double>> power_spectrum_per_channel(const std::vector<Kakshya::DataVariant>& channels, size_t window_size)
709{
710 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
711 a->set_energy_method(Yantra::EnergyMethod::POWER);
712 if (window_size > 0)
713 a->set_window_parameters(window_size, window_size / 2);
714 auto result = a->analyze_energy(channels);
715 std::vector<std::vector<double>> spectra;
716
717 spectra.reserve(result.channels.size());
718 for (const auto& ch : result.channels) {
719 spectra.push_back(ch.energy_values);
720 }
721
722 return spectra;
723}
724
725//=========================================================================
726// PITCH AND TIME - Use EnergyAnalyzer for harmonic analysis
727//=========================================================================
728
729double estimate_pitch(const std::vector<double>& data, double sample_rate, double min_freq, double max_freq)
730{
731 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
732 a->set_energy_method(Yantra::EnergyMethod::HARMONIC);
733 a->set_parameter("sample_rate", sample_rate);
734 a->set_parameter("min_freq", min_freq);
735 a->set_parameter("max_freq", max_freq);
736 auto result = a->analyze_energy({ Kakshya::DataVariant(data) });
737 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy * sample_rate / 1000.0;
738}
739
740double estimate_pitch(const Kakshya::DataVariant& data, double sample_rate, double min_freq, double max_freq)
741{
742 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
743 a->set_energy_method(Yantra::EnergyMethod::HARMONIC);
744 a->set_parameter("sample_rate", sample_rate);
745 a->set_parameter("min_freq", min_freq);
746 a->set_parameter("max_freq", max_freq);
747 auto result = a->analyze_energy({ data });
748 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy * sample_rate / 1000.0;
749}
750
751std::vector<double> estimate_pitch_per_channel(const std::vector<Kakshya::DataVariant>& channels, double sample_rate, double min_freq, double max_freq)
752{
753 auto a = std::make_shared<Yantra::StandardEnergyAnalyzer>();
754 a->set_energy_method(Yantra::EnergyMethod::HARMONIC);
755 a->set_parameter("sample_rate", sample_rate);
756 a->set_parameter("min_freq", min_freq);
757 a->set_parameter("max_freq", max_freq);
758 auto result = a->analyze_energy(channels);
759 std::vector<double> pitches;
760 pitches.reserve(result.channels.size());
761
762 for (const auto& ch : result.channels) {
763 pitches.push_back(ch.mean_energy * sample_rate / 1000.0);
764 }
765 return pitches;
766}
767
768//=========================================================================
769// WINDOWING AND SEGMENTATION
770//=========================================================================
771
772std::vector<double> extract_silent_data(const std::vector<double>& data, double threshold, size_t min_silence_duration)
773{
774 static const auto s_op = [] {
775 auto e = std::make_shared<Yantra::FeatureExtractor<>>();
776 e->set_extraction_method(Yantra::ExtractionMethod::SILENCE_DATA);
777 return e;
778 }();
779 s_op->set_parameter("silence_threshold", threshold);
780 s_op->set_parameter("min_duration", static_cast<uint32_t>(min_silence_duration));
782 return s_op->apply_operation(input).data[0];
783}
784
785std::vector<double> extract_silent_data(const Kakshya::DataVariant& data, double threshold, size_t min_silence_duration)
786{
787 static const auto s_op = [] {
788 auto e = std::make_shared<Yantra::FeatureExtractor<>>();
789 e->set_extraction_method(Yantra::ExtractionMethod::SILENCE_DATA);
790 return e;
791 }();
792 s_op->set_parameter("silence_threshold", threshold);
793 s_op->set_parameter("min_duration", static_cast<uint32_t>(min_silence_duration));
795 return s_op->apply_operation(input).data[0];
796}
797
798std::vector<double> extract_zero_crossing_regions(const std::vector<double>& data, double threshold, size_t region_size)
799{
800 static const auto s_op = [] {
801 auto e = std::make_shared<Yantra::FeatureExtractor<>>();
802 e->set_extraction_method(Yantra::ExtractionMethod::ZERO_CROSSING_DATA);
803 e->set_parameter("min_distance", 1.0);
804 return e;
805 }();
806 s_op->set_parameter("threshold", threshold);
807 s_op->set_parameter("region_size", static_cast<uint32_t>(region_size));
809 return s_op->apply_operation(input).data[0];
810}
811
812std::vector<double> extract_zero_crossing_regions(const Kakshya::DataVariant& data, double threshold, size_t region_size)
813{
814 static const auto s_op = [] {
815 auto e = std::make_shared<Yantra::FeatureExtractor<>>();
816 e->set_extraction_method(Yantra::ExtractionMethod::ZERO_CROSSING_DATA);
817 e->set_parameter("min_distance", 1.0);
818 return e;
819 }();
820 s_op->set_parameter("threshold", threshold);
821 s_op->set_parameter("region_size", static_cast<uint32_t>(region_size));
823 return s_op->apply_operation(input).data[0];
824}
825
826void apply_window(std::vector<double>& data, const std::string& window_type)
827{
829
830 if (window_type == "hann" || window_type == "hanning") {
832 } else if (window_type == "hamming") {
834 } else if (window_type == "blackman") {
836 } else if (window_type == "rectangular" || window_type == "rect") {
838 } else {
840 }
841
842 auto window = Nodes::Generator::generate_window(data.size(), win_type);
843 for (size_t i = 0; i < data.size() && i < window.size(); ++i)
844 data[i] *= window[i];
845}
846
847void apply_window(Kakshya::DataVariant& data, const std::string& window_type)
848{
849 auto double_data = std::get<std::vector<double>>(data);
850 apply_window(double_data, window_type);
851 data = Kakshya::DataVariant(double_data);
852}
853
854void apply_window_channels(std::vector<Kakshya::DataVariant>& channels, const std::string& window_type)
855{
856 for (auto& ch : channels)
857 apply_window(ch, window_type);
858}
859
860std::vector<std::vector<double>> windowed_segments(const std::vector<double>& data, size_t window_size, size_t hop_size)
861{
862 auto e = std::make_shared<Yantra::FeatureExtractor<>>(
863 static_cast<uint32_t>(window_size), static_cast<uint32_t>(hop_size),
865 e->set_parameter("overlap", double(hop_size) / (double)window_size);
866
868 auto extracted = e->apply_operation(input).data[0];
869 std::vector<std::vector<double>> segments;
870 for (size_t i = 0; i < extracted.size(); i += window_size) {
871 size_t end = std::min(i + window_size, extracted.size());
872 segments.emplace_back(extracted.begin() + i, extracted.begin() + end);
873 }
874 return segments;
875}
876
877std::vector<std::vector<double>> windowed_segments(const Kakshya::DataVariant& data, size_t window_size, size_t hop_size)
878{
879 auto e = std::make_shared<Yantra::FeatureExtractor<>>(
880 static_cast<uint32_t>(window_size), static_cast<uint32_t>(hop_size),
882 e->set_parameter("overlap", double(hop_size) / (double)window_size);
884 auto extracted = e->apply_operation(input).data[0];
885 std::vector<std::vector<double>> segments;
886 for (size_t i = 0; i < extracted.size(); i += window_size) {
887 size_t end = std::min(i + window_size, extracted.size());
888 segments.emplace_back(extracted.begin() + i, extracted.begin() + end);
889 }
890 return segments;
891}
892
893std::vector<std::vector<std::vector<double>>> windowed_segments_per_channel(const std::vector<Kakshya::DataVariant>& channels, size_t window_size, size_t hop_size)
894{
895 std::vector<std::vector<std::vector<double>>> all_segments;
896 all_segments.reserve(channels.size());
897 for (const auto& ch : channels)
898 all_segments.push_back(windowed_segments(ch, window_size, hop_size));
899 return all_segments;
900}
901
902std::vector<std::pair<size_t, size_t>> detect_silence(const std::vector<double>& data, double threshold, size_t min_silence_duration)
903{
904 static const auto s_op = [] {
905 auto e = std::make_shared<Yantra::FeatureExtractor<>>();
906 e->set_extraction_method(Yantra::ExtractionMethod::SILENCE_DATA);
907 return e;
908 }();
909 s_op->set_parameter("silence_threshold", threshold);
910 s_op->set_parameter("min_duration", static_cast<uint32_t>(min_silence_duration));
912 auto result = s_op->apply_operation(input);
913 auto pos = result.template get_metadata<std::vector<std::pair<size_t, size_t>>>("window_positions");
914 return pos.has_value() ? pos.value() : std::vector<std::pair<size_t, size_t>> {};
915}
916
917std::vector<std::pair<size_t, size_t>> detect_silence(const Kakshya::DataVariant& data, double threshold, size_t min_silence_duration)
918{
919 static const auto s_op = [] {
920 auto e = std::make_shared<Yantra::FeatureExtractor<>>();
921 e->set_extraction_method(Yantra::ExtractionMethod::SILENCE_DATA);
922 return e;
923 }();
924 s_op->set_parameter("silence_threshold", threshold);
925 s_op->set_parameter("min_duration", static_cast<uint32_t>(min_silence_duration));
927 auto result = s_op->apply_operation(input);
928 auto pos = result.template get_metadata<std::vector<std::pair<size_t, size_t>>>("window_positions");
929 return pos.has_value() ? pos.value() : std::vector<std::pair<size_t, size_t>> {};
930}
931
932std::vector<std::vector<std::pair<size_t, size_t>>> detect_silence_per_channel(const std::vector<Kakshya::DataVariant>& channels, double threshold, size_t min_silence_duration)
933{
934 std::vector<std::vector<std::pair<size_t, size_t>>> all_regions;
935 all_regions.reserve(channels.size());
936 for (const auto& ch : channels)
937 all_regions.push_back(detect_silence(ch, threshold, min_silence_duration));
938 return all_regions;
939}
940
941//=========================================================================
942// UTILITY AND CONVERSION - Use MathematicalTransformer for mixing
943//=========================================================================
944
945std::vector<double> mix(const std::vector<std::vector<double>>& streams)
946{
947 if (streams.empty())
948 return {};
949
950 size_t max_length = 0;
951 for (const auto& s : streams)
952 max_length = std::max(max_length, s.size());
953
954 std::vector<double> result(max_length, 0.0);
955 for (const auto& s : streams) {
956 for (size_t i = 0; i < s.size(); ++i)
957 result[i] += s[i];
958 }
959
960 apply_gain(result, 1.0 / static_cast<double>(streams.size()));
961 return result;
962}
963
964std::vector<double> mix(const std::vector<Kakshya::DataVariant>& streams)
965{
966 if (streams.empty())
967 return {};
968
969 auto numeric_data = Yantra::OperationHelper::extract_numeric_data(streams);
970
971 if (is_same_size(numeric_data)) {
972 std::vector<double> result(numeric_data[0].size(), 0.0);
973 for (const auto& span : numeric_data) {
974 for (size_t i = 0; i < span.size(); ++i)
975 result[i] += span[i];
976 }
977 apply_gain(result, 1.0 / static_cast<double>(numeric_data.size()));
978 return result;
979 }
980
981 std::vector<std::vector<double>> double_streams;
982 double_streams.reserve(streams.size());
983 for (const auto& span : numeric_data)
984 double_streams.emplace_back(span.begin(), span.end());
985 return mix(double_streams);
986}
987
988std::vector<double> mix_with_gains(const std::vector<std::vector<double>>& streams, const std::vector<double>& gains)
989{
990 if (streams.empty() || gains.size() != streams.size()) {
991 error<std::invalid_argument>(Journal::Component::API, Journal::Context::API, std::source_location::current(),
992 "Streams and gains vectors must have the same size");
993 }
994
995 size_t max_length = 0;
996 for (const auto& s : streams)
997 max_length = std::max(max_length, s.size());
998
999 std::vector<double> result(max_length, 0.0);
1000 for (size_t s = 0; s < streams.size(); ++s) {
1001 for (size_t i = 0; i < streams[s].size(); ++i)
1002 result[i] += streams[s][i] * gains[s];
1003 }
1004 return result;
1005}
1006
1007std::vector<double> mix_with_gains(const std::vector<Kakshya::DataVariant>& streams, const std::vector<double>& gains)
1008{
1009 if (streams.empty() || gains.size() != streams.size()) {
1010 error<std::invalid_argument>(Journal::Component::API, Journal::Context::API, std::source_location::current(),
1011 "Streams and gains vectors must have the same size");
1012 }
1013
1014 auto numeric_data = Yantra::OperationHelper::extract_numeric_data(streams);
1015
1016 if (is_same_size(numeric_data)) {
1017 std::vector<double> result(numeric_data[0].size(), 0.0);
1018 for (size_t s = 0; s < numeric_data.size(); ++s) {
1019 for (size_t i = 0; i < numeric_data[s].size(); ++i)
1020 result[i] += numeric_data[s][i] * gains[s];
1021 }
1022 return result;
1023 }
1024
1025 std::vector<std::vector<double>> double_streams;
1026 double_streams.reserve(streams.size());
1027 for (const auto& span : numeric_data)
1028 double_streams.emplace_back(span.begin(), span.end());
1029 return mix_with_gains(double_streams, gains);
1030}
1031
1032std::vector<double> to_double_vector(const Kakshya::DataVariant& data)
1033{
1035 return span.empty() ? std::vector<double> {} : std::vector<double>(span.begin(), span.end());
1036}
1037
1038Kakshya::DataVariant to_data_variant(const std::vector<double>& data)
1039{
1040 return { data };
1041}
1042
1043std::vector<std::vector<double>> to_double_vectors(const std::vector<Kakshya::DataVariant>& channels)
1044{
1045 auto spans = Yantra::OperationHelper::extract_numeric_data(channels);
1046 std::vector<std::vector<double>> result;
1047 result.reserve(spans.size());
1048 for (const auto& span : spans)
1049 result.emplace_back(span.begin(), span.end());
1050 return result;
1051}
1052
1053std::vector<Kakshya::DataVariant> to_data_variants(const std::vector<std::vector<double>>& channel_data)
1054{
1055 std::vector<Kakshya::DataVariant> result;
1056 result.reserve(channel_data.size());
1057 for (const auto& ch : channel_data)
1058 result.emplace_back(ch);
1059 return result;
1060}
1061
1062//=========================================================================
1063// INITIALIZATION
1064//=========================================================================
1065
1067{
1068 // Initialize any global Yantra state if needed
1069 // Operations are generally stateless, so minimal initialization required
1070}
1071
1072} // namespace MayaFlux
Discrete sequence analysis primitives for MayaFlux::Kinesis.
Span-based energy analysis for digital signals in Maya Flux.
Concrete feature extractor using analyzer-guided extraction.
size_t a
RangeSet ranges
Range size
std::optional< size_t > times
uint32_t channel
Discrete sequence transformation primitives for MayaFlux::Kinesis.
Data analysis and transformation convenience API.
static std::span< double > extract_numeric_data(const T &compute_data)
extract numeric data from single-variant types
@ API
API calls from external code.
@ API
MayaFlux/API Wrapper and convenience functions.
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:76
void linear(std::span< double > data, double a, double b) noexcept
Linear map y = a*x + b applied in-place.
Definition Transform.cpp:11
void reverse(std::span< double > data) noexcept
Reverse temporal order in-place.
Definition Transform.cpp:90
std::vector< size_t > onset_positions(std::span< const double > data, uint32_t window_size, uint32_t hop_size, double threshold)
Sample indices of onsets detected via spectral flux.
Definition Analysis.cpp:670
void normalize(std::span< double > data, double target_min, double target_max) noexcept
Normalize to [target_min, target_max] in-place Single-pass min/max reduction followed by a single tra...
Definition Transform.cpp:61
std::vector< double > generate_window(uint32_t size, WindowType window_type)
Generate window coefficients using C++20 ranges.
@ SPECTRAL
Spectral energy (FFT-based)
@ DYNAMIC_RANGE
Dynamic range (dB)
@ ZERO_CROSSING
Zero-crossing rate.
@ HARMONIC
Harmonic energy (low-frequency content)
@ POWER
Power (sum of squares)
@ SILENCE_DATA
Extract actual silent regions.
@ ZERO_CROSSING_DATA
Extract actual data at zero crossing points.
@ OVERLAPPING_WINDOWS
Extract overlapping windowed data.
std::vector< std::vector< double > > to_double_vectors(const std::vector< Kakshya::DataVariant > &channels)
Convert multi-channel data to vector of double vectors.
Definition Yantra.cpp:1043
std::vector< size_t > zero_crossings(const std::vector< double > &data, double threshold)
Detect zero crossings in single-channel signal.
Definition Yantra.cpp:333
Kakshya::DataVariant to_data_variant(const std::vector< double > &data)
Convert vector<double> to DataVariant.
Definition Yantra.cpp:1038
std::vector< double > zero_crossing_rate_per_channel(const std::vector< Kakshya::DataVariant > &channels, size_t window_size)
Calculate zero crossing rate per channel for multi-channel data.
Definition Yantra.cpp:428
std::vector< Kakshya::DataVariant > with_gain_channels(const std::vector< Kakshya::DataVariant > &channels, double gain_factor)
Apply gain to multi-channel data (non-destructive)
Definition Yantra.cpp:557
std::vector< double > dynamic_range_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Calculate dynamic range per channel for multi-channel data.
Definition Yantra.cpp:231
double std_dev_combined(const std::vector< Kakshya::DataVariant > &channels)
Calculate standard deviation across all channels (mix then analyze)
Definition Yantra.cpp:194
std::vector< std::vector< double > > magnitude_spectrum_per_channel(const std::vector< Kakshya::DataVariant > &channels, size_t window_size)
Compute magnitude spectrum per channel for multi-channel data.
Definition Yantra.cpp:674
std::vector< double > estimate_pitch_per_channel(const std::vector< Kakshya::DataVariant > &channels, double sample_rate, double min_freq, double max_freq)
Estimate fundamental frequency per channel for multi-channel data.
Definition Yantra.cpp:751
double estimate_pitch(const std::vector< double > &data, double sample_rate, double min_freq, double max_freq)
Estimate fundamental frequency using autocorrelation for single-channel data.
Definition Yantra.cpp:729
std::vector< Kakshya::DataVariant > reversed_channels(const std::vector< Kakshya::DataVariant > &channels)
Reverse time order of multi-channel data (non-destructive)
Definition Yantra.cpp:644
std::vector< double > peak_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Find peak amplitude per channel for multi-channel data.
Definition Yantra.cpp:304
double zero_crossing_rate(const std::vector< double > &data, size_t window_size)
Calculate zero crossing rate for single-channel data.
Definition Yantra.cpp:408
void reverse(std::vector< double > &data)
Reverse time order of single-channel data (in-place)
Definition Yantra.cpp:614
std::vector< double > mean_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Calculate mean per channel for multi-channel data.
Definition Yantra.cpp:75
void apply_gain_channels(std::vector< Kakshya::DataVariant > &channels, double gain_factor)
Apply gain to multi-channel data (in-place)
Definition Yantra.cpp:527
void normalize_together(std::vector< Kakshya::DataVariant > &channels, double target_peak)
Normalize multi-channel data relative to global peak (in-place)
Definition Yantra.cpp:581
std::vector< double > to_double_vector(const Kakshya::DataVariant &data)
Convert DataVariant to vector<double> if possible.
Definition Yantra.cpp:1032
std::vector< std::vector< std::vector< double > > > windowed_segments_per_channel(const std::vector< Kakshya::DataVariant > &channels, size_t window_size, size_t hop_size)
Split multi-channel data into overlapping windows per channel.
Definition Yantra.cpp:893
std::vector< double > with_gain(const std::vector< double > &data, double gain_factor)
Apply gain to single-channel data (non-destructive)
Definition Yantra.cpp:543
double dynamic_range(const std::vector< double > &data)
Calculate dynamic range (max/min ratio in dB) of single-channel data.
Definition Yantra.cpp:209
std::vector< std::pair< size_t, size_t > > detect_silence(const std::vector< double > &data, double threshold, size_t min_silence_duration)
Detect silence regions in single-channel data.
Definition Yantra.cpp:902
double rms(const std::vector< double > &data)
Calculate RMS (Root Mean Square) energy of single-channel data.
Definition Yantra.cpp:102
void normalize_channels(std::vector< Kakshya::DataVariant > &channels, double target_peak)
Normalize each channel independently to specified peak level (in-place)
Definition Yantra.cpp:575
void reverse_channels(std::vector< Kakshya::DataVariant > &channels)
Reverse time order of multi-channel data (in-place)
Definition Yantra.cpp:624
double peak_channel(const std::vector< Kakshya::DataVariant > &channels, size_t channel_index)
Find peak amplitude in specific channel.
Definition Yantra.cpp:320
std::vector< double > extract_zero_crossing_regions(const std::vector< double > &data, double threshold, size_t region_size)
Extract zero crossing regions from single-channel data.
Definition Yantra.cpp:798
std::vector< double > std_dev_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Calculate standard deviation per channel for multi-channel data.
Definition Yantra.cpp:176
std::vector< double > reversed(const std::vector< double > &data)
Reverse time order of single-channel data (non-destructive)
Definition Yantra.cpp:630
std::vector< std::vector< double > > power_spectrum_per_channel(const std::vector< Kakshya::DataVariant > &channels, size_t window_size)
Compute power spectrum per channel for multi-channel data.
Definition Yantra.cpp:708
std::vector< Kakshya::DataVariant > to_data_variants(const std::vector< std::vector< double > > &channel_data)
Convert vector of double vectors to multi-channel DataVariant format.
Definition Yantra.cpp:1053
std::vector< double > extract_silent_data(const std::vector< double > &data, double threshold, size_t min_silence_duration)
Extract silent regions from single-channel data.
Definition Yantra.cpp:772
double dynamic_range_global(const std::vector< Kakshya::DataVariant > &channels)
Calculate dynamic range across all channels (global min/max)
Definition Yantra.cpp:249
std::vector< double > magnitude_spectrum(const std::vector< double > &data, size_t window_size)
Compute magnitude spectrum for single-channel data.
Definition Yantra.cpp:656
void apply_window_channels(std::vector< Kakshya::DataVariant > &channels, const std::string &window_type)
Apply window function to multi-channel data (in-place)
Definition Yantra.cpp:854
std::vector< std::vector< double > > detect_onsets_per_channel(const std::vector< Kakshya::DataVariant > &channels, double sample_rate, double threshold)
Detect onset times per channel for multi-channel signal.
Definition Yantra.cpp:503
void normalize(std::vector< double > &data, double target_peak)
Normalize single-channel data to specified peak level (in-place)
Definition Yantra.cpp:565
void apply_window(std::vector< double > &data, const std::string &window_type)
Apply window function to single-channel data (in-place)
Definition Yantra.cpp:826
double rms_combined(const std::vector< Kakshya::DataVariant > &channels)
Calculate RMS energy across all channels (mix then analyze)
Definition Yantra.cpp:142
std::vector< std::vector< double > > windowed_segments(const std::vector< double > &data, size_t window_size, size_t hop_size)
Split single-channel data into overlapping windows.
Definition Yantra.cpp:860
std::vector< double > mix_with_gains(const std::vector< std::vector< double > > &streams, const std::vector< double > &gains)
Mix multiple data streams with specified gains.
Definition Yantra.cpp:988
std::vector< Kakshya::DataVariant > normalized_channels(const std::vector< Kakshya::DataVariant > &channels, double target_peak)
Normalize each channel independently (non-destructive)
Definition Yantra.cpp:602
std::vector< double > spectral_centroid_per_channel(const std::vector< Kakshya::DataVariant > &channels, double sample_rate)
Find spectral centroid per channel for multi-channel data.
Definition Yantra.cpp:461
double spectral_centroid(const std::vector< double > &data, double sample_rate)
Find spectral centroid (brightness measure) for single-channel data.
Definition Yantra.cpp:443
void initialize_yantra()
Initialize Yantra subsystem with default configuration.
Definition Yantra.cpp:1066
double std_dev(const std::vector< double > &data)
Calculate standard deviation of single-channel data.
Definition Yantra.cpp:156
std::vector< double > normalized(const std::vector< double > &data, double target_peak)
Normalize single-channel data (non-destructive)
Definition Yantra.cpp:588
double mean(const std::vector< double > &data)
Calculate mean of single-channel data.
Definition Yantra.cpp:55
double mean_combined(const std::vector< Kakshya::DataVariant > &channels)
Calculate mean across all channels (mix then analyze)
Definition Yantra.cpp:91
std::vector< double > detect_onsets(const std::vector< double > &data, double sample_rate, double threshold)
Detect onset times in single-channel signal.
Definition Yantra.cpp:476
std::vector< std::vector< size_t > > zero_crossings_per_channel(const std::vector< Kakshya::DataVariant > &channels, double threshold)
Detect zero crossings per channel for multi-channel signal.
Definition Yantra.cpp:380
double peak(const std::vector< double > &data)
Find peak amplitude in single-channel data.
Definition Yantra.cpp:268
void apply_gain(std::vector< double > &data, double gain_factor)
Apply gain to single-channel data (in-place)
Definition Yantra.cpp:517
void apply_gain_per_channel(std::vector< Kakshya::DataVariant > &channels, const std::vector< double > &gain_factors)
Apply different gain to each channel (in-place)
Definition Yantra.cpp:533
std::vector< double > mix(const std::vector< std::vector< double > > &streams)
Mix multiple data streams with equal weighting.
Definition Yantra.cpp:945
std::vector< double > rms_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Calculate RMS energy per channel for multi-channel data.
Definition Yantra.cpp:124
std::vector< std::vector< std::pair< size_t, size_t > > > detect_silence_per_channel(const std::vector< Kakshya::DataVariant > &channels, double threshold, size_t min_silence_duration)
Detect silence regions per channel for multi-channel data.
Definition Yantra.cpp:932
std::vector< double > power_spectrum(const std::vector< double > &data, size_t window_size)
Compute power spectrum for single-channel data.
Definition Yantra.cpp:690
Main namespace for the Maya Flux audio engine.
Definition Runtime.cpp:12
T data
The actual computation data.
Definition DataIO.hpp:25
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:24