COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :

Go Back   Cockos Incorporated Forums > Other Software Discussion > WDL users forum

Reply
 
Thread Tools Display Modes
Old 08-27-2015, 11:20 AM   #1
TBProAudio
Human being with feelings
 
TBProAudio's Avatar
 
Join Date: May 2014
Location: Germany
Posts: 643
Default 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
__________________
www.tbproaudio.de
TBProAudio is offline   Reply With Quote
Old 08-27-2015, 11:31 AM   #2
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

Well, the example uses the zero-latency engine (WDL_ConvolutionEngine_Div). If you switch to WDL_ConvolutionEngine, you should see some latency.
Tale is offline   Reply With Quote
Old 08-27-2015, 03:03 PM   #3
TBProAudio
Human being with feelings
 
TBProAudio's Avatar
 
Join Date: May 2014
Location: Germany
Posts: 643
Default

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
__________________
www.tbproaudio.de
TBProAudio is offline   Reply With Quote
Old 08-28-2015, 01:24 AM   #4
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

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);
}
Tale is offline   Reply With Quote
Old 08-29-2015, 02:59 AM   #5
TBProAudio
Human being with feelings
 
TBProAudio's Avatar
 
Join Date: May 2014
Location: Germany
Posts: 643
Default

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
__________________
www.tbproaudio.de
TBProAudio is offline   Reply With Quote
Old 08-29-2015, 05:32 AM   #6
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

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);
Tale is offline   Reply With Quote
Old 08-29-2015, 08:24 AM   #7
TBProAudio
Human being with feelings
 
TBProAudio's Avatar
 
Join Date: May 2014
Location: Germany
Posts: 643
Default

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
__________________
www.tbproaudio.de
TBProAudio is offline   Reply With Quote
Old 08-30-2015, 08:04 AM   #8
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

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.
Tale is offline   Reply With Quote
Old 08-31-2015, 12:51 AM   #9
TBProAudio
Human being with feelings
 
TBProAudio's Avatar
 
Join Date: May 2014
Location: Germany
Posts: 643
Default

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
__________________
www.tbproaudio.de
TBProAudio is offline   Reply With Quote
Old 08-31-2015, 01:34 AM   #10
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

Quote:
Originally Posted by TBProAudio View Post
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).
Attached Images
File Type: jpg convo.jpg (34.4 KB, 255 views)
Tale is offline   Reply With Quote
Old 08-31-2015, 01:58 AM   #11
TBProAudio
Human being with feelings
 
TBProAudio's Avatar
 
Join Date: May 2014
Location: Germany
Posts: 643
Default

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
__________________
www.tbproaudio.de
TBProAudio is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:19 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.