Don't leave the negative frequencies as 0 for inverse FFT
This commit is contained in:
@@ -266,8 +266,7 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo
|
|||||||
/* The iFFT'd response is scaled up by the number of bins, so apply the
|
/* The iFFT'd response is scaled up by the number of bins, so apply the
|
||||||
* inverse to the output mixing gain.
|
* inverse to the output mixing gain.
|
||||||
*/
|
*/
|
||||||
constexpr size_t m{ConvolveUpdateSize/2 + 1};
|
const float gain{slot->Params.Gain * (1.0f/float{ConvolveUpdateSize})};
|
||||||
const float gain{slot->Params.Gain * (1.0f/m)};
|
|
||||||
auto &chans = *mChans;
|
auto &chans = *mChans;
|
||||||
if(mChannels == FmtBFormat3D || mChannels == FmtBFormat2D)
|
if(mChannels == FmtBFormat3D || mChannels == FmtBFormat2D)
|
||||||
{
|
{
|
||||||
@@ -386,6 +385,12 @@ void ConvolutionState::process(const size_t samplesToDo,
|
|||||||
mFftBuffer[i] += *input * *filter;
|
mFftBuffer[i] += *input * *filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reconstruct the mirrored/negative frequencies to do a proper
|
||||||
|
* inverse FFT.
|
||||||
|
*/
|
||||||
|
for(size_t i{m};i < ConvolveUpdateSize;++i)
|
||||||
|
mFftBuffer[i] = std::conj(mFftBuffer[ConvolveUpdateSize-i]);
|
||||||
|
|
||||||
/* Apply iFFT to get the 1024 (really 1023) samples for output. The
|
/* Apply iFFT to get the 1024 (really 1023) samples for output. The
|
||||||
* 512 output samples are combined with the last output's 511
|
* 512 output samples are combined with the last output's 511
|
||||||
* second-half samples (and this output's second half is
|
* second-half samples (and this output's second half is
|
||||||
|
|||||||
@@ -226,15 +226,15 @@ void PshifterState::process(const size_t samplesToDo, const al::span<const Float
|
|||||||
|
|
||||||
mFftBuffer[k] = std::polar(mSynthesisBuffer[k].Amplitude, mSumPhase[k]);
|
mFftBuffer[k] = std::polar(mSynthesisBuffer[k].Amplitude, mSumPhase[k]);
|
||||||
}
|
}
|
||||||
/* Clear negative frequencies to recontruct the time-domain signal. */
|
for(size_t k{STFT_HALF_SIZE+1};k < STFT_SIZE;++k)
|
||||||
std::fill(mFftBuffer.begin()+STFT_HALF_SIZE+1, mFftBuffer.end(), complex_d{});
|
mFftBuffer[k] = std::conj(mFftBuffer[STFT_SIZE-k]);
|
||||||
|
|
||||||
/* Apply an inverse FFT to get the time-domain siganl, and accumulate
|
/* Apply an inverse FFT to get the time-domain siganl, and accumulate
|
||||||
* for the output with windowing.
|
* for the output with windowing.
|
||||||
*/
|
*/
|
||||||
complex_fft(mFftBuffer, 1.0);
|
complex_fft(mFftBuffer, 1.0);
|
||||||
for(size_t k{0u};k < STFT_SIZE;k++)
|
for(size_t k{0u};k < STFT_SIZE;k++)
|
||||||
mOutputAccum[k] += HannWindow[k]*mFftBuffer[k].real() * (2.0/STFT_HALF_SIZE/OVERSAMP);
|
mOutputAccum[k] += HannWindow[k]*mFftBuffer[k].real() * (2.0/STFT_SIZE/OVERSAMP);
|
||||||
|
|
||||||
/* Shift FIFO and accumulator. */
|
/* Shift FIFO and accumulator. */
|
||||||
fifo_iter = std::copy(mFIFO.begin()+STFT_STEP, mFIFO.end(), mFIFO.begin());
|
fifo_iter = std::copy(mFIFO.begin()+STFT_STEP, mFIFO.end(), mFIFO.begin());
|
||||||
|
|||||||
+8
-5
@@ -44,18 +44,21 @@ std::array<float,Uhj2Encoder::sFilterSize> GenerateFilter()
|
|||||||
*/
|
*/
|
||||||
constexpr complex_d c0{0.0, 1.0};
|
constexpr complex_d c0{0.0, 1.0};
|
||||||
constexpr complex_d c1{0.0, -1.0};
|
constexpr complex_d c1{0.0, -1.0};
|
||||||
constexpr size_t half_size{32768};
|
constexpr size_t fft_size{65536};
|
||||||
|
constexpr size_t half_size{fft_size / 2};
|
||||||
|
|
||||||
/* Generate a frequency domain impulse with a +90 degree phase offset. Keep
|
/* Generate a frequency domain impulse with a +90 degree phase offset.
|
||||||
* the mirrored frequencies clear for converting to the time domain.
|
* Reconstruct the mirrored frequencies to convert to the time domain.
|
||||||
*/
|
*/
|
||||||
auto fftBuffer = std::vector<complex_d>(half_size*2, complex_d{});
|
auto fftBuffer = std::vector<complex_d>(fft_size, complex_d{});
|
||||||
for(size_t i{0};i < half_size;i += 2)
|
for(size_t i{0};i < half_size;i += 2)
|
||||||
{
|
{
|
||||||
fftBuffer[i ] = c0;
|
fftBuffer[i ] = c0;
|
||||||
fftBuffer[i+1] = c1;
|
fftBuffer[i+1] = c1;
|
||||||
}
|
}
|
||||||
fftBuffer[half_size] = c0;
|
fftBuffer[half_size] = c0;
|
||||||
|
for(size_t i{half_size+1};i < fft_size;++i)
|
||||||
|
fftBuffer[i] = std::conj(fftBuffer[fft_size - i]);
|
||||||
complex_fft(fftBuffer, 1.0);
|
complex_fft(fftBuffer, 1.0);
|
||||||
|
|
||||||
/* Reverse and truncate the filter to a usable size, and store only the
|
/* Reverse and truncate the filter to a usable size, and store only the
|
||||||
@@ -65,7 +68,7 @@ std::array<float,Uhj2Encoder::sFilterSize> GenerateFilter()
|
|||||||
auto fftiter = fftBuffer.data() + half_size + (Uhj2Encoder::sFilterSize-1);
|
auto fftiter = fftBuffer.data() + half_size + (Uhj2Encoder::sFilterSize-1);
|
||||||
for(float &coeff : ret)
|
for(float &coeff : ret)
|
||||||
{
|
{
|
||||||
coeff = static_cast<float>(fftiter->real() / (half_size+1));
|
coeff = static_cast<float>(fftiter->real() / double{fft_size});
|
||||||
fftiter -= 2;
|
fftiter -= 2;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user