📄 taudiofilterconvolver.cpp
字号:
/*
* Copyright (c) 2005,2006 Milan Cutka
* based on jack_convolve by Florian Schmidt
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "stdafx.h"
#include "TaudioFilterConvolver.h"
#include "fftsg.h"
#include "ffdebug.h"
#include "resample/resample2.h"
TaudioFilterConvolver::TaudioFilterConvolver(IffdshowBase *Ideci,Tfilters *Iparent):TaudioFilter(Ideci,Iparent)
{
}
//==================== TaudioFilterConvolver::Tconvolver::fft_response_t ========================
void TaudioFilterConvolver::Tconvolver::fft_response_t::init(const TwavReader<float> &response,const TconvolverSettings *cfg,unsigned int chunk_length,float normalization_factor,Tfftforward &fft_plan_forward,unsigned int procchannel)
{
float levelAdjust=cfg->levelAdjustAuto?response.getAdjust():db2value((float)cfg->levelAdjustDB,10);
// create new response struct
length=response[0].size();
// make channel_data array big enough to hold pointers for all channels
size_t number_of_response_channels=procchannel!=INT32_MAX?1:response.size();
channel_data.resize(number_of_response_channels);
// how many chunks do we need for this response?
number_of_chunks = (unsigned int)ceil((response[0].size())/(float)(chunk_length));
// allocate per channel data buffer)
// no need for double size, as we use r2c/c2r
for (unsigned int index2 = 0; index2 < number_of_response_channels; ++index2)
channel_data[index2].resize( (chunk_length + 1) * number_of_chunks);
// for each channel
std::vector<float> fft_real(2*chunk_length);
std::vector<complex> fft_complex(chunk_length+1);
for (unsigned int index2 = 0; index2 < number_of_response_channels; ++index2)
{
unsigned int respchannel=procchannel!=INT32_MAX?std::min(response.nchannels-1,procchannel):index2;
// for each chunk
for (unsigned int index3 = 0; index3 < number_of_chunks; ++index3)
{
// copy original chunk to fft_real
for (unsigned int index4 = 0; index4 < chunk_length; ++index4)
{
if (index4 + index3 * chunk_length < length)
fft_real[index4] = response[respchannel][index4+index3*chunk_length]*levelAdjust;
else
fft_real[index4] = 0;
// and zero pad the second half of the chunk at the same time
fft_real[index4+chunk_length] = 0;
}
// do the fft
fft_plan_forward.execute(&fft_real[0],&fft_complex[0]);
// copy fft output to our private chunk store :)
for (unsigned int index4 = 0; index4 < chunk_length + 1; ++index4)
channel_data[index2][index4+index3 * (chunk_length + 1)]= complex(fft_complex[index4].real() / normalization_factor, fft_complex[index4].imag() / normalization_factor);
}
}
}
static unsigned int getNextPower2(unsigned int l)
{
int num=1<<(av_log2(l)+2);
return num;
}
//============================== TaudioFilterConvolver::Tconvolver ==============================
TaudioFilterConvolver::Tconvolver::Tconvolver(const TsampleFormat &infmt,const TwavReader<float> &response,const TconvolverSettings *cfg,unsigned int procchannel):
chunk_length(getNextPower2((unsigned int)response[0].size())),
number_of_responses(1),
fft_plan_forward(2*getNextPower2((unsigned int)response[0].size())),
fft_plan_backward(2*getNextPower2((unsigned int)response[0].size())),
fft_real(2*getNextPower2((unsigned int)response[0].size())),
fft_complex(getNextPower2((unsigned int)response[0].size())+1),
fft_responses(1),
input_chunk_ringbuffers(1)
{
number_of_response_channels=procchannel!=INT32_MAX?1:response.nchannels;
normalization_factor=sqrt(chunk_length * 2.0f);
// -------------- chunk, pad, fft and store the responses
// allocate array of response pointers
// process input responses to padded, chunked, fft'ed internal representation
//for (unsigned int index=0;index<number_of_responses;++index)
fft_responses[0].init(response,cfg,chunk_length,normalization_factor,fft_plan_forward,procchannel);
// ------------- setup ringbuffers for storing FFT'ed input..
// the chunks are size chunk_length + 1 thus
// we need number_of_chunks * (chunk_length + 1)
// frames
// one for each response
for (unsigned int index = 0; index < number_of_responses; ++index)
{
input_chunk_ringbuffers[index].resize(fft_responses[index].number_of_chunks * (chunk_length + 1));
// zero out
for (unsigned int index2 = 0; index2 < (chunk_length + 1) * fft_responses[index].number_of_chunks; ++index2)
input_chunk_ringbuffers[index][index2]=0;
}
// allocate input_chunk_ringbuffer_index arrays
input_chunk_ringbuffer_indexes.resize(number_of_responses);
// zero out
for (unsigned int index = 0; index < number_of_responses; ++index)
input_chunk_ringbuffer_indexes[index] = 0;
// ---------------- setup overlap buffers
// these need only be chunk_length sized
overlap_buffers.resize(number_of_response_channels);
for (unsigned int index = 0; index < number_of_response_channels; ++index)
{
overlap_buffers[index].resize(chunk_length);
// zero out
for (unsigned int index2 = 0; index2 < chunk_length; ++index2)
overlap_buffers[index][index2] = 0;
}
if (procchannel!=INT32_MAX)
{
in_channels=out_channels=infmt.nchannels;
in_channel[0]=out_channel[0]=procchannel;
}
else
{
in_channels=infmt.nchannels;
for (unsigned int i=0;i<number_of_response_channels;i++)
in_channel[i]=number_of_response_channels%in_channels;
out_channels=number_of_response_channels;
for (unsigned int i=0;i<number_of_response_channels;i++)
out_channel[i]=i;
}
}
int TaudioFilterConvolver::Tconvolver::process(const float * const in_data,float *out_data,size_t numsamples,const TconvolverSettings *cfg)
{
float mixingStrength=cfg->mixingStrength/100.0f,mixingStrengthInv=1.0f-mixingStrength;
int samplesPtr=0;
for (;samplesPtr<int(numsamples-chunk_length);samplesPtr+=chunk_length)
{
for (unsigned int index = 0; index < number_of_responses; ++index)
{
// copy input chunk into fft_real
for (unsigned int index2 = 0; index2 < chunk_length; ++index2)
{
fft_real[index2] = in_data[in_channel[0]+in_channels*(index2+samplesPtr)];//in_data[index][index2];
// and pad at the same time
fft_real[index2+chunk_length] = 0;
}
// do the fft
fft_plan_forward.execute(&fft_real[0],&fft_complex[0]);
// copy output into input_chunks ringbuffers
for (unsigned int index2 = 0; index2 < chunk_length + 1; ++index2)
input_chunk_ringbuffers[index][index2 + input_chunk_ringbuffer_indexes[index]]=complex(fft_complex[index2].real() / normalization_factor, fft_complex[index2].imag() / normalization_factor);
}
// do the complex multiplications for all response input channels
for (unsigned int index = 0; index < number_of_response_channels; ++index)
{
// zero our the reverse fft input buffer
for (unsigned int index2 = 0; index2 < chunk_length + 1; ++index2)
fft_complex[index2]=0;
// for all responses (of this output channel)
for (unsigned int index2 = 0; index2 < number_of_responses; ++index2)
{
// for all chunks
for (unsigned int index3 = 0; index3 < fft_responses[index2].number_of_chunks; ++index3)
{
// we go backward in time (from current chunk in input_chunnks_ringbuffers[] to oldest)
int tmp_rb_chunk_index = input_chunk_ringbuffer_indexes[index2]
- (index3 * (chunk_length + 1))
+ ((chunk_length + 1) * fft_responses[index2].number_of_chunks);
// constraint to the actual data length ("%")
tmp_rb_chunk_index %= (chunk_length + 1) * fft_responses[index2].number_of_chunks;
complex_mul(&input_chunk_ringbuffers[index2][tmp_rb_chunk_index],
&fft_responses[index2].channel_data[index][index3 * (chunk_length + 1)],
&fft_complex[0],
chunk_length + 1);
} // chunks
} // responses
// reverse fft the results
fft_plan_backward.execute(&fft_complex[0],&fft_real[0]);
// copy to out_buffers, save overlap and add previous overlap
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -