Thanks Giulio, I tried again but still no luck.
What I'm concerned about isn't just the first two loops in process_fft()
but also the FFT conversion of the impulse response. The IR frequency domain bins do not need to change for the duration of the program. I want to convert the IR from time to frequency domain in setup and somehow be able to access that in process_fft()
instead of continually doing work that has already been done.
Here is the code this minute, though it keeps changing as I'm trying it a million different ways!
static std::vector<float> gIRmask(gIRsize); // IR time domain
static std::vector<float> gIRfdr(gFftSize); // IR frequency domain real
static std::vector<float> gIRfdi(gFftSize); // IR frequency domain imaginary
bool setup(BelaContext *context, void *userData)
{
// Boring bits
rt_printf("IR length %i", gIRsize);
gScope.setup(2, context->audioSampleRate);
gui.setup(context->projectName);
controller.setup(&gui, "Controls");
gainSliderIdx = controller.addSlider("Gain", 0.0001, 0.0001, 3, 0.001);
winShiftSliderIdx=controller.addSlider("WinShift", 0.0, -2, 2, 0.25);
// Load IR file
if(!gIRplayer.setup(gIRfilename)) {
rt_printf("Error loading audio file '%s'\n", gIRfilename.c_str());
return false;
}
// Copy IR to static vector and pad to FFT size
for(int n=0; n < gFftSize; n++) {
if (n==0) gIRplayer.trigger();
if (n<gIRsize) gIRmask[n] = gIRplayer.process();
else if (n>=gIRsize) gIRmask[n] = 0;
}
// Transform IR to frequency domain
gFftIR.setup(gFftSize);
gFftIR.fft(gIRmask);
// Fill static vectors with IR frequency domain real and imaginary
for(int n=0; n<gFftSize; n++) {
gIRfdr[n] = gFftIR.fdr(n);
gIRfdi[n] = gFftIR.fdi(n);
}
gFft.setup(gFftSize); // for audio input to convolve with IR
gFftTask = Bela_createAuxiliaryTask(process_fft_background, 50, "bela-process-fft");
return true;
}
void process_fft(std::vector<float> const& inBuffer, unsigned int inPointer, std::vector<float>& outBuffer, unsigned int outPointer, std::vector<float> const& IRfdr, std::vector<float> const& IRfdi)
{
// Unwrap circular buffer of audio input
static std::vector<float> unwrappedBuffer(gFftSize);
for(int n = 0; n < gFftSize; n++) {
if (n < gHopSize){
int circularBufferIndex = (inPointer + n - gHopSize + gBufferSize) % gBufferSize;
unwrappedBuffer[n] = inBuffer[circularBufferIndex];
}
else if (n >= gHopSize) unwrappedBuffer[n] = 0; //zero pad to FFT size, is concatenation better???
}
// Process the audio input FFT
gFft.fft(unwrappedBuffer);
// Multiply frequency domain of input with frequency domain of IR.
for(int n = 0; n < gFftSize; n++) {
gFft.fdr(n) = gFft.fdr(n)*IRfdr[n] - gFft.fdi(n)*IRfdi[n];
gFft.fdi(n) = gFft.fdi(n)*IRfdr[n] + gFft.fdr(n)*IRfdi[n];
}
// Transform to time domain and output
gFft.ifft();
for(int n = 0; n < (gHopSize+gIRsize-1); n++) {
int circularBufferIndex = (outPointer+n) % gBufferSize;
outBuffer[circularBufferIndex] += gFft.td(n);
}
}
void process_fft_background(void *)
{
process_fft(gInputBuffer, gCachedInputBufferPointer, gOutputBuffer, gOutputBufferWritePointer, gIRfdr, gIRfdi);
gOutputBufferWritePointer = (gOutputBufferWritePointer + gHopSize) % gBufferSize; // update out buffer write pointer to start at next hop
}
This just gives me a flat scope line for output when i can see input audio.
If I comment out the multiplication I get the audio input at the output so I know everything else working.
When I put the IR fft code in process_fft()
the whole thing works and I get the input convolved with the IR at the output. I'm fairly convinced my problem is either that running the fft process in setup isn't working or I'm failing to access the variables, created in setup, from inside process_fft()
. Would those issues likely cause errors displayed in the ide?