MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SpectralTransformer.hpp
Go to the documentation of this file.
1#pragma once
2
5
6namespace MayaFlux::Yantra {
7
8/**
9 * @enum SpectralOperation
10 * @brief Specific spectral operations supported
11 */
12enum class SpectralOperation : uint8_t {
13 FREQUENCY_SHIFT, ///< Shift entire spectrum
14 PITCH_SHIFT, ///< Pitch-preserving shift
15 SPECTRAL_FILTER, ///< Filter frequency bands
16 HARMONIC_ENHANCE, ///< Enhance harmonics
17 SPECTRAL_GATE, ///< Spectral gating
18};
19
20/**
21 * @class SpectralTransformer
22 * @brief Concrete transformer for frequency-domain operations
23 *
24 * Handles transformations in the spectral domain:
25 * - Spectral filtering and shaping
26 * - Pitch shifting and harmonics
27 * - Spectral morphing and cross-synthesis
28 * - Frequency analysis and manipulation
29 */
30template <ComputeData InputType = std::vector<Kakshya::DataVariant>, ComputeData OutputType = InputType>
31class MAYAFLUX_API SpectralTransformer final : public UniversalTransformer<InputType, OutputType> {
32public:
35
36 /**
37 * @brief Constructs a SpectralTransformer with specified operation
38 * @param op The spectral operation to perform (default: FREQUENCY_SHIFT)
39 */
40 explicit SpectralTransformer(SpectralOperation op = SpectralOperation::FREQUENCY_SHIFT)
41 : m_operation(op)
42 {
43 set_default_parameters();
44 }
45
46 /**
47 * @brief Gets the transformation type
48 * @return TransformationType::SPECTRAL
49 */
50 [[nodiscard]] TransformationType get_transformation_type() const override
51 {
52 return TransformationType::SPECTRAL;
53 }
54
55 /**
56 * @brief Gets the transformer name including the operation type
57 * @return String representation of the transformer name
58 */
59 [[nodiscard]] std::string get_transformer_name() const override
60 {
61 return std::string("SpectralTransformer_").append(Utils::enum_to_string(m_operation));
62 }
63
64protected:
65 /**
66 * @brief Core transformation implementation for spectral operations
67 * @param input Input data to transform in the frequency domain
68 * @return Transformed output data
69 *
70 * Performs the spectral operation specified by m_operation on the input data.
71 * Operations are performed using FFT/IFFT transforms with windowing for overlap-add processing.
72 * Supports both in-place and out-of-place transformations.
73 */
75 {
76 switch (m_operation) {
77 case SpectralOperation::FREQUENCY_SHIFT: {
78 auto shift_hz = get_parameter_or<double>("shift_hz", 0.0);
79 auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
80 auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
81 auto sample_rate = get_parameter_or<double>("sample_rate", 48000.0);
82
83 auto low_freq = std::max(0.0, shift_hz);
84 auto high_freq = sample_rate / 2.0 + shift_hz;
85
86 if (this->is_in_place()) {
87 return create_output(transform_spectral_filter(input, low_freq, high_freq, sample_rate, window_size, hop_size));
88 }
89 return create_output(transform_spectral_filter(input, low_freq, high_freq, sample_rate, window_size, hop_size, m_working_buffer));
90 }
91
92 case SpectralOperation::PITCH_SHIFT: {
93 auto pitch_ratio = get_parameter_or<double>("pitch_ratio", 1.0);
94 auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
95 auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
96
97 double semitones = 12.0 * std::log2(pitch_ratio);
98
99 if (this->is_in_place()) {
100 return create_output(transform_pitch_shift(input, semitones, window_size, hop_size));
101 }
102 return create_output(transform_pitch_shift(input, semitones, window_size, hop_size, m_working_buffer));
103 }
104
105 case SpectralOperation::SPECTRAL_FILTER: {
106 auto low_freq = get_parameter_or<double>("low_freq", 20.0);
107 auto high_freq = get_parameter_or<double>("high_freq", 20000.0);
108 auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
109 auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
110 auto sample_rate = get_parameter_or<double>("sample_rate", 48000.0);
111
112 if (this->is_in_place()) {
113 return create_output(transform_spectral_filter(input, low_freq, high_freq, sample_rate, window_size, hop_size));
114 }
115 return create_output(transform_spectral_filter(input, low_freq, high_freq, sample_rate, window_size, hop_size, m_working_buffer));
116 }
117
118 case SpectralOperation::HARMONIC_ENHANCE: {
119 auto enhancement_factor = get_parameter_or<double>("enhancement_factor", 2.0);
120 auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
121 auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
122
123 if (this->is_in_place()) {
124 auto [data_span, structure_info] = OperationHelper::extract_structured_double(input);
125
126 auto processor = [enhancement_factor](Eigen::VectorXcd& spectrum, size_t) {
127 for (int i = 1; i < spectrum.size() / 2; ++i) {
128 double freq_factor = 1.0 + (enhancement_factor - 1.0) * (double(i) / (spectrum.size() / 2));
129 spectrum[i] *= freq_factor;
130 spectrum[spectrum.size() - i] *= freq_factor;
131 }
132 };
133
134 for (auto& span : data_span) {
135 auto result = process_spectral_windows(span, window_size, hop_size, processor);
136 std::ranges::copy(result, span.begin());
137 }
138
139 auto reconstructed_data = data_span
140 | std::views::transform([](const auto& span) {
141 return std::vector<double>(span.begin(), span.end());
142 })
143 | std::ranges::to<std::vector>();
144
145 return create_output(OperationHelper::reconstruct_from_double<InputType>(reconstructed_data, structure_info));
146 }
147
148 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, m_working_buffer);
149 auto processor = [enhancement_factor](Eigen::VectorXcd& spectrum, size_t) {
150 for (int i = 1; i < spectrum.size() / 2; ++i) {
151 double freq_factor = 1.0 + (enhancement_factor - 1.0) * (double(i) / (spectrum.size() / 2));
152 spectrum[i] *= freq_factor;
153 spectrum[spectrum.size() - i] *= freq_factor;
154 }
155 };
156
157 for (size_t i = 0; i < target_data.size(); ++i) {
158 auto result = process_spectral_windows(target_data[i], window_size, hop_size, processor);
159 m_working_buffer[i] = std::move(result);
160 }
161
162 return create_output(OperationHelper::reconstruct_from_double<InputType>(m_working_buffer, structure_info));
163 }
164
165 case SpectralOperation::SPECTRAL_GATE: {
166 auto threshold = get_parameter_or<double>("threshold", -40.0);
167 auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
168 auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
169
170 double linear_threshold = std::pow(10.0, threshold / 20.0);
171
172 if (this->is_in_place()) {
173 auto [data_span, structure_info] = OperationHelper::extract_structured_double(input);
174
175 auto processor = [linear_threshold](Eigen::VectorXcd& spectrum, size_t) {
176 std::ranges::transform(spectrum, spectrum.begin(), [linear_threshold](const std::complex<double>& bin) {
177 return (std::abs(bin) > linear_threshold) ? bin : std::complex<double>(0.0, 0.0);
178 });
179 };
180
181 for (auto& span : data_span) {
182 auto result = process_spectral_windows(span, window_size, hop_size, processor);
183 std::ranges::copy(result, span.begin());
184 }
185
186 auto reconstructed_data = data_span
187 | std::views::transform([](const auto& span) {
188 return std::vector<double>(span.begin(), span.end());
189 })
190 | std::ranges::to<std::vector>();
191
192 return create_output(OperationHelper::reconstruct_from_double<InputType>(reconstructed_data, structure_info));
193 }
194
195 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, m_working_buffer);
196 auto processor = [linear_threshold](Eigen::VectorXcd& spectrum, size_t) {
197 std::ranges::transform(spectrum, spectrum.begin(), [linear_threshold](const std::complex<double>& bin) {
198 return (std::abs(bin) > linear_threshold) ? bin : std::complex<double>(0.0, 0.0);
199 });
200 };
201
202 for (size_t i = 0; i < target_data.size(); ++i) {
203 auto result = process_spectral_windows(target_data[i], window_size, hop_size, processor);
204 m_working_buffer[i] = std::move(result);
205 }
206
207 return create_output(OperationHelper::reconstruct_from_double<InputType>(m_working_buffer, structure_info));
208 }
209
210 default:
211 return create_output(input);
212 }
213 }
214
215 /**
216 * @brief Sets transformation parameters
217 * @param name Parameter name
218 * @param value Parameter value
219 *
220 * Handles setting of spectral operation type and delegates other parameters to base class.
221 * Supports both enum and string values for the "operation" parameter.
222 *
223 * Common parameters include:
224 * - "shift_hz": Frequency shift in Hz
225 * - "pitch_ratio": Pitch scaling factor (1.0 = no change)
226 * - "low_freq", "high_freq": Filter frequency bounds
227 * - "enhancement_factor": Harmonic enhancement strength
228 * - "threshold": Spectral gate threshold in dB
229 * - "window_size", "hop_size": FFT processing parameters
230 */
231 void set_transformation_parameter(const std::string& name, std::any value) override
232 {
233 if (name == "operation") {
234 if (auto op_result = safe_any_cast<SpectralOperation>(value)) {
235 m_operation = *op_result.value;
236 return;
237 }
238 if (auto str_result = safe_any_cast<std::string>(value)) {
239 if (auto op_enum = Utils::string_to_enum_case_insensitive<SpectralOperation>(*str_result.value)) {
240 m_operation = *op_enum;
241 return;
242 }
243 }
244 }
245
247 }
248
249private:
250 SpectralOperation m_operation; ///< Current spectral operation
251 mutable std::vector<std::vector<double>> m_working_buffer; ///< Buffer for out-of-place spectral operations
252
253 /**
254 * @brief Sets default parameter values for all spectral operations
255 *
256 * Initializes all possible parameters with sensible defaults to ensure
257 * the transformer works correctly regardless of the selected operation.
258 * Default values are chosen for typical audio processing scenarios.
259 */
261 {
262 this->set_parameter("shift_hz", 0.0);
263 this->set_parameter("pitch_ratio", 1.0);
264 this->set_parameter("low_freq", 20.0);
265 this->set_parameter("high_freq", 20000.0);
266 this->set_parameter("enhancement_factor", 2.0);
267 this->set_parameter("threshold", -40.0);
268 this->set_parameter("time_stretch", 1.0);
269 this->set_parameter("window_size", uint32_t { 1024 });
270 this->set_parameter("hop_size", uint32_t { 512 });
271 }
272
273 /**
274 * @brief Gets a parameter value with fallback to default
275 * @tparam T Parameter type
276 * @param name Parameter name
277 * @param default_value Default value if parameter not found or wrong type
278 * @return Parameter value or default
279 */
280 template <typename T>
281 T get_parameter_or(const std::string& name, const T& default_value) const
282 {
283 auto param = this->get_transformation_parameter(name);
284 if (!param.has_value())
285 return default_value;
286
287 auto result = safe_any_cast<T>(param);
288 return result.value_or(default_value);
289 }
290
291 /**
292 * @brief Creates output with proper type conversion
293 * @param data Input data to convert
294 * @return Output with converted data type
295 *
296 * Handles type conversion between InputType and OutputType when necessary,
297 * or direct assignment when types match. Ensures spectral processing results
298 * are properly converted back to the expected output type.
299 */
301 {
302 if constexpr (std::is_same_v<InputType, OutputType>) {
303 return input;
304 } else {
305 auto [result_data, metadata] = OperationHelper::extract_structured_double(input);
306 return this->convert_result(result_data, metadata);
307 }
308 }
309};
310}
Float Processing Guidelines.
std::string get_transformer_name() const override
Gets the transformer name including the operation type.
output_type create_output(const input_type &input)
Creates output with proper type conversion.
SpectralOperation m_operation
Current spectral operation.
output_type transform_implementation(input_type &input) override
Core transformation implementation for spectral operations.
TransformationType get_transformation_type() const override
Gets the transformation type.
std::vector< std::vector< double > > m_working_buffer
Buffer for out-of-place spectral operations.
SpectralTransformer(SpectralOperation op=SpectralOperation::FREQUENCY_SHIFT)
Constructs a SpectralTransformer with specified operation.
T get_parameter_or(const std::string &name, const T &default_value) const
Gets a parameter value with fallback to default.
void set_default_parameters()
Sets default parameter values for all spectral operations.
void set_transformation_parameter(const std::string &name, std::any value) override
Sets transformation parameters.
Concrete transformer for frequency-domain operations.
Template-flexible transformer base with instance-defined I/O types.
std::vector< double > process_spectral_windows(std::span< double > data, uint32_t window_size, uint32_t hop_size, ProcessorFunc &&processor)
Common spectral processing helper to eliminate code duplication.
SpectralOperation
Specific spectral operations supported.
@ SPECTRAL_FILTER
Filter frequency bands.
@ HARMONIC_ENHANCE
Enhance harmonics.
@ PITCH_SHIFT
Pitch-preserving shift.
@ FREQUENCY_SHIFT
Shift entire spectrum.
DataType transform_spectral_filter(DataType &input, double low_freq, double high_freq, double sample_rate=48000.0, uint32_t window_size=1024, uint32_t hop_size=256)
Spectral filtering using existing FFT infrastructure with C++20 ranges (IN-PLACE)
DataType transform_pitch_shift(DataType &input, double semitones, uint32_t window_size=1024, uint32_t hop_size=256)
Pitch shifting using existing FFT from AnalysisHelper with C++20 ranges (IN-PLACE)
TransformationType
Categories of transformation operations for discovery and organization.
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:24