Files
soothe2-re/dsp/spectral.hpp
T
Matiq 575d26a771 STFT partitioned conv: FIR construction pipeline (52b550-52b8bb)
Implement minimum-phase FIR design from BLOCKMAP:
- buildFirFromMask: mask → 1/mask (reciprocal via log→negate→exp) →
  IFFT → causal window → FFT → normalize → complex multiply
- RT_FIRCONV=2 activates the new path
- RT_FIRCONV=1 preserved as simple mask × audio (legacy)

Results (tone1kq single band):
  default (pointwise):  500Hz=-25.35 dB, 1kHz=-50.60 dB
  FIRCONV=1 (mask mul): 500Hz=-1.31 dB, 1kHz=-25.92 dB
  FIRCONV=2 (min-phase): same as FIRCONV=1

The twiddle stages (ops B/C/D with cos/sin tables) are the missing
piece for bit-exact FIR construction. They perform FMA operations
with twiddle factors that modify the mask shape.

Note: dual_b1q_0.5.wav reference is empty (0 bytes) — corpus can't run.
Needs regeneration.
2026-08-27 06:13:18 +03:00

51 lines
1.6 KiB
C++

#pragma once
#include <cstddef>
#include <cstdint>
#include <complex>
#include <vector>
#include "fft.hpp"
#include "framed_model.hpp"
constexpr size_t DEFAULT_NFFT = 2048;
constexpr size_t DEFAULT_HOP = 512;
class SpectralProcessor {
public:
SpectralProcessor(size_t nfft = DEFAULT_NFFT, size_t hop = DEFAULT_HOP,
float sample_rate = 44100.0f);
~SpectralProcessor();
void setDetectorParams(const std::vector<DetectorBand>& bands);
void processBlock(float* in, float* out, size_t num_samples, size_t num_channels = 1);
private:
size_t nfft_;
size_t hop_;
double* window_;
FFTPlan plan_;
std::complex<double>* buf_;
std::complex<double>* tmp_buf_;
std::complex<double>* fir_buf_;
std::complex<double>* fir_freq_;
std::vector<double> fir_window_;
std::vector<float> overlap_;
std::vector<float> mask_;
FramedDetector detector_;
size_t frame_count_;
size_t output_pos_;
void computeWindow();
void stftFrame(const float* in, std::complex<double>* out);
void istftFrame(std::complex<double>* in, float* out, float* overlap);
// FIR construction from detector mask (52b550-52b8bb pipeline):
// mask → log → sign-invert → EXP → twiddle ops → window → normalize
// Produces frequency-domain FIR kernel for complex multiply application.
void buildFirFromMask(const float* mask, std::complex<double>* fir, size_t nbin);
// WIN_freq: live-captured freq-path window (0x540658), 0.5→1.0
std::vector<float> win_freq_;
bool win_freq_loaded_ = false;
void loadWinFreq();
};