SpectMorph
smifftsynth.hh
1 // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl-2.1.html
2 
3 #ifndef SPECTMORPH_IFFT_SYNTH_HH
4 #define SPECTMORPH_IFFT_SYNTH_HH
5 
6 #include <sys/types.h>
7 #include <vector>
8 
9 #include "smmath.hh"
10 
11 namespace SpectMorph {
12 
13 struct IFFTSynthTable;
14 
15 class IFFTSynth
16 {
17  IFFTSynthTable *table;
18 
19  int zero_padding;
20  size_t block_size;
21  double mix_freq;
22  double freq256_factor;
23  double mag_norm;
24 
25  float *fft_in;
26  float *fft_out;
27  float *win_scale;
28 
29  enum {
30  SIN_TABLE_SIZE = 4096,
31  SIN_TABLE_MASK = 4095
32  };
33 
34  static std::vector<float> sin_table;
35 
36 public:
37  enum WindowType { WIN_BLACKMAN_HARRIS_92, WIN_HANNING };
38  enum OutputMode { REPLACE, ADD };
39 
40  IFFTSynth (size_t block_size, double mix_freq, WindowType win_type);
41  ~IFFTSynth();
42 
43  void
44  clear_partials()
45  {
46  zero_float_block (block_size, fft_in);
47  }
48 
49  float*
50  fft_buffer()
51  {
52  return fft_in;
53  }
54 
55  inline void render_partial (double freq, double mag, double phase);
56  void get_samples (float *samples, OutputMode output_mode = REPLACE);
57  void precompute_tables();
58 
59  double quantized_freq (double freq);
60 };
61 
63 {
64  std::vector<float> win_trans;
65 
66  float *win_scale;
67 };
68 
69 inline void
70 IFFTSynth::render_partial (double mf_freq, double mag, double phase)
71 {
72  const int range = 4;
73 
74  const int freq256 = sm_round_positive (mf_freq * freq256_factor);
75  const int ibin = freq256 >> 8;
76  float *sp = fft_in + 2 * (ibin - range);
77  const float *wmag_p = &table->win_trans[(freq256 & 0xff) * (range * 2 + 1)];
78 
79  const float nmag = mag * mag_norm;
80 
81  // rotation for initial phase; scaling for magnitude
82 
83  /* the following block computes sincos (phase + phase_adjust) */
84  int iarg = sm_round_positive (phase * (SIN_TABLE_SIZE / (2 * M_PI)));
85 
86  // adjust phase to get the same output like vector sin (smmath.hh)
87  // phase_adjust = freq256 * (M_PI / 256.0) - M_PI / 2;
88  int iphase_adjust = freq256 * SIN_TABLE_SIZE / 512 + (SIN_TABLE_SIZE - SIN_TABLE_SIZE / 4);
89  iarg += iphase_adjust;
90 
91  const float phase_rsmag = sin_table [iarg & SIN_TABLE_MASK] * nmag;
92  iarg += SIN_TABLE_SIZE / 4;
93  const float phase_rcmag = sin_table [iarg & SIN_TABLE_MASK] * nmag;
94 
95  /* compute FFT spectrum modifications */
96  if (ibin > range && 2 * (ibin + range) < static_cast<int> (block_size))
97  {
98  for (int i = 0; i <= 2 * range; i++)
99  {
100  const float wmag = wmag_p[i];
101  *sp++ += phase_rcmag * wmag;
102  *sp++ += phase_rsmag * wmag;
103  }
104  }
105  else
106  {
107  wmag_p += range; // allow negative addressing
108  for (int i = -range; i <= range; i++)
109  {
110  const float wmag = wmag_p[i];
111  if ((ibin + i) < 0)
112  {
113  fft_in[-(ibin + i) * 2] += phase_rcmag * wmag;
114  fft_in[-(ibin + i) * 2 + 1] -= phase_rsmag * wmag;
115  }
116  else if ((ibin + i) == 0)
117  {
118  fft_in[0] += 2 * phase_rcmag * wmag;
119  }
120  else if (2 * (ibin + i) == static_cast<int> (block_size))
121  {
122  fft_in[1] += 2 * phase_rcmag * wmag;
123  }
124  else if (2 * (ibin + i) > static_cast<int> (block_size))
125  {
126  int p = block_size - (2 * (ibin + i) - block_size);
127 
128  fft_in[p] += phase_rcmag * wmag;
129  fft_in[p + 1] -= phase_rsmag * wmag;
130  }
131  else // no corner case
132  {
133  fft_in[(ibin + i) * 2] += phase_rcmag * wmag;
134  fft_in[(ibin + i) * 2 + 1] += phase_rsmag * wmag;
135  }
136  }
137  }
138 }
139 
140 }
141 
142 #endif
Definition: smifftsynth.hh:16
Definition: smifftsynth.hh:63