|
08-27-2015, 11:20 AM
|
#1
|
Human being with feelings
Join Date: May 2014
Location: Germany
Posts: 643
|
WDL: help appreciated with convo engine
Hi,
currently I'm playing around with the WDL convo engine and i got some wired issues:
I started with the basic IPlug example and sent a DIRAC through the plugin in rendering mode (REAPER). The DIRAC starts at sample pos 0, no impulse set.
The rendered wave file did not show anything (even not delayed, DIRAC is just absorbed). Shifting the DIRAC start by 512+ samples gives the awaited IR.
Did i miss something? I expected to see something in the wave fale at least delayed by convo engine latency.
May be some one could give me a hint what I'm doing wrong, thank you.
Regards
Thomas
|
|
|
08-27-2015, 11:31 AM
|
#2
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
|
Well, the example uses the zero-latency engine (WDL_ConvolutionEngine_Div). If you switch to WDL_ConvolutionEngine, you should see some latency.
|
|
|
08-27-2015, 03:03 PM
|
#3
|
Human being with feelings
Join Date: May 2014
Location: Germany
Posts: 643
|
Thanks Tale for your step in.
Well, no, I'm already using WDL_ConvolutionEngine, and yes, I would expect a delay, but the engine seems to truncate the first n samples, which contain unfortunately the DIRAC (starting at sample pos 0).
This means: pushing a wave file containing a DIRAC at pos 0 through the
WDL_ConvolutionEngine results in an empty rendered wav file.
Thanks
Thomas
|
|
|
08-28-2015, 01:24 AM
|
#4
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
|
Well, you could try this, it seems to work here (assuming WDL_FFT_REALSIZE=8 and PLUG_CHANNEL_IO "1-2"):
Code:
void IPlugConvo::ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames)
{
mEngine.Add(inputs, nFrames, 1);
int nAvail = mEngine.Avail(nFrames);
if (nAvail > nFrames) nAvail = nFrames;
int i = 0;
for (int n = nFrames - nAvail; i < n; ++i)
{
outputs[0][i] = outputs[1][i] = 0;
}
WDL_FFT_REAL* convo = mEngine.Get()[0];
for (int j = 0; j < nAvail; ++i, ++j)
{
outputs[0][i] = outputs[1][i] = convo[j];
}
mEngine.Advance(nAvail);
}
|
|
|
08-29-2015, 02:59 AM
|
#5
|
Human being with feelings
Join Date: May 2014
Location: Germany
Posts: 643
|
Thank you for providing this solution, but it did not fix the problem
Still, convo engine seems to drop the first input samples after setting IR data.
This disables PDC, as the outcoming signal is not in sync with host. In fact convoengine drops first n samples, where n is the length of the IR data.
convoengine should not do this or?
In any case this fixes the problem, not nice, but working:
IPlugConvoEngine.cpp: void IPlugConvoEngine::Reset()
Code:
// Tie the impulse response to the convolution engine.
mEngine.SetImpulse(&mImpulse);
// Start fix ...
// pre-feed convoengine to avoid loss of first samples
// Allocate buffer of size irLength and clear it
double **dummy = new double*[1]; dummy[0] = new double[irLength]; memset(dummy[0], 0, irLength * sizeof(double));
// feed engine with samples
mEngine.Add(dummy, irLength, 1);
// clear everything
delete dummy[0];delete dummy;
// End fix ...
regards
Thomas
|
|
|
08-29-2015, 05:32 AM
|
#6
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
|
Hmm... My Reset() resamples the IR, but if I leave that out this is what I do:
Code:
mImpulse.SetNumChannels(1);
const int irLength = sizeof(mIR) / sizeof(mIR[0]);
int len = mImpulse.SetLength(irLength);
WDL_FFT_REAL* dest = mImpulse.impulses[0].Get();
for (int i = 0; i < len; ++i) dest[i] = (WDL_FFT_REAL)mIR[i];
mEngine.SetImpulse(&mImpulse);
|
|
|
08-29-2015, 08:24 AM
|
#7
|
Human being with feelings
Join Date: May 2014
Location: Germany
Posts: 643
|
Sorry, here is the full code for reset:
Code:
void IPlugConvoEngine::Reset()
{
TRACE; IMutexLock lock(this);
// Detect a change in sample rate.
if (GetSampleRate() != mSampleRate)
{
mSampleRate = GetSampleRate();
// Use longer, internal Impuls
const int irLength = sizeof(mIR) / sizeof(mIR[0]);
for(int i = 0; i < irLength;i++)
mIR[i] = 0.0f;
mIR[0] = 1.0;
const double irSampleRate = 44100.;
mImpulse.SetNumChannels(1);
#if defined(_USE_WDL_RESAMPLER)
mResampler.SetMode(false, 0, true); // Sinc, default size
mResampler.SetFeedMode(true); // Input driven
#elif defined(_USE_R8BRAIN)
if (mResampler) delete mResampler;
mResampler = new CDSPResampler16IR(irSampleRate, mSampleRate, mBlockLength);
#endif
// Resample the impulse response.
int len = mImpulse.SetLength(ResampleLength(irLength, irSampleRate, mSampleRate));
if (len) Resample(mIR, irLength, irSampleRate, mImpulse.impulses[0].Get(), len, mSampleRate);
// Tie the impulse response to the convolution engine.
mEngine.SetImpulse(&mImpulse);
// Start fix ...
// pre-feed convoengine to avoid loss of first samples
// Allocate buffer of size irLength and clear it
double **dummy = new double*[1]; dummy[0] = new double[irLength]; memset(dummy[0], 0, irLength * sizeof(double));
// feed engine with samples
mEngine.Add(dummy, irLength, 1);
// clear everything
delete dummy[0];delete dummy;
// End fix ...
}
}
I modified mIR so it is a simple DIRAC. So you can also use the IR from your example, no change.
The issue with the example code is that latency is not reported to the host, so no PDC at all. In this case you cannot check if plugin/convoengine and host are running synchronous. The only way to check synchronism is (offline) rendering.
So still i´m quite sure (maybe due to my stupidity) that convoengine drops irLength sample after SetImpulse, before any output is happening.
Still very strange...
Thank you for your help :-)
Thomas
|
|
|
08-30-2015, 08:04 AM
|
#8
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
|
Yeah, that looks like my current code... At what sample rate are you testing this? Because I'm not sure what happens to the Dirac IR if you resample it.
|
|
|
08-31-2015, 12:51 AM
|
#9
|
Human being with feelings
Join Date: May 2014
Location: Germany
Posts: 643
|
Thank for your investigation.
SR is 44100 for IR + plugin, so no SRC.
As i said, if engine is pre-fed with irlength samples right after SetImpulse, everything is fine :-)
Regards
Thomas
|
|
|
08-31-2015, 01:34 AM
|
#10
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
|
Quote:
Originally Posted by TBProAudio
As i said, if engine is pre-fed with irlength samples right after SetImpulse, everything is fine :-)
|
Right. That is not what I get here, at least not exactly.
If have recreated your test, so I have mIR[512]={1,0}, and I am using WDL_ConvolutionEngine. If I send an impulse through it, then it comes out again a bunch of samples later, which is to be expected. However, the impulse comes out again after 480 samples, not 512 (see attached screenshot of input/dry signal, convo output). After some investigation I found the latency to be ir_length-audio_render_buffer_length.
So if your audio buffer length happens to be 512 samples, then yeah, I also see no latency at all. I guess I will have to think about this and/or look into it (when I have more time).
|
|
|
08-31-2015, 01:58 AM
|
#11
|
Human being with feelings
Join Date: May 2014
Location: Germany
Posts: 643
|
Thanks for following this, and i think we are on the right track, but not yet finished :-)
May be my fix was bounded to my audio settings (512 smp), so it could be the case that the pre-feed needs to be audiobuffer length instead of ir length.
Maybe we could send an impulse with length 1024, Dirac at pos 0 and pos 512...
So we could measure the drop and overall latency.
regards
Thomas
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 04:19 AM.
|