317{
318
319 auto extraction_result = OperationHelper::extract_structured_double(input);
320 auto& target_data = std::get<0>(extraction_result);
321 auto& structure_info = std::get<1>(extraction_result);
322
323 std::ranges::for_each(fade_regions, [&target_data, fade_duration](const auto& fade_pair) {
324 const auto& [region_a, region_b] = fade_pair;
325
326 auto start_a = static_cast<uint64_t>(region_a.start_coordinates[0]);
327 auto end_a = static_cast<uint64_t>(region_a.end_coordinates[0]);
328 auto start_b = static_cast<uint64_t>(region_b.start_coordinates[0]);
329
330 uint64_t fade_start = (end_a > fade_duration) ? end_a - fade_duration : 0;
331 uint64_t fade_end = std::min(start_b + fade_duration,
static_cast<uint64_t
>(target_data[0].
size()));
332
333 for (auto& channel_span : target_data) {
334 if (fade_start < fade_end && fade_start < channel_span.size()) {
335 auto fade_span = channel_span.subspan(fade_start, fade_end - fade_start);
336
337 auto fade_indices = std::views::iota(size_t { 0 }, fade_span.size());
338 std::ranges::for_each(fade_indices, [&fade_span](size_t i) {
339 double ratio = static_cast<double>(i) / (fade_span.size() - 1);
340 double smooth_ratio = 0.5 * (1.0 - std::cos(ratio * M_PI));
341 fade_span[i] *= (1.0 - smooth_ratio);
342 });
343 }
344 }
345 });
346
347 auto reconstructed_data = target_data
348 | std::views::transform([](const auto& span) {
349 return std::vector<double>(span.begin(), span.end());
350 })
351 | std::ranges::to<std::vector>();
352
353 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
354}