30template <
typename TransformFunc>
31 requires std::invocable<TransformFunc, std::span<const double>>
35 TransformFunc transform_func)
37 const size_t num_windows = (data.size() - window_size) / hop_size + 1;
38 std::vector<double> output(data.size(), 0.0);
40 std::ranges::for_each(std::views::iota(
size_t { 0 }, num_windows), [&](
size_t win) {
41 size_t start_idx = win * hop_size;
42 auto window_data = data.subspan(start_idx,
43 std::min(
static_cast<size_t>(window_size), data.size() - start_idx));
45 auto transformed = transform_func(window_data);
47 for (
size_t i = 0; i < transformed.size() && start_idx + i < output.size(); ++i) {
48 output[start_idx + i] += transformed[i];
61template <OperationReadyData DataType>
66 for (
auto& span : target_data) {
67 std::ranges::reverse(span);
70 auto reconstructed_data = target_data
71 | std::views::transform([](
const auto& span) {
72 return std::vector<double>(span.begin(), span.end());
74 | std::ranges::to<std::vector>();
76 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
86template <OperationReadyData DataType>
91 for (
auto& span : target_data) {
92 std::ranges::reverse(span);
95 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
105template <OperationReadyData DataType>
108 if (stretch_factor == 1.0) {
114 std::vector<std::vector<double>> result(target_data.size());
116 for (
size_t i = 0; i < target_data.size(); ++i) {
117 auto new_size =
static_cast<size_t>(target_data[i].size() * stretch_factor);
118 result[i].resize(new_size);
122 return OperationHelper::reconstruct_from_double<DataType>(result, structure_info);
133template <OperationReadyData DataType>
136 if (stretch_factor == 1.0) {
142 for (
size_t i = 0; i < target_data.size(); ++i) {
143 auto new_size =
static_cast<size_t>(target_data[i].size() * stretch_factor);
144 working_buffer[i].resize(new_size);
145 interpolate(target_data[i], working_buffer[i], new_size);
148 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
159template <OperationReadyData DataType>
160DataType
transform_delay(DataType& input, uint32_t delay_samples,
double fill_value = 0.0)
164 std::vector<std::vector<double>> result(target_data.size());
165 for (
size_t i = 0; i < target_data.size(); ++i) {
166 result[i].resize(target_data[i].size() + delay_samples);
167 std::fill_n(result[i].begin(), delay_samples, fill_value);
168 std::copy(target_data[i].begin(), target_data[i].end(), result[i].begin() + delay_samples);
171 return OperationHelper::reconstruct_from_double<DataType>(result, structure_info);
183template <OperationReadyData DataType>
184DataType
transform_delay(DataType& input, uint32_t delay_samples,
double fill_value, std::vector<std::vector<double>>& working_buffer)
188 for (
size_t i = 0; i < target_data.size(); ++i) {
189 std::vector<double> original_data(target_data[i].begin(), target_data[i].end());
191 working_buffer[i].resize(original_data.size() + delay_samples);
192 std::fill_n(working_buffer[i].begin(), delay_samples, fill_value);
193 std::ranges::copy(original_data, working_buffer[i].begin() + delay_samples);
196 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
207template <OperationReadyData DataType>
208DataType
transform_fade(DataType& input,
double fade_in_duration_ratio = 0.0,
double fade_out_duration_ratio = 0.0)
212 for (
auto& span : target_data) {
213 auto fade_in_samples =
static_cast<size_t>(span.size() * fade_in_duration_ratio);
214 auto fade_out_samples =
static_cast<size_t>(span.size() * fade_out_duration_ratio);
215 size_t fade_out_start = span.size() - fade_out_samples;
217 for (
size_t j = 0; j < fade_in_samples && fade_in_samples > 1; ++j) {
218 double fade_factor =
static_cast<double>(j) /
static_cast<double>(fade_in_samples - 1);
219 span[j] *= fade_factor;
222 for (
size_t j = 0; j < fade_out_samples && fade_out_samples > 1 && fade_out_start + j < span.size(); ++j) {
223 double fade_factor = 1.0 - (
static_cast<double>(j) /
static_cast<double>(fade_out_samples - 1));
224 span[fade_out_start + j] *= fade_factor;
228 auto reconstructed_data = target_data
229 | std::views::transform([](
const auto& span) {
230 return std::vector<double>(span.begin(), span.end());
232 | std::ranges::to<std::vector>();
234 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
246template <OperationReadyData DataType>
247DataType
transform_fade(DataType& input,
double fade_in_duration_ratio,
double fade_out_duration_ratio, std::vector<std::vector<double>>& working_buffer)
251 for (
size_t i = 0; i < target_data.size(); ++i) {
252 auto& span = target_data[i];
253 working_buffer[i].assign(span.begin(), span.end());
255 auto fade_in_samples =
static_cast<size_t>(span.size() * fade_in_duration_ratio);
256 auto fade_out_samples =
static_cast<size_t>(span.size() * fade_out_duration_ratio);
257 size_t fade_out_start = span.size() - fade_out_samples;
259 for (
size_t j = 0; j < fade_in_samples && fade_in_samples > 1; ++j) {
260 double fade_factor =
static_cast<double>(j) /
static_cast<double>(fade_in_samples - 1);
261 working_buffer[i][j] *= fade_factor;
264 for (
size_t j = 0; j < fade_out_samples && fade_out_samples > 1 && fade_out_start + j < span.size(); ++j) {
265 double fade_factor = 1.0 - (
static_cast<double>(j) /
static_cast<double>(fade_out_samples - 1));
266 working_buffer[i][fade_out_start + j] *= fade_factor;
270 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
281template <OperationReadyData DataType>
286 std::vector<std::vector<double>> result(target_data.size());
287 for (
size_t i = 0; i < target_data.size(); ++i) {
288 size_t start_idx =
static_cast<size_t>(target_data[i].size() * std::clamp(start_ratio, 0.0, 1.0));
289 size_t end_idx =
static_cast<size_t>(target_data[i].size() * std::clamp(end_ratio, 0.0, 1.0));
291 if (start_idx >= end_idx || end_idx > target_data[i].size()) {
294 result[i].assign(target_data[i].begin() + start_idx, target_data[i].begin() + end_idx);
298 return OperationHelper::reconstruct_from_double<DataType>(result, structure_info);
310template <OperationReadyData DataType>
311DataType
transform_slice(DataType& input,
double start_ratio,
double end_ratio, std::vector<std::vector<double>>& working_buffer)
315 for (
size_t i = 0; i < target_data.size(); ++i) {
316 size_t start_idx =
static_cast<size_t>(target_data[i].size() * std::clamp(start_ratio, 0.0, 1.0));
317 size_t end_idx =
static_cast<size_t>(target_data[i].size() * std::clamp(end_ratio, 0.0, 1.0));
319 if (start_idx >= end_idx || end_idx > target_data[i].size()) {
320 working_buffer[i] = { 0.0 };
322 working_buffer[i].assign(target_data[i].begin() + start_idx, target_data[i].begin() + end_idx);
326 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
static std::tuple< std::vector< std::span< double > >, DataStructureInfo > extract_structured_double(T &compute_data)
Extract structured double data from IO container or direct ComputeData with automatic container handl...
static auto setup_operation_buffer(T &input, std::vector< std::vector< double > > &working_buffer)
Setup operation buffer from IO or ComputeData type.
void interpolate(std::span< double > input, std::vector< double > &output, uint32_t target_size)
DataType transform_time_reverse(DataType &input)
Time reversal transformation using C++20 ranges (IN-PLACE)
DataType transform_delay(DataType &input, uint32_t delay_samples, double fill_value=0.0)
Delay transformation that extends buffer size (IN-PLACE)
DataType transform_time_stretch(DataType &input, double stretch_factor)
Simple time stretching via resampling using C++20 ranges (IN-PLACE)
DataType transform_slice(DataType &input, double start_ratio, double end_ratio)
Slice transformation to extract a portion of the data based on ratios (IN-PLACE)
DataType transform_fade(DataType &input, double fade_in_duration_ratio=0.0, double fade_out_duration_ratio=0.0)
Fade transformation (linear fade-in and fade-out) using C++20 ranges (IN-PLACE)
std::vector< double > process_overlap_add(const std::span< const double > &data, uint32_t window_size, uint32_t hop_size, TransformFunc transform_func)
Overlap-add processing for windowed transforms using C++20 ranges.