14static bool is_same_size(
const std::vector<std::span<double>>& data)
19 const auto expected_size = data.front().size();
20 return std::ranges::all_of(data,
21 [&expected_size](
const auto& v) {
return v.size() == expected_size; });
24static std::vector<double>
concat_vectors(
const std::vector<std::span<double>>& data)
26 std::vector<double> result;
27 result.reserve(std::accumulate(
28 data.begin(), data.end(),
size_t(0),
29 [](
size_t sum,
const auto& span) { return sum + span.size(); }));
31 for (
const auto& span : data) {
32 result.insert(result.end(), span.begin(), span.end());
41double mean(
const std::vector<double>& data)
43 auto analyzer = std::make_shared<Yantra::StatisticalAnalyzer<>>();
46 return result.channel_statistics[0].mean_stat;
51 auto analyzer = std::make_shared<Yantra::StatisticalAnalyzer<>>();
53 auto result = analyzer->analyze_statistics({ data });
54 return result.channel_statistics[0].mean_stat;
59 auto analyzer = std::make_shared<Yantra::StatisticalAnalyzer<>>();
61 auto result = analyzer->analyze_statistics({ data });
63 std::vector<double> means;
64 means.reserve(result.channel_statistics.size());
66 for (
const auto& stats : result.channel_statistics) {
67 means.push_back(stats.mean_stat);
77 return std::accumulate(result.begin(), result.end(), 0.0) / result.size();
84double rms(
const std::vector<double>& data)
86 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
89 return result.channel_statistics[0].statistical_values.empty() ? 0.0 : result.channel_statistics[0].statistical_values[0];
94 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
96 auto result = analyzer->analyze_statistics({ data });
97 return result.channel_statistics[0].statistical_values.empty() ? 0.0 : result.channel_statistics[0].statistical_values[0];
102 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
104 auto result = analyzer->analyze_statistics(channels);
105 std::vector<double> rms_values;
106 for (
const auto& stats : result.channel_statistics) {
107 rms_values.push_back(stats.statistical_values.empty() ? 0.0 : stats.statistical_values[0]);
117 double sum_squares = 0.0;
118 for (
double rms_val : result) {
119 sum_squares += rms_val * rms_val;
121 return std::sqrt(sum_squares / result.size());
128double std_dev(
const std::vector<double>& data)
130 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
133 return result.channel_statistics[0].stat_std_dev;
138 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
140 auto result = analyzer->analyze_statistics({ data });
141 return result.channel_statistics[0].stat_std_dev;
146 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
148 auto result = analyzer->analyze_statistics(channels);
149 std::vector<double> std_devs;
150 for (
const auto& stats : result.channel_statistics) {
151 std_devs.push_back(stats.stat_std_dev);
161 return std::accumulate(result.begin(), result.end(), 0.0) / result.size();
170 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
173 return result.channels.empty() || result.channels[0].energy_values.empty() ? 0.0 : result.channels[0].energy_values[0];
178 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
180 auto result = analyzer->analyze_energy({ data });
181 return result.channels.empty() || result.channels[0].energy_values.empty() ? 0.0 : result.channels[0].energy_values[0];
186 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
188 auto result = analyzer->analyze_energy(channels);
189 std::vector<double> ranges;
190 for (
const auto& channel : result.channels) {
191 ranges.push_back(channel.energy_values.empty() ? 0.0 : channel.energy_values[0]);
199 double global_min = std::numeric_limits<double>::max();
200 double global_max = std::numeric_limits<double>::lowest();
202 for (
const auto& span : data) {
203 auto [min_it, max_it] = std::ranges::minmax_element(span);
204 if (min_it != span.end()) {
205 global_min = std::min(global_min, *min_it);
206 global_max = std::max(global_max, *max_it);
210 if (global_min <= 0.0 || global_max <= 0.0) {
213 return 20.0 * std::log10(global_max / std::abs(global_min));
216double peak(
const std::vector<double>& data)
218 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
221 return result.channels.empty() ? 0.0 : result.channels[0].max_energy;
226 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
228 auto result = analyzer->analyze_energy({ data });
229 return result.channels.empty() ? 0.0 : result.channels[0].max_energy;
232double peak(
const std::vector<Kakshya::DataVariant>& channels)
234 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
236 auto result = analyzer->analyze_energy(channels);
237 double global_peak = 0.0;
238 for (
const auto& channel : result.channels) {
239 global_peak = std::max(global_peak, channel.max_energy);
246 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
248 auto result = analyzer->analyze_energy(channels);
249 std::vector<double> peaks;
250 for (
const auto& channel : result.channels) {
251 peaks.push_back(channel.max_energy);
256double peak_channel(
const std::vector<Kakshya::DataVariant>& channels,
size_t channel_index)
258 if (channel_index >= channels.size()) {
259 throw std::out_of_range(
"Channel index out of range");
261 return peak(channels[channel_index]);
268std::vector<size_t>
zero_crossings(
const std::vector<double>& data,
double threshold)
270 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
273 auto result = analyzer->analyze_energy({ { data } });
275 if (result.channels.empty()) {
279 const auto& positions = result.channels[0].event_positions;
281 if (threshold <= 0.0) {
285 std::vector<size_t> filtered;
286 for (
size_t pos : positions) {
287 if (pos < data.size() && std::abs(data[pos]) >= threshold) {
288 filtered.push_back(pos);
296 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
299 auto result = analyzer->analyze_energy({ data });
301 if (result.channels.empty()) {
305 const auto& positions = result.channels[0].event_positions;
307 if (threshold <= 0.0) {
311 auto double_data = std::get<std::vector<double>>(data);
312 std::vector<size_t> filtered;
313 for (
size_t pos : positions) {
314 if (pos < double_data.size() && std::abs(double_data[pos]) >= threshold) {
315 filtered.push_back(pos);
323 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
325 auto result = analyzer->analyze_energy(channels);
327 std::vector<std::vector<size_t>> all_crossings;
328 all_crossings.reserve(result.channels.size());
330 for (
size_t ch = 0; ch < result.channels.size(); ++ch) {
331 const auto& positions = result.channels[ch].event_positions;
333 if (threshold <= 0.0) {
334 all_crossings.push_back(positions);
338 auto double_data = std::get<std::vector<double>>(channels[ch]);
339 std::vector<size_t> filtered;
340 for (
size_t pos : positions) {
341 if (pos < double_data.size() && std::abs(double_data[pos]) >= threshold) {
342 filtered.push_back(pos);
345 all_crossings.push_back(filtered);
348 return all_crossings;
353 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
355 if (window_size > 0) {
356 analyzer->set_window_parameters(window_size, window_size / 2);
359 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
364 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
366 if (window_size > 0) {
367 analyzer->set_window_parameters(window_size, window_size / 2);
369 auto result = analyzer->analyze_energy({ data });
370 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
375 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
377 if (window_size > 0) {
378 analyzer->set_window_parameters(window_size, window_size / 2);
380 auto result = analyzer->analyze_energy(channels);
382 std::vector<double> rates;
383 for (
const auto& channel : result.channels) {
384 rates.push_back(channel.mean_energy);
391 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
393 analyzer->set_parameter(
"sample_rate", sample_rate);
395 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
400 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
402 analyzer->set_parameter(
"sample_rate", sample_rate);
403 auto result = analyzer->analyze_energy({ data });
404 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
409 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
411 analyzer->set_parameter(
"sample_rate", sample_rate);
412 auto result = analyzer->analyze_energy(channels);
414 std::vector<double> centroids;
415 for (
const auto& channel : result.channels) {
416 centroids.push_back(channel.mean_energy);
421std::vector<double>
detect_onsets(
const std::vector<double>& data,
double sample_rate,
double threshold)
423 std::span<const double> data_span(data.data(), data.size());
431 std::vector<double> onset_times;
432 onset_times.reserve(onset_sample_positions.size());
433 for (
size_t sample_pos : onset_sample_positions) {
434 onset_times.push_back(
static_cast<double>(sample_pos) / sample_rate);
442 auto double_data = std::get<std::vector<double>>(data);
443 std::span<const double> data_span(double_data.data(), double_data.size());
451 std::vector<double> onset_times;
452 onset_times.reserve(onset_sample_positions.size());
453 for (
size_t sample_pos : onset_sample_positions) {
454 onset_times.push_back(
static_cast<double>(sample_pos) / sample_rate);
460std::vector<std::vector<double>>
detect_onsets_per_channel(
const std::vector<Kakshya::DataVariant>& channels,
double sample_rate,
double threshold)
462 std::vector<std::vector<double>> all_onsets;
463 all_onsets.reserve(channels.size());
465 for (
const auto& channel : channels) {
466 auto double_data = std::get<std::vector<double>>(channel);
467 std::span<const double> data_span(double_data.data(), double_data.size());
475 std::vector<double> onset_times;
476 onset_times.reserve(onset_sample_positions.size());
477 for (
size_t sample_pos : onset_sample_positions) {
478 onset_times.push_back(
static_cast<double>(sample_pos) / sample_rate);
481 all_onsets.push_back(onset_times);
491void apply_gain(std::vector<double>& data,
double gain_factor)
494 transformer->set_parameter(
"gain_factor", gain_factor);
497 auto result = transformer->apply_operation(input);
499 data = std::get<std::vector<double>>(result.data[0]);
505 transformer->set_parameter(
"gain_factor", gain_factor);
508 auto result = transformer->apply_operation(input);
510 data = std::get<std::vector<double>>(result.data[0]);
516 transformer->set_parameter(
"gain_factor", gain_factor);
518 auto result = transformer->apply_operation(input);
519 channels = result.
data;
524 if (gain_factors.size() != channels.size()) {
525 throw std::invalid_argument(
"Gain factors size must match channels size");
528 for (
size_t i = 0; i < channels.size(); ++i) {
533std::vector<double>
with_gain(
const std::vector<double>& data,
double gain_factor)
536 transformer->set_parameter(
"gain_factor", gain_factor);
538 auto result = transformer->apply_operation(input);
539 return std::get<std::vector<double>>(result.data[0]);
545 transformer->set_parameter(
"gain_factor", gain_factor);
547 auto result = transformer->apply_operation(input);
548 return result.
data[0];
551std::vector<Kakshya::DataVariant>
with_gain_channels(
const std::vector<Kakshya::DataVariant>& channels,
double gain_factor)
554 transformer->set_parameter(
"gain_factor", gain_factor);
556 auto result = transformer->apply_operation(input);
560void normalize(std::vector<double>& data,
double target_peak)
563 transformer->set_parameter(
"target_peak", target_peak);
565 auto result = transformer->apply_operation(input);
566 data = std::get<std::vector<double>>(result.data[0]);
572 transformer->set_parameter(
"target_peak", target_peak);
574 auto result = transformer->apply_operation(input);
575 data = result.
data[0];
580 for (
auto& channel : channels) {
587 double global_peak =
peak(channels);
589 if (global_peak > 0.0) {
590 double gain_factor = target_peak / global_peak;
595std::vector<double>
normalized(
const std::vector<double>& data,
double target_peak)
598 transformer->set_parameter(
"target_peak", target_peak);
600 auto result = transformer->apply_operation(input);
601 return std::get<std::vector<double>>(result.data[0]);
607 transformer->set_parameter(
"target_peak", target_peak);
609 auto result = transformer->apply_operation(input);
610 return result.
data[0];
613std::vector<Kakshya::DataVariant>
normalized_channels(
const std::vector<Kakshya::DataVariant>& channels,
double target_peak)
615 std::vector<Kakshya::DataVariant> result;
616 result.reserve(channels.size());
617 for (
const auto& channel : channels) {
618 result.push_back(
normalized(channel, target_peak));
631 auto result = transformer->apply_operation(input);
632 data = std::get<std::vector<double>>(result.data[0]);
639 auto result = transformer->apply_operation(input);
640 data = result.
data[0];
647 auto result = transformer->apply_operation(input);
648 channels = result.
data;
651std::vector<double>
reversed(
const std::vector<double>& data)
655 auto result = transformer->apply_operation(input);
656 return std::get<std::vector<double>>(result.data[0]);
663 auto result = transformer->apply_operation(input);
664 return result.
data[0];
667std::vector<Kakshya::DataVariant>
reversed_channels(
const std::vector<Kakshya::DataVariant>& channels)
671 auto result = transformer->apply_operation(input);
681 auto energy_analyzer = std::make_shared<Yantra::EnergyAnalyzer<>>();
683 if (window_size > 0) {
684 energy_analyzer->set_window_parameters(window_size, window_size / 2);
687 return result.channels[0].energy_values;
692 auto energy_analyzer = std::make_shared<Yantra::EnergyAnalyzer<>>();
694 if (window_size > 0) {
695 energy_analyzer->set_window_parameters(window_size, window_size / 2);
697 auto result = energy_analyzer->analyze_energy({ data });
698 return result.channels[0].energy_values;
703 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
705 if (window_size > 0) {
706 energy_analyzer->set_window_parameters(window_size, window_size / 2);
708 auto result = energy_analyzer->analyze_energy(channels);
710 std::vector<std::vector<double>> spectra;
711 for (
const auto& channel : result.channels) {
712 spectra.push_back(channel.energy_values);
717std::vector<double>
power_spectrum(
const std::vector<double>& data,
size_t window_size)
719 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
721 if (window_size > 0) {
722 energy_analyzer->set_window_parameters(window_size, window_size / 2);
725 return result.channels[0].energy_values;
730 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
732 if (window_size > 0) {
733 energy_analyzer->set_window_parameters(window_size, window_size / 2);
735 auto result = energy_analyzer->analyze_energy({ data });
736 return result.channels[0].energy_values;
741 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
743 if (window_size > 0) {
744 energy_analyzer->set_window_parameters(window_size, window_size / 2);
746 auto result = energy_analyzer->analyze_energy(channels);
748 std::vector<std::vector<double>> spectra;
749 for (
const auto& channel : result.channels) {
750 spectra.push_back(channel.energy_values);
759double estimate_pitch(
const std::vector<double>& data,
double sample_rate,
double min_freq,
double max_freq)
761 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
763 energy_analyzer->set_parameter(
"sample_rate", sample_rate);
764 energy_analyzer->set_parameter(
"min_freq", min_freq);
765 energy_analyzer->set_parameter(
"max_freq", max_freq);
768 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy * sample_rate / 1000.0;
773 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
775 energy_analyzer->set_parameter(
"sample_rate", sample_rate);
776 energy_analyzer->set_parameter(
"min_freq", min_freq);
777 energy_analyzer->set_parameter(
"max_freq", max_freq);
778 auto result = energy_analyzer->analyze_energy({ data });
780 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy * sample_rate / 1000.0;
783std::vector<double>
estimate_pitch_per_channel(
const std::vector<Kakshya::DataVariant>& channels,
double sample_rate,
double min_freq,
double max_freq)
785 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
787 energy_analyzer->set_parameter(
"sample_rate", sample_rate);
788 energy_analyzer->set_parameter(
"min_freq", min_freq);
789 energy_analyzer->set_parameter(
"max_freq", max_freq);
790 auto result = energy_analyzer->analyze_energy(channels);
792 std::vector<double> pitches;
793 for (
const auto& channel : result.channels) {
794 double pitch = channel.mean_energy * sample_rate / 1000.0;
795 pitches.push_back(pitch);
806 size_t min_silence_duration)
808 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
810 extractor->set_parameter(
"silence_threshold", threshold);
811 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
814 auto result = extractor->apply_operation(input);
816 return result.
data[0];
821 size_t min_silence_duration)
823 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
825 extractor->set_parameter(
"silence_threshold", threshold);
826 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
829 auto result = extractor->apply_operation(input);
831 return result.
data[0];
838 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
840 extractor->set_parameter(
"threshold", threshold);
841 extractor->set_parameter(
"min_distance", 1.0);
842 extractor->set_parameter(
"region_size",
static_cast<uint32_t
>(region_size));
845 auto result = extractor->apply_operation(input);
847 return result.
data[0];
854 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
856 extractor->set_parameter(
"threshold", threshold);
857 extractor->set_parameter(
"min_distance", 1.0);
858 extractor->set_parameter(
"region_size",
static_cast<uint32_t
>(region_size));
861 auto result = extractor->apply_operation(input);
863 return result.
data[0];
866void apply_window(std::vector<double>& data,
const std::string& window_type)
870 if (window_type ==
"hann" || window_type ==
"hanning") {
872 }
else if (window_type ==
"hamming") {
874 }
else if (window_type ==
"blackman") {
876 }
else if (window_type ==
"rectangular" || window_type ==
"rect") {
884 for (
size_t i = 0; i < data.size() && i < window.size(); ++i) {
885 data[i] *= window[i];
891 auto double_data = std::get<std::vector<double>>(data);
898 for (
auto& channel : channels) {
907 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>(
static_cast<uint32_t
>(window_size),
static_cast<uint32_t
>(hop_size),
909 extractor->set_parameter(
"overlap",
double(hop_size) / window_size);
912 auto result = extractor->apply_operation(input);
914 auto extracted_data = result.
data[0];
916 std::vector<std::vector<double>> segments;
917 for (
size_t i = 0; i < extracted_data.size(); i += window_size) {
918 size_t end_idx = std::min(i + window_size, extracted_data.size());
919 segments.emplace_back(extracted_data.begin() + i, extracted_data.begin() + end_idx);
929 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>(
static_cast<uint32_t
>(window_size),
static_cast<uint32_t
>(hop_size),
931 extractor->set_parameter(
"overlap",
double(hop_size) / window_size);
934 auto result = extractor->apply_operation(input);
936 auto extracted_data = result.
data[0];
938 std::vector<std::vector<double>> segments;
939 for (
size_t i = 0; i < extracted_data.size(); i += window_size) {
940 size_t end_idx = std::min(i + window_size, extracted_data.size());
941 segments.emplace_back(extracted_data.begin() + i, extracted_data.begin() + end_idx);
951 std::vector<std::vector<std::vector<double>>> all_segments;
952 all_segments.reserve(channels.size());
954 for (
const auto& channel : channels) {
961std::vector<std::pair<size_t, size_t>>
detect_silence(
const std::vector<double>& data,
963 size_t min_silence_duration)
965 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
967 extractor->set_parameter(
"silence_threshold", threshold);
968 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
971 auto result = extractor->apply_operation(input);
973 std::vector<std::pair<size_t, size_t>> silence_regions;
974 auto window_positions_opt = result.template get_metadata<std::vector<std::pair<size_t, size_t>>>(
"window_positions");
975 if (window_positions_opt.has_value()) {
976 silence_regions = window_positions_opt.value();
979 return silence_regions;
984 size_t min_silence_duration)
986 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
988 extractor->set_parameter(
"silence_threshold", threshold);
989 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
992 auto result = extractor->apply_operation(input);
994 std::vector<std::pair<size_t, size_t>> silence_regions;
995 auto window_positions_opt = result.template get_metadata<std::vector<std::pair<size_t, size_t>>>(
"window_positions");
996 if (window_positions_opt.has_value()) {
997 silence_regions = window_positions_opt.value();
1000 return silence_regions;
1005 size_t min_silence_duration)
1007 std::vector<std::vector<std::pair<size_t, size_t>>> all_silence_regions;
1008 all_silence_regions.reserve(channels.size());
1010 for (
const auto& channel : channels) {
1011 all_silence_regions.push_back(
detect_silence(channel, threshold, min_silence_duration));
1014 return all_silence_regions;
1021std::vector<double>
mix(
const std::vector<std::vector<double>>& streams)
1023 if (streams.empty())
1026 size_t max_length = 0;
1027 for (
const auto& stream : streams) {
1028 max_length = std::max(max_length, stream.size());
1031 std::vector<double> result(max_length, 0.0);
1033 for (
const auto& stream : streams) {
1034 for (
size_t i = 0; i < stream.size(); ++i) {
1035 result[i] += stream[i];
1039 double gain = 1.0 /
static_cast<double>(streams.size());
1045std::vector<double>
mix(
const std::vector<Kakshya::DataVariant>& streams)
1047 if (streams.empty())
1053 size_t channel_length = numeric_data[0].size();
1054 std::vector<double> result(channel_length, 0.0);
1056 for (
const auto& span : numeric_data) {
1057 for (
size_t i = 0; i < span.size(); ++i) {
1058 result[i] += span[i];
1062 double gain = 1.0 /
static_cast<double>(numeric_data.size());
1067 std::vector<std::vector<double>> double_streams;
1068 double_streams.reserve(streams.size());
1070 for (
const auto& span : numeric_data) {
1071 double_streams.emplace_back(span.begin(), span.end());
1074 return mix(double_streams);
1079 const std::vector<double>& gains)
1081 if (streams.empty() || gains.size() != streams.size()) {
1082 throw std::invalid_argument(
"Streams and gains vectors must have the same size");
1085 size_t max_length = 0;
1086 for (
const auto& stream : streams) {
1087 max_length = std::max(max_length, stream.size());
1090 std::vector<double> result(max_length, 0.0);
1092 for (
size_t s = 0; s < streams.size(); ++s) {
1093 const auto& stream = streams[s];
1094 double gain = gains[s];
1096 for (
size_t i = 0; i < stream.size(); ++i) {
1097 result[i] += stream[i] * gain;
1105 const std::vector<double>& gains)
1107 if (streams.empty() || gains.size() != streams.size()) {
1108 throw std::invalid_argument(
"Streams and gains vectors must have the same size");
1114 size_t channel_length = numeric_data[0].size();
1115 std::vector<double> result(channel_length, 0.0);
1117 for (
size_t s = 0; s < numeric_data.size(); ++s) {
1118 const auto& span = numeric_data[s];
1119 double gain = gains[s];
1121 for (
size_t i = 0; i < span.size(); ++i) {
1122 result[i] += span[i] * gain;
1129 std::vector<std::vector<double>> double_streams;
1130 double_streams.reserve(streams.size());
1132 for (
const auto& span : numeric_data) {
1133 double_streams.emplace_back(span.begin(), span.end());
1142 return span.empty() ? std::vector<double> {} : std::vector<double>(span.begin(), span.end());
1150std::vector<std::vector<double>>
to_double_vectors(
const std::vector<Kakshya::DataVariant>& channels)
1153 std::vector<std::vector<double>> result;
1154 result.reserve(spans.size());
1156 for (
const auto& span : spans) {
1157 result.emplace_back(span.begin(), span.end());
1163std::vector<Kakshya::DataVariant>
to_data_variants(
const std::vector<std::vector<double>>& channel_data)
1165 std::vector<Kakshya::DataVariant> result;
1166 result.reserve(channel_data.size());
1168 for (
const auto& channel : channel_data) {
1169 result.emplace_back(channel);
Discrete sequence analysis primitives for MayaFlux::Kinesis.
Span-based energy analysis for digital signals in Maya Flux.
Data analysis and transformation convenience API.
static std::span< double > extract_numeric_data(const T &compute_data)
extract numeric data from single-variant types
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.
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.
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)
@ GAIN
Linear gain/attenuation.
@ NORMALIZE
Normalization.
@ SILENCE_DATA
Extract actual silent regions.
@ ZERO_CROSSING_DATA
Extract actual data at zero crossing points.
@ OVERLAPPING_WINDOWS
Extract overlapping windowed data.
@ STD_DEV
Standard deviation.
@ TIME_REVERSE
Reverse temporal order.
std::vector< std::vector< double > > to_double_vectors(const std::vector< Kakshya::DataVariant > &channels)
Convert multi-channel data to vector of double vectors.
std::vector< size_t > zero_crossings(const std::vector< double > &data, double threshold)
Detect zero crossings in single-channel signal.
Kakshya::DataVariant to_data_variant(const std::vector< double > &data)
Convert vector<double> to DataVariant.
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.
std::vector< Kakshya::DataVariant > with_gain_channels(const std::vector< Kakshya::DataVariant > &channels, double gain_factor)
Apply gain to multi-channel data (non-destructive)
std::vector< double > dynamic_range_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Calculate dynamic range per channel for multi-channel data.
double std_dev_combined(const std::vector< Kakshya::DataVariant > &channels)
Calculate standard deviation across all channels (mix then analyze)
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.
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.
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.
std::vector< Kakshya::DataVariant > reversed_channels(const std::vector< Kakshya::DataVariant > &channels)
Reverse time order of multi-channel data (non-destructive)
std::vector< double > peak_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Find peak amplitude per channel for multi-channel data.
double zero_crossing_rate(const std::vector< double > &data, size_t window_size)
Calculate zero crossing rate for single-channel data.
void reverse(std::vector< double > &data)
Reverse time order of single-channel data (in-place)
std::vector< double > mean_per_channel(const std::vector< Kakshya::DataVariant > &data)
Calculate mean per channel for multi-channel data.
void apply_gain_channels(std::vector< Kakshya::DataVariant > &channels, double gain_factor)
Apply gain to multi-channel data (in-place)
void normalize_together(std::vector< Kakshya::DataVariant > &channels, double target_peak)
Normalize multi-channel data relative to global peak (in-place)
std::vector< double > to_double_vector(const Kakshya::DataVariant &data)
Convert DataVariant to vector<double> if possible.
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.
std::vector< double > with_gain(const std::vector< double > &data, double gain_factor)
Apply gain to single-channel data (non-destructive)
double dynamic_range(const std::vector< double > &data)
Calculate dynamic range (max/min ratio in dB) of single-channel data.
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.
double rms(const std::vector< double > &data)
Calculate RMS (Root Mean Square) energy of single-channel data.
void normalize_channels(std::vector< Kakshya::DataVariant > &channels, double target_peak)
Normalize each channel independently to specified peak level (in-place)
void reverse_channels(std::vector< Kakshya::DataVariant > &channels)
Reverse time order of multi-channel data (in-place)
double peak_channel(const std::vector< Kakshya::DataVariant > &channels, size_t channel_index)
Find peak amplitude in specific channel.
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.
std::vector< double > std_dev_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Calculate standard deviation per channel for multi-channel data.
std::vector< double > reversed(const std::vector< double > &data)
Reverse time order of single-channel data (non-destructive)
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.
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.
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.
double dynamic_range_global(const std::vector< Kakshya::DataVariant > &channels)
Calculate dynamic range across all channels (global min/max)
static bool is_same_size(const std::vector< std::span< double > > &data)
std::vector< double > magnitude_spectrum(const std::vector< double > &data, size_t window_size)
Compute magnitude spectrum for single-channel data.
void apply_window_channels(std::vector< Kakshya::DataVariant > &channels, const std::string &window_type)
Apply window function to multi-channel data (in-place)
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.
void normalize(std::vector< double > &data, double target_peak)
Normalize single-channel data to specified peak level (in-place)
void apply_window(std::vector< double > &data, const std::string &window_type)
Apply window function to single-channel data (in-place)
double rms_combined(const std::vector< Kakshya::DataVariant > &channels)
Calculate RMS energy across all channels (mix then analyze)
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.
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.
std::vector< Kakshya::DataVariant > normalized_channels(const std::vector< Kakshya::DataVariant > &channels, double target_peak)
Normalize each channel independently (non-destructive)
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.
static std::vector< double > concat_vectors(const std::vector< std::span< double > > &data)
double spectral_centroid(const std::vector< double > &data, double sample_rate)
Find spectral centroid (brightness measure) for single-channel data.
void initialize_yantra()
Initialize Yantra subsystem with default configuration.
double std_dev(const std::vector< double > &data)
Calculate standard deviation of single-channel data.
std::vector< double > normalized(const std::vector< double > &data, double target_peak)
Normalize single-channel data (non-destructive)
double mean(const std::vector< double > &data)
Calculate mean of single-channel data.
double mean_combined(const std::vector< Kakshya::DataVariant > &channels)
Calculate mean across all channels (mix then analyze)
std::vector< double > detect_onsets(const std::vector< double > &data, double sample_rate, double threshold)
Detect onset times in single-channel signal.
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.
double peak(const std::vector< double > &data)
Find peak amplitude in single-channel data.
void apply_gain(std::vector< double > &data, double gain_factor)
Apply gain to single-channel data (in-place)
void apply_gain_per_channel(std::vector< Kakshya::DataVariant > &channels, const std::vector< double > &gain_factors)
Apply different gain to each channel (in-place)
std::vector< double > mix(const std::vector< std::vector< double > > &streams)
Mix multiple data streams with equal weighting.
std::vector< double > rms_per_channel(const std::vector< Kakshya::DataVariant > &channels)
Calculate RMS energy per channel for multi-channel data.
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.
std::vector< double > power_spectrum(const std::vector< double > &data, size_t window_size)
Compute power spectrum for single-channel data.
Main namespace for the Maya Flux audio engine.
T data
The actual computation data.
Input/Output container for computation pipeline data flow with structure preservation.