13std::vector<std::pair<size_t, size_t>> merge_overlapping_windows(
14 const std::vector<std::pair<size_t, size_t>>& window_positions)
16 if (window_positions.empty()) {
20 auto sorted_windows = window_positions;
21 std::ranges::sort(sorted_windows, [](
const auto& a,
const auto& b) {
22 return a.first < b.first;
25 std::vector<std::pair<size_t, size_t>> merged;
26 merged.push_back(sorted_windows[0]);
28 for (
size_t i = 1; i < sorted_windows.size(); ++i) {
29 auto& last_merged = merged.back();
30 const auto& current = sorted_windows[i];
32 if (current.first <= last_merged.second) {
33 last_merged.second = std::max(last_merged.second, current.second);
36 merged.push_back(current);
47 const std::vector<std::span<const double>>& data,
48 double energy_threshold,
52 std::vector<std::vector<double>> result;
53 result.reserve(data.size());
55 for (
const auto& channel : data) {
56 if (channel.empty()) {
57 result.emplace_back();
61 uint32_t effective_window_size = std::min(window_size,
static_cast<uint32_t
>(channel.size()));
62 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
63 if (effective_hop_size == 0)
64 effective_hop_size = 1;
67 result.emplace_back();
72 auto energy_analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
73 effective_window_size, effective_hop_size);
74 energy_analyzer->set_parameter(
"method",
"rms");
76 std::vector<Kakshya::DataVariant> data_variant {
Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
77 EnergyAnalysis energy_result = energy_analyzer->analyze_energy(data_variant);
79 if (energy_result.
channels.empty() || energy_result.
channels[0].energy_values.empty() || energy_result.
channels[0].window_positions.empty()) {
80 result.emplace_back();
84 std::vector<std::pair<size_t, size_t>> qualifying_windows;
85 const auto& ch_energy = energy_result.
channels[0].energy_values;
86 const auto& ch_windows = energy_result.
channels[0].window_positions;
87 for (
size_t i = 0; i < ch_energy.size(); ++i) {
88 if (ch_energy[i] > energy_threshold) {
89 auto [start_idx, end_idx] = ch_windows[i];
90 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
91 qualifying_windows.emplace_back(start_idx, end_idx);
96 auto merged_windows = merge_overlapping_windows(qualifying_windows);
98 std::vector<double> extracted_data;
99 for (
const auto& [start_idx, end_idx] : merged_windows) {
100 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
101 std::back_inserter(extracted_data));
104 result.push_back(std::move(extracted_data));
105 }
catch (
const std::exception&) {
106 result.emplace_back();
114 const std::vector<std::span<const double>>& data,
117 uint32_t region_size)
119 std::vector<std::vector<double>> result;
120 result.reserve(data.size());
122 for (
const auto& channel : data) {
123 if (channel.size() < 3) {
124 result.emplace_back();
129 auto analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
131 analyzer->set_parameter(
"method",
"peak");
132 analyzer->set_parameter(
"threshold", threshold);
134 std::vector<Kakshya::DataVariant> data_variant {
137 EnergyAnalysis energy_result = analyzer->analyze_energy(data_variant);
139 if (energy_result.
channels.empty()) {
140 result.emplace_back();
144 const auto& peak_positions = energy_result.
channels[0].event_positions;
146 if (peak_positions.empty()) {
147 result.emplace_back();
151 std::vector<size_t> filtered_positions;
152 size_t last_position = 0;
154 for (
size_t pos : peak_positions) {
155 if (filtered_positions.empty() || (pos - last_position) >=
static_cast<size_t>(min_distance)) {
156 filtered_positions.push_back(pos);
161 std::vector<double> extracted_data;
162 for (
size_t peak_pos : filtered_positions) {
163 const size_t half_region = region_size / 2;
164 const size_t start_idx = (peak_pos >= half_region) ? peak_pos - half_region : 0;
165 const size_t end_idx = std::min(peak_pos + half_region, channel.size());
167 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
168 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
169 std::back_inserter(extracted_data));
173 result.push_back(std::move(extracted_data));
174 }
catch (
const std::exception&) {
175 result.emplace_back();
183 const std::vector<std::span<const double>>& data,
184 double std_dev_threshold,
185 uint32_t window_size,
188 std::vector<std::vector<double>> result;
189 result.reserve(data.size());
191 for (
const auto& channel : data) {
192 if (channel.empty()) {
193 result.emplace_back();
197 uint32_t effective_window_size = std::min(window_size,
static_cast<uint32_t
>(channel.size()));
198 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
199 if (effective_hop_size == 0)
200 effective_hop_size = 1;
203 result.emplace_back();
208 auto stat_analyzer = std::make_shared<StatisticalAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
209 effective_window_size, effective_hop_size);
210 stat_analyzer->set_parameter(
"method",
"mean");
212 std::vector<Kakshya::DataVariant> data_variant {
Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
213 ChannelStatistics stat_result = stat_analyzer->analyze_statistics(data_variant).channel_statistics[0];
216 result.emplace_back();
220 const double global_mean = stat_result.
mean_stat;
222 const double outlier_threshold = std_dev_threshold * global_std_dev;
224 std::vector<std::pair<size_t, size_t>> qualifying_windows;
228 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
229 qualifying_windows.emplace_back(start_idx, end_idx);
234 auto merged_windows = merge_overlapping_windows(qualifying_windows);
236 std::vector<double> extracted_data;
237 for (
const auto& [start_idx, end_idx] : merged_windows) {
238 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
239 std::back_inserter(extracted_data));
242 result.push_back(std::move(extracted_data));
243 }
catch (
const std::exception&) {
244 result.emplace_back();
252 const std::vector<std::span<const double>>& data,
253 double spectral_threshold,
254 uint32_t window_size,
257 std::vector<std::vector<double>> result;
258 result.reserve(data.size());
260 for (
const auto& channel : data) {
261 if (channel.empty()) {
262 result.emplace_back();
266 uint32_t effective_window_size = std::min(window_size,
static_cast<uint32_t
>(channel.size()));
267 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
268 if (effective_hop_size == 0)
269 effective_hop_size = 1;
272 result.emplace_back();
277 auto energy_analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
278 effective_window_size, effective_hop_size);
279 energy_analyzer->set_parameter(
"method",
"spectral");
281 std::vector<Kakshya::DataVariant> data_variant {
Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
282 EnergyAnalysis energy_result = energy_analyzer->analyze_energy(data_variant);
284 if (energy_result.
channels.empty() || energy_result.
channels[0].energy_values.empty() || energy_result.
channels[0].window_positions.empty()) {
285 result.emplace_back();
289 std::vector<std::pair<size_t, size_t>> qualifying_windows;
290 const auto& ch_energy = energy_result.
channels[0].energy_values;
291 const auto& ch_windows = energy_result.
channels[0].window_positions;
292 for (
size_t i = 0; i < ch_energy.size(); ++i) {
293 if (ch_energy[i] > spectral_threshold) {
294 auto [start_idx, end_idx] = ch_windows[i];
295 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
296 qualifying_windows.emplace_back(start_idx, end_idx);
301 auto merged_windows = merge_overlapping_windows(qualifying_windows);
303 std::vector<double> extracted_data;
304 for (
const auto& [start_idx, end_idx] : merged_windows) {
305 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
306 std::back_inserter(extracted_data));
309 result.push_back(std::move(extracted_data));
310 }
catch (
const std::exception&) {
311 result.emplace_back();
319 const std::vector<std::span<const double>>& data,
320 double mean_multiplier,
321 uint32_t window_size,
324 std::vector<std::vector<double>> result;
325 result.reserve(data.size());
327 for (
const auto& channel : data) {
328 if (channel.empty()) {
329 result.emplace_back();
333 uint32_t effective_window_size = std::min(window_size,
static_cast<uint32_t
>(channel.size()));
334 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
335 if (effective_hop_size == 0)
336 effective_hop_size = 1;
339 result.emplace_back();
344 auto stat_analyzer = std::make_shared<StatisticalAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
345 effective_window_size, effective_hop_size);
346 stat_analyzer->set_parameter(
"method",
"mean");
348 std::vector<Kakshya::DataVariant> data_variant {
Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
349 ChannelStatistics stat_result = stat_analyzer->analyze_statistics(data_variant).channel_statistics[0];
352 result.emplace_back();
356 const double threshold = stat_result.
mean_stat * mean_multiplier;
358 std::vector<std::pair<size_t, size_t>> qualifying_windows;
362 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
363 qualifying_windows.emplace_back(start_idx, end_idx);
368 auto merged_windows = merge_overlapping_windows(qualifying_windows);
370 std::vector<double> extracted_data;
371 for (
const auto& [start_idx, end_idx] : merged_windows) {
372 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
373 std::back_inserter(extracted_data));
376 result.push_back(std::move(extracted_data));
377 }
catch (
const std::exception&) {
378 result.emplace_back();
386 const std::vector<std::span<const double>>& data,
387 uint32_t window_size,
390 std::vector<std::vector<double>> result;
391 result.reserve(data.size());
393 if (window_size == 0 || overlap < 0.0 || overlap >= 1.0) {
394 for (
size_t i = 0; i < data.size(); ++i)
395 result.emplace_back();
399 for (
const auto& channel : data) {
400 if (channel.empty() || window_size > channel.size()) {
401 result.emplace_back();
405 const auto hop_size = std::max(1U,
static_cast<uint32_t
>(window_size * (1.0 - overlap)));
406 std::vector<double> channel_windows;
408 for (
size_t start = 0; start + window_size <= channel.size(); start += hop_size) {
409 channel_windows.insert(channel_windows.end(),
410 channel.begin() + start,
411 channel.begin() + start + window_size);
414 result.push_back(std::move(channel_windows));
421 const std::vector<std::span<const double>>& data,
422 const std::vector<size_t>& window_indices,
423 uint32_t window_size)
425 std::vector<std::vector<double>> result;
426 result.reserve(data.size());
428 for (
const auto& channel : data) {
429 std::vector<double> channel_windows;
430 if (channel.empty() || window_size == 0) {
431 result.emplace_back();
435 for (
size_t start_idx : window_indices) {
436 if (start_idx + window_size <= channel.size()) {
437 auto window_span = channel.subspan(start_idx, window_size);
438 channel_windows.insert(channel_windows.end(), window_span.begin(), window_span.end());
441 result.push_back(std::move(channel_windows));
453 "high_spectral_data",
455 "overlapping_windows",
462 if (window_size == 0 || hop_size == 0) {
466 if (data_size == 0) {
470 if (data_size < window_size) {
471 return data_size >= 3;
478 const std::vector<std::span<const double>>& data,
481 uint32_t region_size)
483 std::vector<std::vector<double>> result;
484 result.reserve(data.size());
486 for (
const auto& channel : data) {
487 if (channel.empty() || region_size == 0) {
488 result.emplace_back();
493 auto analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
494 region_size * 2,
static_cast<uint32_t
>(min_distance));
495 analyzer->set_parameter(
"method",
"zero_crossing");
497 std::vector<Kakshya::DataVariant> data_variant {
500 EnergyAnalysis energy_result = analyzer->analyze_energy(data_variant);
502 if (energy_result.
channels.empty()) {
503 result.emplace_back();
507 const auto& crossing_positions = energy_result.
channels[0].event_positions;
509 if (crossing_positions.empty()) {
510 result.emplace_back();
514 std::vector<size_t> filtered_positions;
515 size_t last_position = 0;
517 for (
size_t pos : crossing_positions) {
518 if (filtered_positions.empty() || (pos - last_position) >=
static_cast<size_t>(min_distance)) {
519 filtered_positions.push_back(pos);
524 std::vector<size_t> qualified_positions;
525 for (
size_t pos : filtered_positions) {
526 if (pos < channel.size() && std::abs(channel[pos]) >= threshold) {
527 qualified_positions.push_back(pos);
531 std::vector<double> extracted_data;
532 for (
size_t pos : qualified_positions) {
533 const size_t half_region = region_size / 2;
534 const size_t region_start = (pos >= half_region) ? pos - half_region : 0;
535 const size_t region_end = std::min(pos + half_region, channel.size());
537 if (region_start < region_end) {
538 auto region = channel.subspan(region_start, region_end - region_start);
539 std::ranges::copy(region, std::back_inserter(extracted_data));
543 result.push_back(std::move(extracted_data));
544 }
catch (
const std::exception&) {
545 result.emplace_back();
553 const std::vector<std::span<const double>>& data,
554 double silence_threshold,
555 uint32_t min_duration,
556 uint32_t window_size,
559 std::vector<std::vector<double>> result;
560 result.reserve(data.size());
562 for (
const auto& channel : data) {
563 if (channel.empty()) {
564 result.emplace_back();
568 uint32_t effective_window = std::min(window_size,
static_cast<uint32_t
>(channel.size()));
569 uint32_t effective_hop = std::max(1U, std::min(hop_size, window_size / 2));
572 auto analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
573 effective_window, effective_hop);
574 analyzer->set_parameter(
"method",
"rms");
575 analyzer->set_energy_thresholds(0.0, silence_threshold, silence_threshold * 2.0, silence_threshold * 5.0);
576 analyzer->enable_classification(
true);
578 std::vector<Kakshya::DataVariant> data_variant {
Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
579 EnergyAnalysis energy_result = analyzer->analyze_energy(data_variant);
581 if (energy_result.
channels.empty() || energy_result.
channels[0].energy_values.empty() || energy_result.
channels[0].window_positions.empty() || energy_result.
channels[0].classifications.empty()) {
582 result.emplace_back();
586 const auto& classifications = energy_result.
channels[0].classifications;
587 const auto& window_positions = energy_result.
channels[0].window_positions;
589 std::vector<std::pair<size_t, size_t>> regions;
590 for (
size_t idx = 0; idx < classifications.size(); ++idx) {
592 auto [start_idx, end_idx] = window_positions[idx];
593 if (end_idx > start_idx && (end_idx - start_idx) >= min_duration) {
594 regions.emplace_back(start_idx, end_idx);
599 auto merged_regions = merge_overlapping_windows(regions);
601 std::vector<double> extracted_data;
602 for (
const auto& [start_idx, end_idx] : merged_regions) {
603 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
604 auto region = channel.subspan(start_idx, end_idx - start_idx);
605 std::ranges::copy(region, std::back_inserter(extracted_data));
609 result.push_back(std::move(extracted_data));
610 }
catch (
const std::exception&) {
611 result.emplace_back();
619 const std::vector<std::span<const double>>& data,
621 uint32_t region_size,
622 uint32_t window_size,
625 std::vector<std::vector<double>> result;
626 result.reserve(data.size());
628 for (
const auto& channel : data) {
629 if (channel.empty()) {
630 result.emplace_back();
636 channel, window_size, hop_size, threshold);
638 if (onset_positions.empty()) {
639 result.emplace_back();
643 std::vector<double> extracted_data;
644 for (
size_t onset_pos : onset_positions) {
645 const size_t half_region = region_size / 2;
646 const size_t region_start = (onset_pos >= half_region) ? onset_pos - half_region : 0;
647 const size_t region_end = std::min(onset_pos + half_region, channel.size());
649 if (region_start < region_end) {
650 auto region = channel.subspan(region_start, region_end - region_start);
651 std::ranges::copy(region, std::back_inserter(extracted_data));
655 result.push_back(std::move(extracted_data));
656 }
catch (
const std::exception&) {
657 result.emplace_back();
Span-based energy analysis for digital signals in Maya Flux.
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< std::vector< double > > extract_overlapping_windows(const std::vector< std::span< const double > > &data, uint32_t window_size, double overlap)
Extract overlapping windows of actual data.
std::vector< std::vector< double > > extract_outlier_data(const std::vector< std::span< const double > > &data, double std_dev_threshold, uint32_t window_size, uint32_t hop_size)
Extract data from statistical outlier regions.
std::vector< std::vector< double > > extract_silence_data(const std::vector< std::span< const double > > &data, double silence_threshold, uint32_t min_duration, uint32_t window_size, uint32_t hop_size)
Extract data from silent regions using existing EnergyAnalyzer.
bool validate_extraction_parameters(uint32_t window_size, uint32_t hop_size, size_t data_size)
Validate extraction parameters.
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.
std::vector< std::vector< double > > extract_high_spectral_data(const std::vector< std::span< const double > > &data, double spectral_threshold, uint32_t window_size, uint32_t hop_size)
Extract data from regions with high spectral energy.
std::vector< std::vector< double > > extract_onset_data(const std::vector< std::span< const double > > &data, double threshold, uint32_t region_size, uint32_t window_size, uint32_t hop_size)
Extract data at onset/transient positions using spectral flux.
std::vector< std::vector< double > > extract_windowed_data_by_indices(const std::vector< std::span< const double > > &data, const std::vector< size_t > &window_indices, uint32_t window_size)
Extract specific data windows by indices.
std::vector< std::vector< double > > extract_above_mean_data(const std::vector< std::span< const double > > &data, double mean_multiplier, uint32_t window_size, uint32_t hop_size)
Extract data from regions with values above statistical mean.
std::vector< std::vector< double > > extract_peak_data(const std::vector< std::span< const double > > &data, double threshold, double min_distance, uint32_t region_size)
Extract data from peak regions using peak detection.
std::vector< std::string > get_available_extraction_methods()
Get available extraction methods.
std::vector< std::vector< double > > extract_high_energy_data(const std::vector< std::span< const double > > &data, double energy_threshold, uint32_t window_size, uint32_t hop_size)
Extract data from high-energy regions using EnergyAnalyzer.
std::vector< std::vector< double > > extract_zero_crossing_data(const std::vector< std::span< const double > > &data, double threshold, double min_distance, uint32_t region_size)
Extract data at zero crossing points using existing EnergyAnalyzer.
std::vector< std::pair< size_t, size_t > > window_positions
std::vector< double > statistical_values
Statistical results for a single data channel.
std::vector< ChannelEnergy > channels
Analysis result structure for energy analysis.