SpectMorph

lib/smifftsynth.hh

00001 /*
00002  * Copyright (C) 2010 Stefan Westerfeld
00003  *
00004  * This library is free software; you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License as published by the
00006  * Free Software Foundation; either version 3 of the License, or (at your
00007  * option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful, but WITHOUT
00010  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
00012  * for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 
00019 #ifndef SPECTMORPH_IFFT_SYNTH_HH
00020 #define SPECTMORPH_IFFT_SYNTH_HH
00021 
00022 #include <sys/types.h>
00023 #include <vector>
00024 
00025 #include "smmath.hh"
00026 
00027 namespace SpectMorph {
00028 
00029 class IFFTSynthTable;
00030 
00031 class IFFTSynth
00032 {
00033   IFFTSynthTable    *table;
00034 
00035   int                zero_padding;
00036   size_t             block_size;
00037   double             mix_freq;
00038   double             freq256_factor;
00039   double             mag_norm;
00040 
00041   float             *fft_in;
00042   float             *fft_out;
00043   float             *win_scale;
00044 
00045   enum { 
00046     SIN_TABLE_SIZE = 4096,
00047     SIN_TABLE_MASK = 4095
00048   };
00049 
00050   static std::vector<float> sin_table;
00051 
00052 public:
00053   enum WindowType { WIN_BLACKMAN_HARRIS_92, WIN_HANNING };
00054   enum OutputMode { REPLACE, ADD };
00055 
00056   IFFTSynth (size_t block_size, double mix_freq, WindowType win_type);
00057   ~IFFTSynth();
00058 
00059   void
00060   clear_partials()
00061   {
00062     zero_float_block (block_size, fft_in);
00063   }
00064 
00065   float*
00066   fft_buffer()
00067   {
00068     return fft_in;
00069   }
00070 
00071   inline void render_partial (double freq, double mag, double phase);
00072   void get_samples (float *samples, OutputMode output_mode = REPLACE);
00073 
00074   double quantized_freq (double freq);
00075 };
00076 
00077 struct IFFTSynthTable
00078 {
00079   std::vector<float> win_trans;
00080 
00081   float             *win_scale;
00082 };
00083 
00084 inline void
00085 IFFTSynth::render_partial (double mf_freq, double mag, double phase)
00086 {
00087   const int range = 4;
00088 
00089   const int freq256 = sm_round_positive (mf_freq * freq256_factor);
00090   const int ibin = freq256 >> 8;
00091   float *sp = fft_in + 2 * (ibin - range);
00092   const float *wmag_p = &table->win_trans[(freq256 & 0xff) * (range * 2 + 1)];
00093 
00094   const float nmag = mag * mag_norm;
00095 
00096   // rotation for initial phase; scaling for magnitude
00097 
00098   /* the following block computes sincos (phase + phase_adjust) */
00099   int iarg = sm_round_positive (phase * (SIN_TABLE_SIZE / (2 * M_PI)));
00100 
00101   // adjust phase to get the same output like vector sin (smmath.hh)
00102   // phase_adjust = freq256 * (M_PI / 256.0) - M_PI / 2;
00103   int iphase_adjust = freq256 * SIN_TABLE_SIZE / 512 + (SIN_TABLE_SIZE - SIN_TABLE_SIZE / 4);
00104   iarg += iphase_adjust;
00105 
00106   const float phase_rsmag = sin_table [iarg & SIN_TABLE_MASK] * nmag;
00107   iarg += SIN_TABLE_SIZE / 4;
00108   const float phase_rcmag = sin_table [iarg & SIN_TABLE_MASK] * nmag;
00109 
00110   /* compute FFT spectrum modifications */
00111   if (ibin > range && 2 * (ibin + range) < static_cast<int> (block_size))
00112     {
00113       for (int i = 0; i <= 2 * range; i++)
00114         {
00115           const float wmag = wmag_p[i];
00116           *sp++ += phase_rcmag * wmag;
00117           *sp++ += phase_rsmag * wmag;
00118         }
00119     }
00120   else
00121     {
00122       wmag_p += range; // allow negative addressing
00123       for (int i = -range; i <= range; i++)
00124         {
00125           const float wmag = wmag_p[i];
00126           if ((ibin + i) < 0)
00127             {
00128               fft_in[-(ibin + i) * 2] += phase_rcmag * wmag;
00129               fft_in[-(ibin + i) * 2 + 1] -= phase_rsmag * wmag;
00130             }
00131           else if ((ibin + i) == 0)
00132             {
00133               fft_in[0] += 2 * phase_rcmag * wmag;
00134             }
00135           else if (2 * (ibin + i) == static_cast<int> (block_size))
00136             {
00137               fft_in[1] += 2 * phase_rcmag * wmag;
00138             }
00139           else if (2 * (ibin + i) > static_cast<int> (block_size))
00140             {
00141               int p = block_size - (2 * (ibin + i) - block_size);
00142 
00143               fft_in[p] += phase_rcmag * wmag;
00144               fft_in[p + 1] -= phase_rsmag * wmag;
00145             }
00146           else // no corner case
00147             {
00148               fft_in[(ibin + i) * 2] += phase_rcmag * wmag;
00149               fft_in[(ibin + i) * 2 + 1] += phase_rsmag * wmag;
00150             }
00151         }
00152     }
00153 }
00154 
00155 }
00156 
00157 #endif
 All Classes Functions Variables Enumerations Enumerator