12static bool is_same_size(
const std::vector<std::span<double>>& data)
17 const auto expected_size = data.front().size();
18 return std::ranges::all_of(data,
19 [&expected_size](
const auto& v) {
return v.size() == expected_size; });
22static std::vector<double>
concat_vectors(
const std::vector<std::span<double>>& data)
24 std::vector<double> result;
25 result.reserve(std::accumulate(
26 data.begin(), data.end(),
size_t(0),
27 [](
size_t sum,
const auto& span) { return sum + span.size(); }));
29 for (
const auto& span : data) {
30 result.insert(result.end(), span.begin(), span.end());
39double mean(
const std::vector<double>& data)
41 auto analyzer = std::make_shared<Yantra::StatisticalAnalyzer<>>();
44 return result.channel_statistics[0].mean_stat;
49 auto analyzer = std::make_shared<Yantra::StatisticalAnalyzer<>>();
51 auto result = analyzer->analyze_statistics({ data });
52 return result.channel_statistics[0].mean_stat;
57 auto analyzer = std::make_shared<Yantra::StatisticalAnalyzer<>>();
59 auto result = analyzer->analyze_statistics({ data });
61 std::vector<double> means;
62 means.reserve(result.channel_statistics.size());
64 for (
const auto& stats : result.channel_statistics) {
65 means.push_back(stats.mean_stat);
75 return std::accumulate(result.begin(), result.end(), 0.0) / result.size();
82double rms(
const std::vector<double>& data)
84 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
87 return result.channel_statistics[0].statistical_values.empty() ? 0.0 : result.channel_statistics[0].statistical_values[0];
92 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
94 auto result = analyzer->analyze_statistics({ data });
95 return result.channel_statistics[0].statistical_values.empty() ? 0.0 : result.channel_statistics[0].statistical_values[0];
98std::vector<double>
rms_per_channel(
const std::vector<Kakshya::DataVariant>& channels)
100 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
102 auto result = analyzer->analyze_statistics(channels);
103 std::vector<double> rms_values;
104 for (
const auto& stats : result.channel_statistics) {
105 rms_values.push_back(stats.statistical_values.empty() ? 0.0 : stats.statistical_values[0]);
115 double sum_squares = 0.0;
116 for (
double rms_val : result) {
117 sum_squares += rms_val * rms_val;
119 return std::sqrt(sum_squares / result.size());
126double std_dev(
const std::vector<double>& data)
128 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
131 return result.channel_statistics[0].stat_std_dev;
136 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
138 auto result = analyzer->analyze_statistics({ data });
139 return result.channel_statistics[0].stat_std_dev;
144 auto analyzer = std::make_shared<Yantra::StandardStatisticalAnalyzer>();
146 auto result = analyzer->analyze_statistics(channels);
147 std::vector<double> std_devs;
148 for (
const auto& stats : result.channel_statistics) {
149 std_devs.push_back(stats.stat_std_dev);
159 return std::accumulate(result.begin(), result.end(), 0.0) / result.size();
168 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
171 return result.channels.empty() || result.channels[0].energy_values.empty() ? 0.0 : result.channels[0].energy_values[0];
176 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
178 auto result = analyzer->analyze_energy({ data });
179 return result.channels.empty() || result.channels[0].energy_values.empty() ? 0.0 : result.channels[0].energy_values[0];
184 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
186 auto result = analyzer->analyze_energy(channels);
187 std::vector<double> ranges;
188 for (
const auto& channel : result.channels) {
189 ranges.push_back(channel.energy_values.empty() ? 0.0 : channel.energy_values[0]);
197 double global_min = std::numeric_limits<double>::max();
198 double global_max = std::numeric_limits<double>::lowest();
200 for (
const auto& span : data) {
201 auto [min_it, max_it] = std::ranges::minmax_element(span);
202 if (min_it != span.end()) {
203 global_min = std::min(global_min, *min_it);
204 global_max = std::max(global_max, *max_it);
208 if (global_min <= 0.0 || global_max <= 0.0) {
211 return 20.0 * std::log10(global_max / std::abs(global_min));
214double peak(
const std::vector<double>& data)
216 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
219 return result.channels.empty() ? 0.0 : result.channels[0].max_energy;
224 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
226 auto result = analyzer->analyze_energy({ data });
227 return result.channels.empty() ? 0.0 : result.channels[0].max_energy;
230double peak(
const std::vector<Kakshya::DataVariant>& channels)
232 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
234 auto result = analyzer->analyze_energy(channels);
235 double global_peak = 0.0;
236 for (
const auto& channel : result.channels) {
237 global_peak = std::max(global_peak, channel.max_energy);
244 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
246 auto result = analyzer->analyze_energy(channels);
247 std::vector<double> peaks;
248 for (
const auto& channel : result.channels) {
249 peaks.push_back(channel.max_energy);
254double peak_channel(
const std::vector<Kakshya::DataVariant>& channels,
size_t channel_index)
256 if (channel_index >= channels.size()) {
257 throw std::out_of_range(
"Channel index out of range");
259 return peak(channels[channel_index]);
266std::vector<size_t>
zero_crossings(
const std::vector<double>& data,
double threshold)
268 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
271 auto result = analyzer->analyze_energy({ { data } });
273 if (result.channels.empty()) {
277 const auto& positions = result.channels[0].event_positions;
279 if (threshold <= 0.0) {
283 std::vector<size_t> filtered;
284 for (
size_t pos : positions) {
285 if (pos < data.size() && std::abs(data[pos]) >= threshold) {
286 filtered.push_back(pos);
294 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
297 auto result = analyzer->analyze_energy({ data });
299 if (result.channels.empty()) {
303 const auto& positions = result.channels[0].event_positions;
305 if (threshold <= 0.0) {
309 auto double_data = std::get<std::vector<double>>(data);
310 std::vector<size_t> filtered;
311 for (
size_t pos : positions) {
312 if (pos < double_data.size() && std::abs(double_data[pos]) >= threshold) {
313 filtered.push_back(pos);
321 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
323 auto result = analyzer->analyze_energy(channels);
325 std::vector<std::vector<size_t>> all_crossings;
326 all_crossings.reserve(result.channels.size());
328 for (
size_t ch = 0; ch < result.channels.size(); ++ch) {
329 const auto& positions = result.channels[ch].event_positions;
331 if (threshold <= 0.0) {
332 all_crossings.push_back(positions);
336 auto double_data = std::get<std::vector<double>>(channels[ch]);
337 std::vector<size_t> filtered;
338 for (
size_t pos : positions) {
339 if (pos < double_data.size() && std::abs(double_data[pos]) >= threshold) {
340 filtered.push_back(pos);
343 all_crossings.push_back(filtered);
346 return all_crossings;
351 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
353 if (window_size > 0) {
354 analyzer->set_window_parameters(window_size, window_size / 2);
357 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
362 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
364 if (window_size > 0) {
365 analyzer->set_window_parameters(window_size, window_size / 2);
367 auto result = analyzer->analyze_energy({ data });
368 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
373 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
375 if (window_size > 0) {
376 analyzer->set_window_parameters(window_size, window_size / 2);
378 auto result = analyzer->analyze_energy(channels);
380 std::vector<double> rates;
381 for (
const auto& channel : result.channels) {
382 rates.push_back(channel.mean_energy);
389 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
391 analyzer->set_parameter(
"sample_rate", sample_rate);
393 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
398 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
400 analyzer->set_parameter(
"sample_rate", sample_rate);
401 auto result = analyzer->analyze_energy({ data });
402 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy;
407 auto analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
409 analyzer->set_parameter(
"sample_rate", sample_rate);
410 auto result = analyzer->analyze_energy(channels);
412 std::vector<double> centroids;
413 for (
const auto& channel : result.channels) {
414 centroids.push_back(channel.mean_energy);
419std::vector<double>
detect_onsets(
const std::vector<double>& data,
double sample_rate,
double threshold)
421 std::span<const double> data_span(data.data(), data.size());
429 std::vector<double> onset_times;
430 onset_times.reserve(onset_sample_positions.size());
431 for (
size_t sample_pos : onset_sample_positions) {
432 onset_times.push_back(
static_cast<double>(sample_pos) / sample_rate);
440 auto double_data = std::get<std::vector<double>>(data);
441 std::span<const double> data_span(double_data.data(), double_data.size());
449 std::vector<double> onset_times;
450 onset_times.reserve(onset_sample_positions.size());
451 for (
size_t sample_pos : onset_sample_positions) {
452 onset_times.push_back(
static_cast<double>(sample_pos) / sample_rate);
458std::vector<std::vector<double>>
detect_onsets_per_channel(
const std::vector<Kakshya::DataVariant>& channels,
double sample_rate,
double threshold)
460 std::vector<std::vector<double>> all_onsets;
461 all_onsets.reserve(channels.size());
463 for (
const auto& channel : channels) {
464 auto double_data = std::get<std::vector<double>>(channel);
465 std::span<const double> data_span(double_data.data(), double_data.size());
473 std::vector<double> onset_times;
474 onset_times.reserve(onset_sample_positions.size());
475 for (
size_t sample_pos : onset_sample_positions) {
476 onset_times.push_back(
static_cast<double>(sample_pos) / sample_rate);
479 all_onsets.push_back(onset_times);
489void apply_gain(std::vector<double>& data,
double gain_factor)
492 transformer->set_parameter(
"gain_factor", gain_factor);
495 auto result = transformer->apply_operation(input);
497 data = std::get<std::vector<double>>(result.data[0]);
503 transformer->set_parameter(
"gain_factor", gain_factor);
506 auto result = transformer->apply_operation(input);
508 data = std::get<std::vector<double>>(result.data[0]);
514 transformer->set_parameter(
"gain_factor", gain_factor);
516 auto result = transformer->apply_operation(input);
517 channels = result.
data;
522 if (gain_factors.size() != channels.size()) {
523 throw std::invalid_argument(
"Gain factors size must match channels size");
526 for (
size_t i = 0; i < channels.size(); ++i) {
531std::vector<double>
with_gain(
const std::vector<double>& data,
double gain_factor)
534 transformer->set_parameter(
"gain_factor", gain_factor);
536 auto result = transformer->apply_operation(input);
537 return std::get<std::vector<double>>(result.data[0]);
543 transformer->set_parameter(
"gain_factor", gain_factor);
545 auto result = transformer->apply_operation(input);
546 return result.
data[0];
549std::vector<Kakshya::DataVariant>
with_gain_channels(
const std::vector<Kakshya::DataVariant>& channels,
double gain_factor)
552 transformer->set_parameter(
"gain_factor", gain_factor);
554 auto result = transformer->apply_operation(input);
558void normalize(std::vector<double>& data,
double target_peak)
561 transformer->set_parameter(
"target_peak", target_peak);
563 auto result = transformer->apply_operation(input);
564 data = std::get<std::vector<double>>(result.data[0]);
570 transformer->set_parameter(
"target_peak", target_peak);
572 auto result = transformer->apply_operation(input);
573 data = result.
data[0];
578 for (
auto& channel : channels) {
585 double global_peak =
peak(channels);
587 if (global_peak > 0.0) {
588 double gain_factor = target_peak / global_peak;
593std::vector<double>
normalized(
const std::vector<double>& data,
double target_peak)
596 transformer->set_parameter(
"target_peak", target_peak);
598 auto result = transformer->apply_operation(input);
599 return std::get<std::vector<double>>(result.data[0]);
605 transformer->set_parameter(
"target_peak", target_peak);
607 auto result = transformer->apply_operation(input);
608 return result.
data[0];
611std::vector<Kakshya::DataVariant>
normalized_channels(
const std::vector<Kakshya::DataVariant>& channels,
double target_peak)
613 std::vector<Kakshya::DataVariant> result;
614 result.reserve(channels.size());
615 for (
const auto& channel : channels) {
616 result.push_back(
normalized(channel, target_peak));
629 auto result = transformer->apply_operation(input);
630 data = std::get<std::vector<double>>(result.data[0]);
637 auto result = transformer->apply_operation(input);
638 data = result.
data[0];
645 auto result = transformer->apply_operation(input);
646 channels = result.
data;
649std::vector<double>
reversed(
const std::vector<double>& data)
653 auto result = transformer->apply_operation(input);
654 return std::get<std::vector<double>>(result.data[0]);
661 auto result = transformer->apply_operation(input);
662 return result.
data[0];
665std::vector<Kakshya::DataVariant>
reversed_channels(
const std::vector<Kakshya::DataVariant>& channels)
669 auto result = transformer->apply_operation(input);
679 auto energy_analyzer = std::make_shared<Yantra::EnergyAnalyzer<>>();
681 if (window_size > 0) {
682 energy_analyzer->set_window_parameters(window_size, window_size / 2);
685 return result.channels[0].energy_values;
690 auto energy_analyzer = std::make_shared<Yantra::EnergyAnalyzer<>>();
692 if (window_size > 0) {
693 energy_analyzer->set_window_parameters(window_size, window_size / 2);
695 auto result = energy_analyzer->analyze_energy({ data });
696 return result.channels[0].energy_values;
701 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
703 if (window_size > 0) {
704 energy_analyzer->set_window_parameters(window_size, window_size / 2);
706 auto result = energy_analyzer->analyze_energy(channels);
708 std::vector<std::vector<double>> spectra;
709 for (
const auto& channel : result.channels) {
710 spectra.push_back(channel.energy_values);
715std::vector<double>
power_spectrum(
const std::vector<double>& data,
size_t window_size)
717 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
719 if (window_size > 0) {
720 energy_analyzer->set_window_parameters(window_size, window_size / 2);
723 return result.channels[0].energy_values;
728 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
730 if (window_size > 0) {
731 energy_analyzer->set_window_parameters(window_size, window_size / 2);
733 auto result = energy_analyzer->analyze_energy({ data });
734 return result.channels[0].energy_values;
739 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
741 if (window_size > 0) {
742 energy_analyzer->set_window_parameters(window_size, window_size / 2);
744 auto result = energy_analyzer->analyze_energy(channels);
746 std::vector<std::vector<double>> spectra;
747 for (
const auto& channel : result.channels) {
748 spectra.push_back(channel.energy_values);
757double estimate_pitch(
const std::vector<double>& data,
double sample_rate,
double min_freq,
double max_freq)
759 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
761 energy_analyzer->set_parameter(
"sample_rate", sample_rate);
762 energy_analyzer->set_parameter(
"min_freq", min_freq);
763 energy_analyzer->set_parameter(
"max_freq", max_freq);
766 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy * sample_rate / 1000.0;
771 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
773 energy_analyzer->set_parameter(
"sample_rate", sample_rate);
774 energy_analyzer->set_parameter(
"min_freq", min_freq);
775 energy_analyzer->set_parameter(
"max_freq", max_freq);
776 auto result = energy_analyzer->analyze_energy({ data });
778 return result.channels.empty() ? 0.0 : result.channels[0].mean_energy * sample_rate / 1000.0;
781std::vector<double>
estimate_pitch_per_channel(
const std::vector<Kakshya::DataVariant>& channels,
double sample_rate,
double min_freq,
double max_freq)
783 auto energy_analyzer = std::make_shared<Yantra::StandardEnergyAnalyzer>();
785 energy_analyzer->set_parameter(
"sample_rate", sample_rate);
786 energy_analyzer->set_parameter(
"min_freq", min_freq);
787 energy_analyzer->set_parameter(
"max_freq", max_freq);
788 auto result = energy_analyzer->analyze_energy(channels);
790 std::vector<double> pitches;
791 for (
const auto& channel : result.channels) {
792 double pitch = channel.mean_energy * sample_rate / 1000.0;
793 pitches.push_back(pitch);
804 size_t min_silence_duration)
806 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
808 extractor->set_parameter(
"silence_threshold", threshold);
809 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
812 auto result = extractor->apply_operation(input);
814 return result.
data[0];
819 size_t min_silence_duration)
821 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
823 extractor->set_parameter(
"silence_threshold", threshold);
824 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
827 auto result = extractor->apply_operation(input);
829 return result.
data[0];
836 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
838 extractor->set_parameter(
"threshold", threshold);
839 extractor->set_parameter(
"min_distance", 1.0);
840 extractor->set_parameter(
"region_size",
static_cast<uint32_t
>(region_size));
843 auto result = extractor->apply_operation(input);
845 return result.
data[0];
852 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
854 extractor->set_parameter(
"threshold", threshold);
855 extractor->set_parameter(
"min_distance", 1.0);
856 extractor->set_parameter(
"region_size",
static_cast<uint32_t
>(region_size));
859 auto result = extractor->apply_operation(input);
861 return result.
data[0];
864void apply_window(std::vector<double>& data,
const std::string& window_type)
868 if (window_type ==
"hann" || window_type ==
"hanning") {
870 }
else if (window_type ==
"hamming") {
872 }
else if (window_type ==
"blackman") {
874 }
else if (window_type ==
"rectangular" || window_type ==
"rect") {
882 for (
size_t i = 0; i < data.size() && i < window.size(); ++i) {
883 data[i] *= window[i];
889 auto double_data = std::get<std::vector<double>>(data);
896 for (
auto& channel : channels) {
905 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>(window_size, hop_size,
907 extractor->set_parameter(
"overlap",
double(hop_size) / window_size);
910 auto result = extractor->apply_operation(input);
912 auto extracted_data = result.
data[0];
914 std::vector<std::vector<double>> segments;
915 for (
size_t i = 0; i < extracted_data.size(); i += window_size) {
916 size_t end_idx = std::min(i + window_size, extracted_data.size());
917 segments.emplace_back(extracted_data.begin() + i, extracted_data.begin() + end_idx);
927 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>(window_size, hop_size,
929 extractor->set_parameter(
"overlap",
double(hop_size) / window_size);
932 auto result = extractor->apply_operation(input);
934 auto extracted_data = result.
data[0];
936 std::vector<std::vector<double>> segments;
937 for (
size_t i = 0; i < extracted_data.size(); i += window_size) {
938 size_t end_idx = std::min(i + window_size, extracted_data.size());
939 segments.emplace_back(extracted_data.begin() + i, extracted_data.begin() + end_idx);
949 std::vector<std::vector<std::vector<double>>> all_segments;
950 all_segments.reserve(channels.size());
952 for (
const auto& channel : channels) {
959std::vector<std::pair<size_t, size_t>>
detect_silence(
const std::vector<double>& data,
961 size_t min_silence_duration)
963 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
965 extractor->set_parameter(
"silence_threshold", threshold);
966 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
969 auto result = extractor->apply_operation(input);
971 std::vector<std::pair<size_t, size_t>> silence_regions;
972 auto window_positions_opt = result.template get_metadata<std::vector<std::pair<size_t, size_t>>>(
"window_positions");
973 if (window_positions_opt.has_value()) {
974 silence_regions = window_positions_opt.value();
977 return silence_regions;
982 size_t min_silence_duration)
984 auto extractor = std::make_shared<Yantra::FeatureExtractor<>>();
986 extractor->set_parameter(
"silence_threshold", threshold);
987 extractor->set_parameter(
"min_duration",
static_cast<uint32_t
>(min_silence_duration));
990 auto result = extractor->apply_operation(input);
992 std::vector<std::pair<size_t, size_t>> silence_regions;
993 auto window_positions_opt = result.template get_metadata<std::vector<std::pair<size_t, size_t>>>(
"window_positions");
994 if (window_positions_opt.has_value()) {
995 silence_regions = window_positions_opt.value();
998 return silence_regions;
1003 size_t min_silence_duration)
1005 std::vector<std::vector<std::pair<size_t, size_t>>> all_silence_regions;
1006 all_silence_regions.reserve(channels.size());
1008 for (
const auto& channel : channels) {
1009 all_silence_regions.push_back(
detect_silence(channel, threshold, min_silence_duration));
1012 return all_silence_regions;
1019std::vector<double>
mix(
const std::vector<std::vector<double>>& streams)
1021 if (streams.empty())
1024 size_t max_length = 0;
1025 for (
const auto& stream : streams) {
1026 max_length = std::max(max_length, stream.size());
1029 std::vector<double> result(max_length, 0.0);
1031 for (
const auto& stream : streams) {
1032 for (
size_t i = 0; i < stream.size(); ++i) {
1033 result[i] += stream[i];
1037 double gain = 1.0 /
static_cast<double>(streams.size());
1043std::vector<double>
mix(
const std::vector<Kakshya::DataVariant>& streams)
1045 if (streams.empty())
1051 size_t channel_length = numeric_data[0].size();
1052 std::vector<double> result(channel_length, 0.0);
1054 for (
const auto& span : numeric_data) {
1055 for (
size_t i = 0; i < span.size(); ++i) {
1056 result[i] += span[i];
1060 double gain = 1.0 /
static_cast<double>(numeric_data.size());
1065 std::vector<std::vector<double>> double_streams;
1066 double_streams.reserve(streams.size());
1068 for (
const auto& span : numeric_data) {
1069 double_streams.emplace_back(span.begin(), span.end());
1072 return mix(double_streams);
1077 const std::vector<double>& gains)
1079 if (streams.empty() || gains.size() != streams.size()) {
1080 throw std::invalid_argument(
"Streams and gains vectors must have the same size");
1083 size_t max_length = 0;
1084 for (
const auto& stream : streams) {
1085 max_length = std::max(max_length, stream.size());
1088 std::vector<double> result(max_length, 0.0);
1090 for (
size_t s = 0; s < streams.size(); ++s) {
1091 const auto& stream = streams[s];
1092 double gain = gains[s];
1094 for (
size_t i = 0; i < stream.size(); ++i) {
1095 result[i] += stream[i] * gain;
1103 const std::vector<double>& gains)
1105 if (streams.empty() || gains.size() != streams.size()) {
1106 throw std::invalid_argument(
"Streams and gains vectors must have the same size");
1112 size_t channel_length = numeric_data[0].size();
1113 std::vector<double> result(channel_length, 0.0);
1115 for (
size_t s = 0; s < numeric_data.size(); ++s) {
1116 const auto& span = numeric_data[s];
1117 double gain = gains[s];
1119 for (
size_t i = 0; i < span.size(); ++i) {
1120 result[i] += span[i] * gain;
1127 std::vector<std::vector<double>> double_streams;
1128 double_streams.reserve(streams.size());
1130 for (
const auto& span : numeric_data) {
1131 double_streams.emplace_back(span.begin(), span.end());
1140 return span.empty() ? std::vector<double> {} : std::vector<double>(span.begin(), span.end());
1148std::vector<std::vector<double>>
to_double_vectors(
const std::vector<Kakshya::DataVariant>& channels)
1151 std::vector<std::vector<double>> result;
1152 result.reserve(spans.size());
1154 for (
const auto& span : spans) {
1155 result.emplace_back(span.begin(), span.end());
1161std::vector<Kakshya::DataVariant>
to_data_variants(
const std::vector<std::vector<double>>& channel_data)
1163 std::vector<Kakshya::DataVariant> result;
1164 result.reserve(channel_data.size());
1166 for (
const auto& channel : channel_data) {
1167 result.emplace_back(channel);
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< 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)
std::vector< size_t > find_onset_positions(std::span< const double > data, uint32_t window_size, uint32_t hop_size, double threshold)
Find onset positions using spectral flux.
@ 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.