Line data Source code
1 : #pragma once
2 :
3 : #include <vector>
4 : #include <memory>
5 : #include <string>
6 :
7 : // Forward-declare kiss_fft types to avoid exposing the C header
8 : struct kiss_fft_state;
9 : typedef struct kiss_fft_state* kiss_fft_cfg;
10 :
11 : namespace Amplitron {
12 :
13 : // =============================================================================
14 : // ConvolutionKernel — immutable, prepared on the GUI thread
15 : // =============================================================================
16 :
17 : class ConvolutionKernel {
18 : public:
19 : // Construct from time-domain IR samples.
20 : // block_size is the audio buffer size (e.g. 64, 128, 256).
21 : ConvolutionKernel(const std::vector<float>& ir_samples, int block_size);
22 : ~ConvolutionKernel();
23 :
24 3120 : int block_size() const { return block_size_; }
25 3072 : int fft_size() const { return fft_size_; }
26 3075 : int num_partitions() const { return num_partitions_; }
27 5092 : int ir_length() const { return ir_length_; }
28 :
29 : // Access the i-th partition in frequency domain.
30 : // Returns fft_size complex values as kiss_fft_cpx array.
31 : const void* partition_freq(int index) const;
32 :
33 : // Time-domain IR (for direct convolution fallback)
34 3033 : const std::vector<float>& ir_time_domain() const { return ir_time_; }
35 :
36 : // Metadata
37 : std::string source_path;
38 : std::string source_name; // filename only
39 : float duration_ms = 0.0f;
40 :
41 : private:
42 : int block_size_;
43 : int fft_size_; // = 2 * block_size (for linear convolution via overlap-add)
44 : int num_partitions_;
45 : int ir_length_;
46 :
47 : std::vector<float> ir_time_; // original IR (for direct convolution fallback)
48 :
49 : // Frequency-domain partitions: each is fft_size kiss_fft_cpx values
50 : std::vector<std::vector<char>> partitions_freq_; // raw storage
51 :
52 : kiss_fft_cfg fft_cfg_ = nullptr;
53 : };
54 :
55 : // =============================================================================
56 : // ConvolutionEngine — mutable state for the audio thread
57 : // =============================================================================
58 :
59 : class ConvolutionEngine {
60 : public:
61 : ConvolutionEngine();
62 : ~ConvolutionEngine();
63 :
64 : // Set the active kernel. Resets internal state if kernel changes.
65 : void set_kernel(const ConvolutionKernel* kernel);
66 :
67 : // Process a block of audio in-place.
68 : void process(float* buffer, int num_samples);
69 :
70 : // Reset all internal state.
71 : void reset();
72 :
73 6050 : bool has_kernel() const { return kernel_ != nullptr; }
74 :
75 : private:
76 : const ConvolutionKernel* kernel_ = nullptr;
77 :
78 : // Frequency-domain delay line (circular buffer of past input blocks in freq domain)
79 : std::vector<std::vector<char>> fdl_; // raw storage for kiss_fft_cpx arrays
80 : int fdl_index_ = 0;
81 :
82 : // Overlap-add tail from previous block
83 : std::vector<float> overlap_;
84 :
85 : // FFT workspace
86 : kiss_fft_cfg fft_cfg_ = nullptr; // forward
87 : kiss_fft_cfg ifft_cfg_ = nullptr; // inverse
88 :
89 : int current_fft_size_ = 0;
90 :
91 : // Preallocated FFT buffers (raw storage for kiss_fft_cpx arrays)
92 : // Kept here to avoid per-block allocations in the audio callback.
93 : std::vector<char> input_cpx_;
94 : std::vector<char> accum_cpx_;
95 : std::vector<char> ifft_out_cpx_;
96 :
97 : void init_fft(int fft_size);
98 : void cleanup_fft();
99 :
100 : // Direct time-domain convolution fallback
101 : void process_direct(float* buffer, int num_samples);
102 : std::vector<float> direct_input_; // scratch copy of input (allocation-free in callback)
103 : std::vector<float> direct_overlap_; // tail from direct convolution
104 : };
105 :
106 : } // namespace Amplitron
|