1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2
3 #include "smifftsynth.hh"
4 #include "smmath.hh"
5 #include "smfft.hh"
6 #include "smblockutils.hh"
7 #include <assert.h>
8 #include <stdio.h>
9
10 #include <map>
11
12 using namespace SpectMorph;
13
from_hex_nibble(char c)14 using std::vector;
15 using std::map;
16
17 static map<size_t, IFFTSynthTable *> table_for_block_size;
18
19 namespace SpectMorph {
20 vector<float> IFFTSynth::sin_table;
21 }
22
23 IFFTSynth::IFFTSynth (size_t block_size, double mix_freq, WindowType win_type) :
24 block_size (block_size),
25 mix_freq (mix_freq)
decode(const string & str,vector<unsigned char> & out)26 {
27 zero_padding = 256;
28
29 table = table_for_block_size[block_size];
30 if (!table)
31 {
32 const int range = 4;
33
34 table = new IFFTSynthTable();
35
36 const size_t win_size = block_size * zero_padding;
37 float *win = FFT::new_array_float (win_size);
38 float *wspectrum = FFT::new_array_float (win_size);
39
40 std::fill (win, win + win_size, 0); // most of it should be zero due to zeropadding
41 for (size_t i = 0; i < block_size; i++)
42 {
43 if (i < block_size / 2)
44 win[i] = window_blackman_harris_92 (double (block_size / 2 - i) / block_size * 2 - 1.0);
45 else
46 win[win_size - block_size + i] = window_blackman_harris_92 (double (i - block_size / 2) / block_size * 2 - 1.0);
47 }
48
49 FFT::fftar_float (block_size * zero_padding, win, wspectrum, FFT::PLAN_ESTIMATE);
50
51 // compute complete (symmetric) expanded window transform for all frequency fractions
52 for (int freq_frac = 0; freq_frac < zero_padding; freq_frac++)
53 {
54 for (int i = -range; i <= range; i++)
55 {
56 int pos = i * 256 - freq_frac;
57 table->win_trans.push_back (wspectrum[abs (pos * 2)]);
58 }
59 }
60 FFT::free_array_float (win);
61 FFT::free_array_float (wspectrum);
62
63 table->win_scale = FFT::new_array_float (block_size); // SSE
64 for (size_t i = 0; i < block_size; i++)
65 table->win_scale[(i + block_size / 2) % block_size] = window_cos (2.0 * i / block_size - 1.0) / window_blackman_harris_92 (2.0 * i / block_size - 1.0);
66
67 // we only need to do this once per block size (FIXME: not thread safe yet)
68 table_for_block_size[block_size] = table;
69 }
70 if (sin_table.empty())
71 {
72 // sin() table
73 sin_table.resize (SIN_TABLE_SIZE);
74 for (size_t i = 0; i < SIN_TABLE_SIZE; i++)
75 sin_table[i] = sin (i * 2 * M_PI / SIN_TABLE_SIZE);
76 }
77
78 if (win_type == WIN_BLACKMAN_HARRIS_92)
79 win_scale = NULL;
80 else
81 win_scale = table->win_scale;
82
83 fft_in = FFT::new_array_float (block_size);
84 fft_out = FFT::new_array_float (block_size);
85 freq256_factor = 1 / mix_freq * block_size * zero_padding;
86 mag_norm = 0.5 / block_size;
87 }
88
89 IFFTSynth::~IFFTSynth()
90 {
91 FFT::free_array_float (fft_in);
92 FFT::free_array_float (fft_out);
93 }
94
95 void
96 IFFTSynth::get_samples (float *samples,
97 OutputMode output_mode)
98 {
99 FFT::fftsr_destructive_float (block_size, fft_in, fft_out);
100
101 if (win_scale)
102 Block::mul (block_size, fft_out, win_scale);
103
104 if (output_mode == REPLACE)
105 {
106 memcpy (samples, &fft_out[block_size / 2], sizeof (float) * block_size / 2);
107 memcpy (&samples[block_size / 2], fft_out, sizeof (float) * block_size / 2);
108 }
109 else if (output_mode == ADD)
110 {
111 Block::add (block_size / 2, samples, fft_out + block_size / 2);
112 Block::add (block_size / 2, samples + block_size / 2, fft_out);
113 }
114 else
115 {
116 assert (false);
117 }
118 }
119
120 double
121 IFFTSynth::quantized_freq (double mf_freq)
122 {
123 const int freq256 = sm_round_positive (mf_freq * freq256_factor);
124 const double qfreq = freq256 * (1 / 256.0);
125 const double mf_qfreq = qfreq / block_size * mix_freq;
126
127 return mf_qfreq;
128 }
129