SpectMorph
smifftsynth.hh
1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.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 class 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 
58  double quantized_freq (double freq);
59 };
60 
62 {
63  std::vector<float> win_trans;
64 
65  float *win_scale;
66 };
67 
68 inline void
69 IFFTSynth::render_partial (double mf_freq, double mag, double phase)
70 {
71  const int range = 4;
72 
73  const int freq256 = sm_round_positive (mf_freq * freq256_factor);
74  const int ibin = freq256 >> 8;
75  float *sp = fft_in + 2 * (ibin - range);
76  const float *wmag_p = &table->win_trans[(freq256 & 0xff) * (range * 2 + 1)];
77 
78  const float nmag = mag * mag_norm;
79 
80  // rotation for initial phase; scaling for magnitude
81 
82  /* the following block computes sincos (phase + phase_adjust) */
83  int iarg = sm_round_positive (phase * (SIN_TABLE_SIZE / (2 * M_PI)));
84 
85  // adjust phase to get the same output like vector sin (smmath.hh)
86  // phase_adjust = freq256 * (M_PI / 256.0) - M_PI / 2;
87  int iphase_adjust = freq256 * SIN_TABLE_SIZE / 512 + (SIN_TABLE_SIZE - SIN_TABLE_SIZE / 4);
88  iarg += iphase_adjust;
89 
90  const float phase_rsmag = sin_table [iarg & SIN_TABLE_MASK] * nmag;
91  iarg += SIN_TABLE_SIZE / 4;
92  const float phase_rcmag = sin_table [iarg & SIN_TABLE_MASK] * nmag;
93 
94  /* compute FFT spectrum modifications */
95  if (ibin > range && 2 * (ibin + range) < static_cast<int> (block_size))
96  {
97  for (int i = 0; i <= 2 * range; i++)
98  {
99  const float wmag = wmag_p[i];
100  *sp++ += phase_rcmag * wmag;
101  *sp++ += phase_rsmag * wmag;
102  }
103  }
104  else
105  {
106  wmag_p += range; // allow negative addressing
107  for (int i = -range; i <= range; i++)
108  {
109  const float wmag = wmag_p[i];
110  if ((ibin + i) < 0)
111  {
112  fft_in[-(ibin + i) * 2] += phase_rcmag * wmag;
113  fft_in[-(ibin + i) * 2 + 1] -= phase_rsmag * wmag;
114  }
115  else if ((ibin + i) == 0)
116  {
117  fft_in[0] += 2 * phase_rcmag * wmag;
118  }
119  else if (2 * (ibin + i) == static_cast<int> (block_size))
120  {
121  fft_in[1] += 2 * phase_rcmag * wmag;
122  }
123  else if (2 * (ibin + i) > static_cast<int> (block_size))
124  {
125  int p = block_size - (2 * (ibin + i) - block_size);
126 
127  fft_in[p] += phase_rcmag * wmag;
128  fft_in[p + 1] -= phase_rsmag * wmag;
129  }
130  else // no corner case
131  {
132  fft_in[(ibin + i) * 2] += phase_rcmag * wmag;
133  fft_in[(ibin + i) * 2 + 1] += phase_rsmag * wmag;
134  }
135  }
136  }
137 }
138 
139 }
140 
141 #endif
Definition: smifftsynth.hh:61
Definition: smifftsynth.hh:15
Definition: smalignedarray.cc:7