|
06-30-2016, 07:52 AM
|
#1
|
Human being with feelings
Join Date: Aug 2013
Posts: 236
|
Delay with smooth changing delay rate
I made a delay in IPlug but have a problem. Crackling when change rate delay from slider. How smooth changing delay rate to prevent crackling? The recorder is enough to playback I do no why have this.
Code:
repos=pos-delayL;
if (repos<0) repos=buf_size+repos;
replay1=*(buffer+repos);
replay2=*(buffer+repos+1);
*(buffer+pos)=min(*in1 + replay1*feedback,4);
*(buffer+pos+1)=min(*in2 + replay2*feedback,4);
pos=pos+2;
if (pos>= buf_size) pos=0;
*out1=*in1*drymix + replay1*wetmix;
*out2=*in2*drymix + replay2*wetmix;
Tried more simple code with small recorder surprisingly with less crackling
Code:
replay1=*(buffer+pos);
replay2=*(buffer+pos+1);
*(buffer+pos)=min(*in1 + replay1*feedback,4);
*(buffer+pos+1)=min(*in2 + replay2*feedback,4);
pos=pos+2;
if (pos>= delayL*2) pos=0;
*out1=*in1*drymix + replay1*wetmix;
*out2=*in2*drymix + replay2*wetmix;
Last edited by SaschArt; 07-01-2016 at 01:59 PM.
|
|
|
07-01-2016, 01:56 AM
|
#2
|
Human being with feelings
Join Date: Aug 2013
Posts: 236
|
No one knows the solution ?
|
|
|
07-01-2016, 04:33 AM
|
#3
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
You could try to smooth your slider, but I guess the real problem is that you are using truncation when indexing your buffer. Implementing some sort of interpolation (even linear interpolation) would probaly help a lot.
|
|
|
07-01-2016, 05:37 AM
|
#4
|
Human being with feelings
Join Date: May 2016
Posts: 34
|
hello !
in my case:
Code:
//delay.h
#pragma once
enum DelayMode
{
OFF,
CLASSIC,
PING_PONG,
INVERTED,
kNumDelayModes
};
class DelayGenerator
{
protected:
int mMode;
unsigned long delaySamples, bufferSize, dynamicBufferSize, mOffset;
double* bufferR;
double* bufferL;
double mMix;
int feedsCount;
double feedsCountM;
void ClearBuffers()
{
for (i = 0; i < bufferSize; i++)
{
bufferL[i] = 0.0;
bufferR[i] = 0.0;
}
}
void UpdateBuffers(double* outL, double* outR)
{
bufferL[mOffset] = 0.0;
bufferR[mOffset] = 0.0;
for (i = 1; i < feedsCountM; i++)
{
fact = (feedsCountM - i) / feedsCountM;
ind = (i * delaySamples + mOffset) % bufferSize;
switch(mMode)
{
case CLASSIC:
bufferL[ind] += *outL * fact;
bufferR[ind] += *outR * fact;
break;
case PING_PONG:
if (i % 2 == 0)
{
bufferL[ind] += *outL * fact;
}
else
{
bufferR[ind] += *outR * fact;
}
break;
case INVERTED:
bufferL[ind] += *outR * fact;
bufferR[ind] += *outL * fact;
break;
}
}
mOffset++;
if (mOffset >= bufferSize) mOffset = 0;
}
public:
DelayGenerator(void)
{
bufferSize = (unsigned long)(int(DELAY_TIME_MAX) * DELAY_FEED_MAX * long(SAMPLE_RATE));
bufferR = new double[bufferSize];
bufferL= new double[bufferSize];
feedsCount = DELAY_FEED_DEFAULT;
delaySamples = long(DELAY_TIME_DEFAULT) * long(SAMPLE_RATE);
dynamicBufferSize = feedsCount * delaySamples;
mMix = 0.3;
mOffset = 0;
mMode = OFF;
ClearBuffers();
}
~DelayGenerator(void)
{
ClearBuffers();
delete bufferR;
delete bufferL;
}
void SetDelayTime(double timeMS) { delaySamples = long(timeMS * long(SAMPLE_RATE)); }
void SetFeedsCount(int count)
{
feedsCount = count;
feedsCountM = count + 1;
}
void SetMode(int mode)
{
mMode = mode;
ClearBuffers();
}
void SetMix(double mix) { mMix = mix; }
void process(double* outL, double* outR)
{
if (mMode == OFF) return;
tempR = bufferR[mOffset], tempL = bufferL[mOffset];
UpdateBuffers(outL, outR);
*outL = *outL * (1 - mMix) + tempL * mMix;
*outR = *outR * (1 - mMix) + tempR * mMix;
}
private:
unsigned long i, ind;
double tempR, tempL, fact;
};
i'm not the coder: it's Alexey55 ( https://github.com/Alexey55/Plug-In/...layGenerator.h)
it works for me. But i don't know if you use the same delay/code/algo.
|
|
|
07-01-2016, 07:05 AM
|
#5
|
Human being with feelings
Join Date: Aug 2013
Posts: 236
|
Quote:
Originally Posted by Tale
You could try to smooth your slider, but I guess the real problem is that you are using truncation when indexing your buffer. Implementing some sort of interpolation (even linear interpolation) would probaly help a lot.
|
Sound very clear when no slider changing, if it was incorrectly indexed buffer was not supposed to sound distorted?
Quote:
Originally Posted by Staiff
|
There is a lot of handy codes, thanks, will check
|
|
|
07-01-2016, 09:18 AM
|
#6
|
Human being with feelings
Join Date: Aug 2013
Posts: 236
|
Staiff I tested Alexey55 delay solution and crackling a lot. Try to change delay time while using keyboard.
|
|
|
07-01-2016, 11:01 AM
|
#7
|
Human being with feelings
Join Date: May 2016
Posts: 34
|
maybe i will say stupid thing but: do you test in debug or release mod ?
if i test in debug i've crackles, even with osc.
if i test in release all work fine.
why ?
i don't know.
|
|
|
07-01-2016, 11:21 AM
|
#8
|
Human being with feelings
Join Date: Aug 2013
Posts: 236
|
I tested FirstPlugIn.dll version from archive build by Alexey55, May be you don't try to change delay time.
|
|
|
07-02-2016, 01:35 AM
|
#9
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by SaschArt
Sound very clear when no slider changing, if it was incorrectly indexed buffer was not supposed to sound distorted?
|
Here is what I think happens: You have a delay of 1 sample, which sounds good. Then you slowly increase it to 1.1, 1.2, etc., up to 2 samples. While changing it nothing happens (because 1.x gets rounded down to 1), until it gets to 2 samples, when it very suddenly changes the delay from 1 to 2 samples. I think these sudden, non-fractional steps cause crackling.
|
|
|
07-02-2016, 04:00 AM
|
#10
|
Human being with feelings
Join Date: May 2015
Location: Serbia
Posts: 654
|
Try this:
Code:
#include <vector>
using namespace std;
class InterpolatedDelay
{
public:
void SetMaxBufferSize(int size)
{
mem.resize(size);
MAXDELAY = size;
}
double DelaySignal(double in, double delaySamples)
{
mem[index] = in;
intdelay = int(delaySamples - 0.4999999999);
frac = delaySamples - double(intdelay);
temp1 = index - intdelay;
temp2 = temp1 - 1;
if (temp1 < 0)
temp1 = temp1 + (double)MAXDELAY;
temp1 = mem[(int)temp1];
if (temp2 < 0)
temp2 = temp2 + (double)MAXDELAY;
temp2 = mem[(int)temp2];
frac = (1 - frac) / (1 + frac);
out = temp2 + frac * (temp1 - out1);
out1 = out;
index = index + 1;
if (index > MAXDELAY) index = 0;
}
private:
int index;
int intdelay;
double frac;
double temp1, temp2;
double out = 0.0, out1 = 0.0;
vector <double> mem;
int MAXDELAY;
};
|
|
|
07-02-2016, 12:53 PM
|
#11
|
Human being with feelings
Join Date: Aug 2013
Posts: 236
|
Quote:
Originally Posted by Tale
Here is what I think happens: You have a delay of 1 sample, which sounds good. Then you slowly increase it to 1.1, 1.2, etc., up to 2 samples. While changing it nothing happens (because 1.x gets rounded down to 1), until it gets to 2 samples, when it very suddenly changes the delay from 1 to 2 samples. I think these sudden, non-fractional steps cause crackling.
|
My sliders for delay rate are beat sync 1/8, 1/4T,1/8D,1/4 etc
Quote:
Originally Posted by Youlean
Try this:
|
I will check , thanks but at first sight can not find where to return DelaySignal
Last edited by SaschArt; 07-02-2016 at 01:47 PM.
|
|
|
07-03-2016, 12:10 AM
|
#12
|
Human being with feelings
Join Date: Apr 2012
Posts: 279
|
Quote:
Originally Posted by SaschArt
I will check , thanks but at first sight can not find where to return DelaySignal
|
Add "return out" at the end
|
|
|
07-03-2016, 12:30 AM
|
#13
|
Human being with feelings
Join Date: May 2015
Location: Serbia
Posts: 654
|
Quote:
Originally Posted by stw
Add "return out" at the end
|
Yep, this should be nice.. 😁
I didn't tested this, but it should work, I converted this from Flowstone interpolated delay module. If you still get glitches, applay low pass filter on parameter...
|
|
|
07-03-2016, 05:22 AM
|
#14
|
Human being with feelings
Join Date: Jan 2014
Posts: 5,207
|
Wish ReaDelay worked like this
|
|
|
07-04-2016, 03:01 AM
|
#15
|
Human being with feelings
Join Date: Nov 2013
Location: France
Posts: 181
|
Hi SaschArt !
Quote:
Originally Posted by SaschArt
No one knows the solution ?
|
I use the following code to read a value from a buffer:
Code:
inline double readBuff(double * Buff, double ind)
{
long pos;
double x_1, x0, x1, x2;
double a, b, c;
double delta;
if (ind < 0.0) ind += EchBuffsiz;
pos = (long)(ind);
delta = ind - (double) pos;
x_1 = Buff[(pos-1) & EchBuffMask];
x0 = Buff[(pos) & EchBuffMask];
x1 = Buff[(pos+1) & EchBuffMask];
x2 = Buff[(pos+2) & EchBuffMask];
a = (3.0 * (x0-x1) - x_1 + x2) / 2.0;
b = 2.0*x1 + x_1 - (5.0*x0 + x2) / 2.0;
c = (x1 - x_1) / 2.0;
return (((a * delta) + b) * delta + c) * delta + x0;
}
The buffer is Buff, the buffer size is EchBuffsiz, a power of 2, with EchBuffMask= EchBuffsiz-1; ind is the fractional index. It is usually the write position in the buffer, minus a variable delay.
And I use a low pass filter when I perform large changes in the delay.
Precisely, the write position (Wp, an integer) is incremented by 1 for every sample, the delay (Dy, any number), is fixed for a while, and the delay variations (Dv, typically a LFO, an envelop, a parameter from GUI, etc.) is filtered at audio rate. The call is :
Code:
out=readBuff(Buffer, Wp-Dy-Dv);
Reaching a new delay value target (DelayTarget) after a change can be linear (increment = (DelayTarget-Dv)/timeToReachInNumberOfSamples; then use Dv=Dv+increment; in audio loop) or exponential (like Dv=(1.0-A)*Dv+A*DelayTarget; with A between 0.01 and 0.000001 for fast to slow variations, nice for suddenly changing DelayTarget), and execute a test to set Dv=DelayTarget; when the values are very close.
Hope this helps. This works very well for me.
|
|
|
09-08-2016, 07:01 AM
|
#16
|
Human being with feelings
Join Date: Aug 2013
Posts: 236
|
Thanks for all the posts and help
I test this codes but the results not satisfied me enough. So I did my own research, to see exactly what is happen when the rate change. I made a micro-oscilloscope which stop exactly when the rate change, here's the result:
So the wave are cut, this is the problem. My solution was crossfade about 50-100ms from older wave to the new. The result is perfect and no need any filter, I made all my delays with this solution and works very well.
|
|
|
09-20-2016, 10:01 AM
|
#17
|
Human being with feelings
Join Date: Sep 2009
Posts: 623
|
Think of it like a looping tape, and changing the delay time is just moving the head. If you move the head 6 inches instantaneously, it's going to pop. If you move it slowly, it will do sort of a pitch shift thingy while it's moving.
To get smooth delay changes you have to:
1) Prevent the delay value from changing too fast. A simple LPF on the delay value can fix this.
2) Interpolate the delay value between samples. that way as you move your delay value, it has a continuous waveform to pull from.
3) Keep your delay buffer the same size. Obviously if you are resizing your buffer for every delay change, you are going to get pops and other nasties. Also, it would be a beast on your CPU.
|
|
|
07-02-2017, 01:48 AM
|
#18
|
Human being with feelings
Join Date: Apr 2017
Posts: 36
|
Quote:
Originally Posted by bozmillar
Think of it like a looping tape, and changing the delay time is just moving the head. If you move the head 6 inches instantaneously, it's going to pop. If you move it slowly, it will do sort of a pitch shift thingy while it's moving.
To get smooth delay changes you have to:
1) Prevent the delay value from changing too fast. A simple LPF on the delay value can fix this.
2) Interpolate the delay value between samples. that way as you move your delay value, it has a continuous waveform to pull from.
3) Keep your delay buffer the same size. Obviously if you are resizing your buffer for every delay change, you are going to get pops and other nasties. Also, it would be a beast on your CPU.
|
Reviving an old thread here, but I'm having a similar problem while making a pitch-delay - popping when delay length is changed, but fine when it's static.
I've basically tried all of above, resample and interpolating the signal, lpf on the parameter, cross-fading with the old signal. Still get loads of noise when changing delay (only using milliseconds, not tempo / fractional)
Last edited by mibes; 07-02-2017 at 06:10 AM.
|
|
|
07-02-2017, 11:32 AM
|
#19
|
Human being with feelings
Join Date: Dec 2015
Posts: 331
|
Quote:
Originally Posted by mibes
Reviving an old thread here, but I'm having a similar problem while making a pitch-delay - popping when delay length is changed, but fine when it's static.
I've basically tried all of above, resample and interpolating the signal, lpf on the parameter, cross-fading with the old signal. Still get loads of noise when changing delay (only using milliseconds, not tempo / fractional)
|
There are two basic choices: 1) A smoothed control signal along with fractional interpolation of the delay line, or 2) Soft mute/unmute as the delay time is changed. #1 causes pitch shifting, like changing the speed of a tape, while the is no shift in #2. Obviously, you're referring to #1.
You say you're not using fractional, but you must. Otherwise you are violating the "with smooth changing delay rate" title of this thread. If you smooth the parameter with a one-pole lpf (if you choose higher, don't use Butterworth response—the edges ring), and you use fractional delay, I assure you that it will work. Start with linear interpolation, because it's easy to debug and you'll be convinced that it works, then get more sophisticated if you want/need to.
|
|
|
07-02-2017, 11:50 AM
|
#20
|
Human being with feelings
Join Date: Apr 2017
Posts: 36
|
Quote:
Originally Posted by earlevel
You say you're not using fractional, but you must. Otherwise you are violating the "with smooth changing delay rate" title of this thread. If you smooth the parameter with a one-pole lpf (if you choose higher, don't use Butterworth response—the edges ring), and you use fractional delay, I assure you that it will work. Start with linear interpolation, because it's easy to debug and you'll be convinced that it works, then get more sophisticated if you want/need to.
|
Thanks for the response
I'm not using "fractional" delay because I'm using the resampler to repitch the significant part of the buffer. So it's doing the interpolating.
|
|
|
07-02-2017, 09:57 PM
|
#21
|
Human being with feelings
Join Date: Dec 2015
Posts: 331
|
Quote:
Originally Posted by mibes
Thanks for the response
I'm not using "fractional" delay because I'm using the resampler to repitch the significant part of the buffer. So it's doing the interpolating.
|
OK, but you're reviving a thread that is about something different...many things to go wrong in what you're trying to do...
|
|
|
07-03-2017, 02:36 PM
|
#22
|
Human being with feelings
Join Date: Apr 2017
Posts: 36
|
Figured it out finally! I'll post the mistakes I made (embarrassingly), just in case someone else has the same problem and comes here to find the answer:
I was crossfading at the new location of the read-pointer - obviously it needs to crossfade with the data just after the OLD location of the read-pointer (duh), because it needs to flow on from what was being read last.
|
|
|
07-09-2017, 02:15 AM
|
#23
|
Human being with feelings
Join Date: Apr 2015
Posts: 55
|
Oh, this would be great I have the same problem
|
|
|
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 03:58 PM.
|