diff options
author | John Glover <glover.john@gmail.com> | 2011-07-08 18:06:21 +0100 |
---|---|---|
committer | John Glover <glover.john@gmail.com> | 2011-07-08 18:06:21 +0100 |
commit | d6073e01c933c77f1e2bc3c3fe1126d617003549 (patch) | |
tree | 695d23677c5b84bf3a0f88fbd4959b4f7cbc0e90 /src/loris/ReassignedSpectrum.C | |
parent | 641688b252da468eb374674a0dbaae1bbac70b2b (diff) | |
download | simpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.tar.gz simpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.tar.bz2 simpl-d6073e01c933c77f1e2bc3c3fe1126d617003549.zip |
Start adding Loris files
Diffstat (limited to 'src/loris/ReassignedSpectrum.C')
-rw-r--r-- | src/loris/ReassignedSpectrum.C | 746 |
1 files changed, 746 insertions, 0 deletions
diff --git a/src/loris/ReassignedSpectrum.C b/src/loris/ReassignedSpectrum.C new file mode 100644 index 0000000..0292905 --- /dev/null +++ b/src/loris/ReassignedSpectrum.C @@ -0,0 +1,746 @@ +/* + * This is the Loris C++ Class Library, implementing analysis, + * manipulation, and synthesis of digitized sounds using the Reassigned + * Bandwidth-Enhanced Additive Sound Model. + * + * Loris is Copyright (c) 1999-2010 by Kelly Fitz and Lippold Haken + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * ReassignedSpectrum.C + * + * Implementation of class Loris::ReassignedSpectrum. + * + * Kelly Fitz, 9 Dec 1999 + * loris@cerlsoundgroup.org + * + * http://www.cerlsoundgroup.org/Loris/ + * + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include "ReassignedSpectrum.h" +#include "Notifier.h" +#include "LorisExceptions.h" +#include <algorithm> // for std::transform(), others +#include <functional> // for bind1st, multiplies, etc. +#include <cstdlib> // for std::abs() +#include <numeric> // for std::accumulate() + +#include <cmath> // for M_PI (except when its not there), fmod, fabs +#if defined(HAVE_M_PI) && (HAVE_M_PI) + const double Pi = M_PI; +#else + const double Pi = 3.14159265358979324; +#endif + +// The old quadratic interpolation code is still around, in case +// we ever want to use it for comparison, Lemur used to use that. +#if defined(Like_Lemur) +#define USE_PARABOLIC_INTERPOLATION +#endif + +// define this symbol to compute the mixed phase derivative +#define COMPUTE_MIXED_PHASE_DERIVATIVE 1 + +// there's a lot of std in here, +// import the whole namespace, as ugly as that is. +using namespace std; + +// begin namespace +namespace Loris { + +static unsigned long nextPO2( unsigned long N ) +{ + return (unsigned long)ceil( log( double(N) ) / log( 2. ) ); +} + +// --------------------------------------------------------------------------- +// ReassignedSpectrum constructor +// --------------------------------------------------------------------------- +//! Construct a new instance using the specified short-time window. +//! Transform lengths are the smallest power of two greater than twice the +//! window length. +// +ReassignedSpectrum::ReassignedSpectrum( const std::vector< double > & window ) : + mMagnitudeTransform( 1 << ( 1 + nextPO2( window.size() ) ) ), + mCorrectionTransform( 1 << ( 1 + nextPO2( window.size() ) ) ) +{ + // Build and store the window functions. + buildReassignmentWindows( window ); + + debugger << "ReassignedSpectrum: length is " << mMagnitudeTransform.size() << endl; +} + +// --------------------------------------------------------------------------- +// ReassignedSpectrum constructor +// --------------------------------------------------------------------------- +//! Construct a new instance using the specified short-time window and +//! its time derivative. +//! Transform lengths are the smallest power of two greater than twice the +//! window length. +ReassignedSpectrum::ReassignedSpectrum( const std::vector< double > & window, + const std::vector< double > & windowDerivative ) : + mMagnitudeTransform( 1 << ( 1 + nextPO2( window.size() ) ) ), + mCorrectionTransform( 1 << ( 1 + nextPO2( window.size() ) ) ) +{ + // Build and store the window functions. + buildReassignmentWindows( window, windowDerivative ); + + debugger << "ReassignedSpectrum: length is " << mMagnitudeTransform.size() << endl; +} + + +// --------------------------------------------------------------------------- +// transform +// --------------------------------------------------------------------------- +//! Compute the reassigned Fourier transform of the samples on the half open +//! range [sampsBegin, sampsEnd), aligning sampCenter with the center of +//! the analysis window. +//! +//! \param sampsBegin pointer representing the beginning of +//! the (half-open) range of samples to transform +//! \param sampCenter the sample in the range that is to be +//! aligned with the center of the analysis window +//! \param sampsEnd pointer representing the end of +//! the (half-open) range of samples to transform +//! +//! \pre sampsBegin must not be past sampCenter +//! \pre sampsEnd must be past sampCenter +//! \post the transform buffers store the reassigned +//! short-time transform data for the specified +//! samples +// +void +ReassignedSpectrum::transform( const double * sampsBegin, + const double * sampCenter, + const double * sampsEnd ) +{ + if ( sampCenter < sampsBegin || sampCenter >= sampsEnd ) + { + Throw( InvalidArgument, "Invalid sample range boundaries." ); + } + + const long firstHalfWinLength = window().size() / 2; + const long secondHalfWinLength = (window().size() - 1) / 2; + + // ensure that samples outside the window are not used: + sampsBegin = std::max( sampsBegin, sampCenter - firstHalfWinLength ); + sampsEnd = std::min( sampsEnd, sampCenter + secondHalfWinLength + 1 ); + + // we will skip the beginning of the window + // only if pos is too close to the start of + // the buffer: + long winBeginOffset = 0; + if ( sampCenter - sampsBegin < (window().size() / 2) ) + { + winBeginOffset = (window().size() / 2) - ( sampCenter - sampsBegin ); + } + + // to get phase right, we will rotate the Fourier transform + // input by pos - sampsBegin samples: + long rotateBy = sampCenter - sampsBegin; + + // window and rotate input and compute normal transform: + // window the samples into the FT buffer: + FourierTransform::iterator it = + std::transform( sampsBegin, sampsEnd, mCplxWin_W_Wtd.begin() + winBeginOffset, + mMagnitudeTransform.begin(), std::multiplies< std::complex< double > >() ); + // fill the rest with zeros: + std::fill( it, mMagnitudeTransform.end(), 0. ); + // rotate to align phase: + std::rotate( mMagnitudeTransform.begin(), mMagnitudeTransform.begin() + rotateBy, mMagnitudeTransform.end() ); + + // compute transform: + mMagnitudeTransform.transform(); + + // compute the dual reassignment transform: + // window the samples into the reassignment FT buffer, + // using the complex-valued reassignment window: + it = std::transform( sampsBegin, sampsEnd, mCplxWin_Wd_Wt.begin() + winBeginOffset, + mCorrectionTransform.begin(), std::multiplies< std::complex<double> >() ); + // fill the rest with zeros: + std::fill( it, mCorrectionTransform.end(), 0. ); + // rotate to align phase: + std::rotate( mCorrectionTransform.begin(), mCorrectionTransform.begin() + rotateBy, mCorrectionTransform.end() ); + // compute the transform: + mCorrectionTransform.transform(); +} + +// --------------------------------------------------------------------------- +// size +// --------------------------------------------------------------------------- +//! Return the length of the Fourier transforms. +// +ReassignedSpectrum::size_type +ReassignedSpectrum::size( void ) const +{ + return mMagnitudeTransform.size(); +} + +// --------------------------------------------------------------------------- +// window +// --------------------------------------------------------------------------- +//! Return read access to the short-time window samples. +//! (Peers may need to know about the analysis window +//! or about the scale factors in introduces.) +// +const std::vector< double > & +ReassignedSpectrum::window( void ) const +{ + return mWindow; +} + +// --------------------------------------------------------------------------- +// circEvenPartAt - helper +// --------------------------------------------------------------------------- +// Extract the circular even part from Fourier transform data. +// Used for computing two real transforms using a single complex transform. +// +template< class TransformData > +static std::complex<double> +circEvenPartAt( const TransformData & td, long idx ) +{ + const long N = td.size(); + while( idx < 0 ) + { + idx += N; + } + while( idx >= N ) + { + idx -= N; + } + + long flip_idx; + if ( idx != 0 ) + { + flip_idx = N - idx; + } + else + { + flip_idx = idx; + } + + return 0.5*( td[idx] + std::conj( td[flip_idx] ) ); +} + +// --------------------------------------------------------------------------- +// circOddPartAt - helper +// --------------------------------------------------------------------------- +// Extract the circular odd part divided by j from Fourier transform data. +// Used for computing two real transforms using a single complex transform. +// +template< class TransformData > +static std::complex<double> +circOddPartAt( const TransformData & td, long idx ) +{ + const long N = td.size(); + while( idx < 0 ) + { + idx += N; + } + while( idx >= N ) + { + idx -= N; + } + + long flip_idx; + if ( idx != 0 ) + { + flip_idx = N - idx; + } + else + { + flip_idx = idx; + } + + /* + const std::complex<double> minus_j(0,-1); + std::complex<double> tra_part = minus_j * 0.5 * + ( td[idx] - std::conj( td[flip_idx] ) ); + */ + // can compute this without complex multiplies: + std::complex<double> tmp = td[idx] - std::conj( td[flip_idx] ); + return std::complex<double>( 0.5*tmp.imag(), -0.5*tmp.real() ); +} + +// --------------------------------------------------------------------------- +// frequencyCorrection +// --------------------------------------------------------------------------- +//! Compute the frequency correction at the specified frequency sample +//! using the method of Auger and Flandrin to evaluate the partial +//! derivative of spectrum phase w.r.t. time. +//! +//! Correction is computed in fractional frequency samples, because +//! that's the kind of frequency domain ramp we used on our window. +//! sample is the frequency sample index, the nominal component +//! frequency in samples. +// +// Parabolic interpolation can be tried too (see reassignedFrequency()) +// but it appears to give slightly worse results, for example, with +// a square wave. +// +double +ReassignedSpectrum::frequencyCorrection( long idx ) const +{ + std::complex<double> X_h = circEvenPartAt( mMagnitudeTransform, idx ); + std::complex<double> X_Dh = circEvenPartAt( mCorrectionTransform, idx ); + + double num = X_h.real() * X_Dh.imag() - + X_h.imag() * X_Dh.real(); + + double magSquared = std::norm( X_h ); + + // need to scale by the oversampling factor + double oversampling = (double)mCorrectionTransform.size() / mCplxWin_W_Wtd.size(); + return - oversampling * num / magSquared; +} + +// --------------------------------------------------------------------------- +// timeCorrection +// --------------------------------------------------------------------------- +//! Compute the time correction at the specified frequency sample +//! using the method of Auger and Flandrin to evaluate the partial +//! derivative of spectrum phase w.r.t. frequency. +//! +//! Correction is computed in fractional samples, because +//! that's the kind of ramp we used on our window. +// +double +ReassignedSpectrum::timeCorrection( long idx ) const +{ + std::complex<double> X_h = circEvenPartAt( mMagnitudeTransform, idx ); + std::complex<double> X_Th = circOddPartAt( mCorrectionTransform, idx ); + + double num = X_h.real() * X_Th.real() + + X_h.imag() * X_Th.imag(); + double magSquared = norm( X_h ); + + // No need to scale by the oversampling factor. + // No, seems to sound bad, why? + // (try alienthreat) + // double oversampling = (double)mCorrectionTransform.size() / mCplxWin_W_Wtd.size(); + return num / magSquared; +} + +// --------------------------------------------------------------------------- +// reassignedFrequency +// --------------------------------------------------------------------------- +//! Return the reassigned frequency in fractional frequency +//! samples computed at the specified transform index. +//! +//! \param idx the frequency sample at which to evaluate the +//! transform +// +double +ReassignedSpectrum::reassignedFrequency( long idx ) const +{ +#if ! defined(USE_PARABOLIC_INTERPOLATION) + + return double(idx) + frequencyCorrection( idx ); + +#else // defined(USE_PARABOLIC_INTERPOLATION) + + double dbLeft = 20. * log10( abs( circEvenPartAt( mMagnitudeTransform, idx-1 ) ) ); + double dbCandidate = 20. * log10( abs( circEvenPartAt( mMagnitudeTransform, idx ) ) ); + double dbRight = 20. * log10( abs( circEvenPartAt( mMagnitudeTransform, idx+1 ) ) ); + + double peakXOffset = 0.5 * (dbLeft - dbRight) / + (dbLeft - 2.0 * dbCandidate + dbRight); + + return idx + peakXOffset; + +#endif // defined USE_PARABOLIC_INTERPOLATION +} + +// --------------------------------------------------------------------------- +// reassignedTime +// --------------------------------------------------------------------------- +//! Return the reassigned time in fractional samples +//! computed at the specified transform index. +//! +//! \param idx the frequency sample at which to evaluate the +//! transform +// +double +ReassignedSpectrum::reassignedTime( long idx ) const +{ + return timeCorrection( idx ); +} + +// --------------------------------------------------------------------------- +// reassignedMagnitude +// --------------------------------------------------------------------------- +//! Return the spectrum magnitude (absolute) +//! computed at the specified transform index. +//! +//! \param idx the frequency sample at which to evaluate the +//! transform +// +double +ReassignedSpectrum::reassignedMagnitude( long idx ) const +{ +#if ! defined(USE_PARABOLIC_INTERPOLATION) + + // compute the nominal spectral amplitude by scaling + // the peak spectral sample: + return abs( circEvenPartAt( mMagnitudeTransform, idx ) ); + +#else // defined(USE_PARABOLIC_INTERPOLATION) + + // keep this parabolic interpolation computation around + // only for sake of comparison, it is unlikely to yield + // good results with bandwidth association: + double dbLeft = 20. * log10( abs( circEvenPartAt( mMagnitudeTransform, idx-1 ) ) ); + double dbCandidate = 20. * log10( abs( circEvenPartAt( mMagnitudeTransform, idx ) ) ); + double dbRight = 20. * log10( abs( circEvenPartAt( mMagnitudeTransform, idx+1 ) ) ); + + double peakXOffset = 0.5 * (dbLeft - dbRight) / + (dbLeft - 2.0 * dbCandidate + dbRight); + double dbmag = dbCandidate - 0.25 * (dbLeft - dbRight) * peakXOffset; + double x = pow( 10., 0.05 * dbmag ); + + return x; + +#endif // defined USE_PARABOLIC_INTERPOLATION +} + +// --------------------------------------------------------------------------- +// reassignedPhase +// --------------------------------------------------------------------------- +//! Return the phase in radians computed at the specified transform index. +//! The reassigned phase is shifted to account for the time +//! correction according to the corrected frequency. +//! +//! \param idx the frequency sample at which to evaluate the +//! transform +// +double +ReassignedSpectrum::reassignedPhase( long idx ) const +{ + double phase = arg( circEvenPartAt( mMagnitudeTransform, idx ) ); + + const double offsetTime = timeCorrection( idx ); + const double offsetFreq = frequencyCorrection( idx ); + + // adjust phase according to the frequency correction: + // first compute H(1): + // + // this seems like it would be a good idea, but in practice, + // it screws the phases up badly. + // Am I just correcting in the wrong direction? No, its + // something else. + // + // Seems like I had the slope way too big. Changed to compute + // the slope from H(1) of a rotated window, and now the slope + // is so small that it seems like there will never be any phase + // correction. + // + // Phase ought to be linear anyway, so I should just be + // able to use dumb old linear interpolation. + // offsetFreq is in fractional frequency samples + if ( offsetFreq > 0 ) + { + double nextphase = arg( circEvenPartAt( mMagnitudeTransform, idx+1 ) ); + double slope = nextphase - phase; + phase += offsetFreq * slope; + } + else + { + double prevphase = arg( circEvenPartAt( mMagnitudeTransform, idx-1 ) ); + double slope = phase - prevphase; + phase += offsetFreq * slope; + } + + + // adjust phase according to the time correction: + const double fracFreqSample = idx + offsetFreq; + phase += offsetTime * fracFreqSample * 2. * Pi / mMagnitudeTransform.size(); + + // NOTICE + // This could be pretty much anything -- a sample reassigned by a + // millisecond at 1000 Hz in a 1024 FFT at 44k sample rate is + // adjusted by 2Pi. + // + // What if the frequency estimate is bad? Corrupts the phase estimate too! + + return fmod( phase, 2. * Pi ); +} + +// --------------------------------------------------------------------------- +// convergence +// --------------------------------------------------------------------------- +//! Compute and return the convergence indicator, computed from the +//! mixed partial derivative of spectral phase, optionally used in +//! BW enhanced analysis as a convergence indicator. The convergence +//! value is on the range [0,1], 0 for a sinusoid, and 1 for an impulse. +//! +//! \param idx the frequency sample at which to evaluate the +//! transform +// +double +ReassignedSpectrum::convergence( long idx ) const +{ +#if defined(COMPUTE_MIXED_PHASE_DERIVATIVE) + + std::complex<double> X_h = circEvenPartAt( mMagnitudeTransform, idx ); + std::complex<double> X_Th = circOddPartAt( mCorrectionTransform, idx ); + std::complex<double> X_Dh = circEvenPartAt( mCorrectionTransform, idx ); + std::complex<double> X_TDh = circOddPartAt( mMagnitudeTransform, idx ); + + double term1 = (X_TDh * conj(X_h)).real() / norm( X_h ); + double term2 = ((X_Th * X_Dh) / (X_h * X_h)).real(); + + double scaleBy = 2. * Pi / mCplxWin_W_Wtd.size(); + + double bw = fabs( 1.0 + (scaleBy * (term1 - term2)) ); + bw = min( 1.0, bw ); + +#else + double bw = 0.; +#endif + + return bw; +} + +// --------------------------------------------------------------------------- +// subscript operator (deprecated) +// --------------------------------------------------------------------------- +// Included to support old code. +// The signature has changed, can no longer return a reference, +// but since the reference returned was const, this version should +// keep most old code working, if not all. +// +std::complex< double > +ReassignedSpectrum::operator[]( unsigned long idx ) const +{ + return circEvenPartAt( mMagnitudeTransform, idx ); +} + +// --------------------------------------------------------------------------- +// make_complex +// --------------------------------------------------------------------------- +// Function object for building complex numbers. +// +template <class T> +struct make_complex + : binary_function< T, T, std::complex<T> > +{ + std::complex<T> operator()(const T& re, const T& im) const + { + return std::complex<T>( re, im ); + } +}; + +// --------------------------------------------------------------------------- +// applyFreqRamp +// --------------------------------------------------------------------------- +// Adapted from the FrequencyReassignment constructor in Lemur 5. +// +// This function computes an estimate of the time derivative of the +// specified window function, scaled by N/2pi, appropriate for computing +// frequency reassignment. +// +static inline void applyFreqRamp( vector< double > & w ) +{ + // we're going to do the frequency-domain ramp + // by Fourier transforming the window, ramping, + // then transforming again. + // Use a transform exactly as long as the window. + // load, w/out rotation, and transform. + FourierTransform temp( w.size() ); + FourierTransform::iterator it = std::copy( w.begin(), w.end(), temp.begin() ); + std::fill( it, temp.end(), 0. ); + temp.transform(); + + // extract complex transform and multiply by + // a frequency (sample) ramp: + // (the frequency ramp goes from 0 to N/2 + // over the first half, then -N/2 to 0 over + // the second (aliased) half of the transform, + // and has to be scaled by the ratio of the + // transform lengths, so that k spans the length + // of the padded transforms, N) + for ( int k = 0 ; k < temp.size(); ++k ) + { + double x = (double)k; // to get type promotion right + if ( k < temp.size() / 2 ) + { + temp[ k ] *= x; + } + else + { + temp[ k ] *= ( x - temp.size() ); + } + } + + // invert the transform: + temp.transform(); + + // the DFT of a DFT gives the scaled and INDEX REVERSED + // sequence. See p. 539 of O and S. + // DFT( X[n] ) -- DFT --> Nx[ -k mod N ] + // + // seems that I want the imaginary part of the index-reversed + // transform scaled by the size of the transform: + std::reverse( temp.begin() + 1, temp.end() ); + for ( int i = 0; i < w.size(); ++i ) + { + w[i] = - imag( temp[i] ) / temp.size(); + } +} + +// --------------------------------------------------------------------------- +// applyTimeRamp +// --------------------------------------------------------------------------- +// Make a copy of mWindow scaled by a ramp from -N/2 to N/2 for computing +// time corrections in samples. +// +static inline void applyTimeRamp( vector< double > & w ) +{ + // the very center of the window should be scaled by 0., + // need a fractional value for even-length windows, a + // whole number for odd-length windows: + double offset = 0.5 * ( w.size() - 1 ); + for ( int k = 0 ; k < w.size(); ++k ) + { + w[ k ] *= ( k - offset ); + } +} + +// --------------------------------------------------------------------------- +// buildReassignmentWindows (private) +// --------------------------------------------------------------------------- +// Build a pair of complex-valued windows, one having the frequency-ramp +// (time-derivative) window in the real part and the time-ramp window in the +// imagnary part, and the other having the unmodified window in the real part +// and, if computing mixed deriviatives, the time-ramp time-derivative window +// in the imaginary part. +// +// Input is the unmodified window function. +// +void +ReassignedSpectrum::buildReassignmentWindows( const std::vector< double > & window ) +{ + mWindow.resize( window.size(), 0. ); + + // Scale the window so that the reported magnitudes + // are correct. + double winsum = std::accumulate( window.begin(), window.end(), 0. ); + std::transform( window.begin(), window.end(), mWindow.begin(), + std::bind1st( std::multiplies<double>(), 2/winsum ) ); + + + // Construct the ramped windows from the scaled window. + std::vector< double > tramp = mWindow; + applyTimeRamp( tramp ); + + std::vector< double > framp = mWindow; + applyFreqRamp( framp ); + + std::vector< double > tframp( mWindow.size(), 0. ); + +#if defined(COMPUTE_MIXED_PHASE_DERIVATIVE) + + // Do this only if we are computing the mixed + // partial derivative of phase, otherwise, leave + // that vector empty. + tframp = framp; + applyTimeRamp( tframp ); + +#endif + + // Copy the windows into real and imaginary parts of + // complex window vectors. + mCplxWin_W_Wtd.resize( mWindow.size(), 0. ); + mCplxWin_Wd_Wt.resize( mWindow.size(), 0. ); + + std::transform( framp.begin(), framp.end(), tramp.begin(), + mCplxWin_Wd_Wt.begin(), make_complex< double >() ); + + std::transform( mWindow.begin(), mWindow.end(), tframp.begin(), + mCplxWin_W_Wtd.begin(), make_complex< double >() ); +} + +// --------------------------------------------------------------------------- +// buildReassignmentWindows +// --------------------------------------------------------------------------- +// Build a pair of complex-valued windows, one having the frequency-ramp +// (time-derivative) window in the real part and the time-ramp window in the +// imagnary part, and the other having the unmodified window in the real part +// and, if computing mixed deriviatives, the time-ramp time-derivative window +// in the imaginary part. +// +// Input is the unmodified window function and its time derivative, so the +// DFT kludge is unnecessary. +// + +void +ReassignedSpectrum::buildReassignmentWindows( const std::vector< double > & window, + const std::vector< double > & windowDerivative ) +{ + + mWindow.resize( window.size(), 0. ); + + // Scale the windows so that the reported magnitudes + // are correct. + double winsum = std::accumulate( window.begin(), window.end(), 0. ); + std::transform( window.begin(), window.end(), mWindow.begin(), + std::bind1st( std::multiplies<double>(), 2/winsum ) ); + + + // The fancy frequency reassignment window needs to scale the + // time derivative window by N (its length) / 2pi, in addition + // to scaling by 2/winsum to match the amplitude scaling above. + const double fancyScale = windowDerivative.size() / ( winsum * Pi ); + std::vector< double > framp( windowDerivative.size(), 0 ); + std::transform( windowDerivative.begin(), windowDerivative.end(), framp.begin(), + std::bind1st( std::multiplies<double>(), fancyScale ) ); + + + // Construct the ramped windows from the scaled window. + std::vector< double > tramp = mWindow; + applyTimeRamp( tramp ); + + std::vector< double > tframp( mWindow.size(), 0. ); + +#if defined(COMPUTE_MIXED_PHASE_DERIVATIVE) + + // Do this only if we are computing the mixed + // partial derivative of phase, otherwise, leave + // that vector empty. + tframp = framp; + applyTimeRamp( tframp ); + +#endif + + // Copy the windows into real and imaginary parts of + // complex window vectors. + mCplxWin_W_Wtd.resize( mWindow.size(), 0. ); + mCplxWin_Wd_Wt.resize( mWindow.size(), 0. ); + + std::transform( framp.begin(), framp.end(), tramp.begin(), + mCplxWin_Wd_Wt.begin(), make_complex< double >() ); + + std::transform( mWindow.begin(), mWindow.end(), tframp.begin(), + mCplxWin_W_Wtd.begin(), make_complex< double >() ); +} + + +} // end of namespace Loris |