MayaFlux 0.3.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
9
10/**
11 * @enum SpectralOperation
12 * @brief Spectral operations supported by SpectralTransformer
13 */
14enum class SpectralOperation : uint8_t {
15 FREQUENCY_SHIFT, ///< Bandpass repositioning (approximate frequency shift)
16 PITCH_SHIFT, ///< Phase-vocoder pitch shift, duration preserved
17 SPECTRAL_FILTER, ///< Hard bandpass filter
18 HARMONIC_ENHANCE, ///< Linear spectral tilt
19 SPECTRAL_GATE, ///< Hard magnitude gate
20};
21
22/**
23 * @class SpectralTransformer
24 * @brief Concrete transformer for frequency-domain operations
25 *
26 * Handles transformations in the spectral domain:
27 * - Spectral filtering and shaping
28 * - Pitch shifting and harmonics
29 * - Spectral morphing and cross-synthesis
30 * - Frequency analysis and manipulation
31 */
32template <ComputeData InputType = std::vector<Kakshya::DataVariant>, ComputeData OutputType = InputType>
33class MAYAFLUX_API SpectralTransformer final : public UniversalTransformer<InputType, OutputType> {
34public:
37
38 /**
39 * @brief Constructs a SpectralTransformer with specified operation
40 * @param op The spectral operation to perform (default: FREQUENCY_SHIFT)
41 */
42 explicit SpectralTransformer(SpectralOperation op = SpectralOperation::FREQUENCY_SHIFT)
43 : m_operation(op)
44 {
45 set_default_parameters();
46 }
47
48 /**
49 * @brief Gets the transformation type
50 * @return TransformationType::SPECTRAL
51 */
52 [[nodiscard]] TransformationType get_transformation_type() const override
53 {
54 return TransformationType::SPECTRAL;
55 }
56
57 /**
58 * @brief Gets the transformer name including the operation type
59 * @return String representation of the transformer name
60 */
61 [[nodiscard]] std::string get_transformer_name() const override
62 {
63 return std::string("SpectralTransformer_").append(Reflect::enum_to_string(m_operation));
64 }
65
66protected:
67 /**
68 * @brief Applies the configured spectral operation
69 * @param input Input data
70 * @return Transformed output
71 *
72 * Extracts per-channel double spans, calls the corresponding
73 * Kinesis::Discrete::Spectral primitive on each channel, then
74 * reconstructs the typed output via OperationHelper.
75 *
76 * FREQUENCY_SHIFT is implemented as a bandpass repositioning matching
77 * the prior behaviour. True single-sideband frequency
78 * shift (complex exponential modulation) is a separate primitive.
79 */
81 {
82 switch (m_operation) {
83
84 case SpectralOperation::FREQUENCY_SHIFT: {
85 const auto shift_hz = get_parameter_or<double>("shift_hz", 0.0);
86 const auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
87 const auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
88 const auto sample_rate = get_parameter_or<double>("sample_rate", 48000.0);
89 const double lo = std::max(0.0, shift_hz);
90 const double hi = sample_rate / 2.0 + shift_hz;
91
92 return apply_per_channel(input,
93 [lo, hi, sample_rate, window_size, hop_size](std::span<double> ch) {
94 return D::spectral_filter(ch, lo, hi, sample_rate, window_size, hop_size);
95 });
96 }
97
98 case SpectralOperation::PITCH_SHIFT: {
99 const auto pitch_ratio = get_parameter_or<double>("pitch_ratio", 1.0);
100 const auto window_size = get_parameter_or<uint32_t>("window_size", 2048);
101 const auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
102 const double semitones = 12.0 * std::log2(pitch_ratio);
103
104 return apply_per_channel(input,
105 [semitones, window_size, hop_size](std::span<double> ch) {
106 return D::pitch_shift(ch, semitones, window_size, hop_size);
107 });
108 }
109
110 case SpectralOperation::SPECTRAL_FILTER: {
111 const auto lo_freq = get_parameter_or<double>("low_freq", 20.0);
112 const auto hi_freq = get_parameter_or<double>("high_freq", 20000.0);
113 const auto sample_rate = get_parameter_or<double>("sample_rate", 48000.0);
114 const auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
115 const auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
116
117 return apply_per_channel(input,
118 [lo_freq, hi_freq, sample_rate, window_size, hop_size](std::span<double> ch) {
119 return D::spectral_filter(ch, lo_freq, hi_freq, sample_rate, window_size, hop_size);
120 });
121 }
122
123 case SpectralOperation::HARMONIC_ENHANCE: {
124 const auto factor = get_parameter_or<double>("enhancement_factor", 2.0);
125 const auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
126 const auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
127
128 return apply_per_channel(input,
129 [factor, window_size, hop_size](std::span<double> ch) {
130 return D::harmonic_enhance(ch, factor, window_size, hop_size);
131 });
132 }
133
134 case SpectralOperation::SPECTRAL_GATE: {
135 const auto threshold = get_parameter_or<double>("threshold", -40.0);
136 const auto window_size = get_parameter_or<uint32_t>("window_size", 1024);
137 const auto hop_size = get_parameter_or<uint32_t>("hop_size", 512);
138
139 return apply_per_channel(input,
140 [threshold, window_size, hop_size](std::span<double> ch) {
141 return D::spectral_gate(ch, threshold, window_size, hop_size);
142 });
143 }
144
145 default:
146 return create_output(input);
147 }
148 }
149
150 /**
151 * @brief Sets transformation parameters
152 * @param name Parameter name
153 * @param value Parameter value
154 *
155 * Handles setting of spectral operation type and delegates other parameters to base class.
156 * Supports both enum and string values for the "operation" parameter.
157 *
158 * Common parameters include:
159 * - "shift_hz": Frequency shift in Hz
160 * - "pitch_ratio": Pitch scaling factor (1.0 = no change)
161 * - "low_freq", "high_freq": Filter frequency bounds
162 * - "enhancement_factor": Harmonic enhancement strength
163 * - "threshold": Spectral gate threshold in dB
164 * - "window_size", "hop_size": FFT processing parameters
165 */
166 void set_transformation_parameter(const std::string& name, std::any value) override
167 {
168 if (name == "operation") {
169 if (auto r = safe_any_cast<SpectralOperation>(value)) {
170 m_operation = *r.value;
171 return;
172 }
173 if (auto r = safe_any_cast<std::string>(value)) {
174 if (auto e = Reflect::string_to_enum_case_insensitive<SpectralOperation>(*r.value)) {
175 m_operation = *e;
176 return;
177 }
178 }
179 }
180
182 }
183
184private:
185 SpectralOperation m_operation; ///< Current spectral operation
186 mutable std::vector<std::vector<double>> m_working_buffer; ///< Buffer for out-of-place spectral operations
187
188 /**
189 * @brief Extracts per-channel spans, applies func to each, and reconstructs.
190 * @tparam Func Callable matching std::vector<double>(std::span<double>)
191 *
192 * In-place: results are written back into the channel spans of @p input before
193 * reconstruction, leaving no second allocation of channel data live at the same time.
194 * Out-of-place: results land in m_working_buffer; the original channel data in
195 * @p input is not touched.
196 */
197 template <typename Func>
199 {
200 auto [channels, structure_info] = OperationHelper::extract_structured_double(input);
201 m_working_buffer.resize(channels.size());
202 for (size_t i = 0; i < channels.size(); ++i)
203 m_working_buffer[i] = func(channels[i]);
204
205 if (this->is_in_place())
206 for (size_t i = 0; i < channels.size(); ++i)
207 std::ranges::copy(m_working_buffer[i], channels[i].begin());
208
209 return create_output(
210 OperationHelper::reconstruct_from_double<InputType>(m_working_buffer, structure_info));
211 }
212
213 /**
214 * @brief Sets default parameter values for all spectral operations
215 *
216 * Initializes all possible parameters with sensible defaults to ensure
217 * the transformer works correctly regardless of the selected operation.
218 * Default values are chosen for typical audio processing scenarios.
219 */
221 {
222 this->set_parameter("shift_hz", 0.0);
223 this->set_parameter("pitch_ratio", 1.0);
224 this->set_parameter("low_freq", 20.0);
225 this->set_parameter("high_freq", 20000.0);
226 this->set_parameter("enhancement_factor", 2.0);
227 this->set_parameter("threshold", -40.0);
228 this->set_parameter("time_stretch", 1.0);
229 this->set_parameter("window_size", uint32_t { 1024 });
230 this->set_parameter("hop_size", uint32_t { 512 });
231 }
232
233 /**
234 * @brief Gets a parameter value with fallback to default
235 * @tparam T Parameter type
236 * @param name Parameter name
237 * @param default_value Default value if parameter not found or wrong type
238 * @return Parameter value or default
239 */
240 template <typename T>
241 T get_parameter_or(const std::string& name, const T& default_value) const
242 {
243 auto param = this->get_transformation_parameter(name);
244 if (!param.has_value())
245 return default_value;
246
247 auto result = safe_any_cast<T>(param);
248 return result.value_or(default_value);
249 }
250
251 /**
252 * @brief Creates output with proper type conversion
253 * @param data Input data to convert
254 * @return Output with converted data type
255 *
256 * Handles type conversion between InputType and OutputType when necessary,
257 * or direct assignment when types match. Ensures spectral processing results
258 * are properly converted back to the expected output type.
259 */
261 {
262 if constexpr (std::is_same_v<InputType, OutputType>) {
263 return input;
264 } else {
265 auto [result_data, metadata] = OperationHelper::extract_structured_double(input);
266 return this->convert_result(result_data, metadata);
267 }
268 }
269};
270}
Short-time Fourier domain primitives for MayaFlux::Kinesis.
Float Processing Guidelines.
output_type apply_per_channel(input_type &input, Func &&func)
Extracts per-channel spans, applies func to each, and reconstructs.
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
Applies the configured spectral operation.
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.
SpectralOperation
Spectral operations supported by SpectralTransformer.
@ SPECTRAL_FILTER
Hard bandpass filter.
@ SPECTRAL_GATE
Hard magnitude gate.
@ HARMONIC_ENHANCE
Linear spectral tilt.
@ PITCH_SHIFT
Phase-vocoder pitch shift, duration preserved.
@ FREQUENCY_SHIFT
Bandpass repositioning (approximate frequency shift)
TransformationType
Categories of transformation operations for discovery and organization.
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:24