Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delay1's first output sample is its input, rather than 0 #1313

Closed
jamshark70 opened this issue Feb 14, 2015 · 6 comments
Closed

Delay1's first output sample is its input, rather than 0 #1313

jamshark70 opened this issue Feb 14, 2015 · 6 comments
Labels
bug Issues that relate to unexpected/unwanted behavior. Don't use for PRs. comp: server plugins

Comments

@jamshark70
Copy link
Contributor

Are we absolutely sure this is correct, in Delay1?

void Delay1_Ctor(Delay1* unit)
{
    //printf("Delay1_Reset\n");
    SETCALC(Delay1_next);
    unit->m_x1 = ZIN0(0);
    Delay1_next(unit, 1);
}

Specifically unit->m_x1 = ZIN0(0);

By definition, a delay line should be silent (i.e., 0) until the delay time has passed. The delay time here is 1 sample (ar) or 1 control block (kr). But instead of silence, this code replicates the first input value.

One user impact is that you can't use Delay1 on a trigger that occurs in the first sample or control block:

a = {
    var trig = Impulse.kr(0);
    Poll.kr(Delay1.kr(trig), trig);
    FreeSelf.kr(trig <= 0);
    Silent.ar(1)
}.play;

... prints nothing, where I'd have expected Poll's trigger input to be 0 in the first kr block, then 1 in the second. As a result, to delay an initial trigger (assuming kr) by 1 block, you have to use the clumsier construction DelayN.kr(trig, 0.01, ControlDur.ir).

@jamshark70 jamshark70 added bug Issues that relate to unexpected/unwanted behavior. Don't use for PRs. comp: server plugins labels Feb 14, 2015
@telephon
Copy link
Member

The Delay1_Ctor method calls Delay1_next(unit, 1);, which should normally then do the right thing. But:

float x1 = unit->m_x1;
<...>
LOOP(inNumSamples & 3,
        x0 = ZXP(in);
        ZXP(out) = x1;
        x1 = x0;
    );

This will output unit->m_x1, which has been set by Delay1_Ctor to the input. So yes, this is wrong.

Somehow I have a hard time testing this though.

@telephon
Copy link
Member

Trying your example (and a variant) I do get the expected result.

(
a = {
    var trig = Impulse.ar(0);
    Poll.ar(Delay1.ar(trig), trig, "hello");
    FreeSelf.kr(T2K.kr(trig) <= 0);
    Silent.ar(1)
}.play;
)

(
a = {
    var trig = Impulse.kr(0);
    Poll.kr(Delay1.kr(trig), trig, "hello");
    FreeSelf.kr(trig <= 0);
    Silent.ar(1)
}.play;
)

Returns: hello: 0

@jamshark70
Copy link
Contributor Author

Probably close this one. I must have been seeing this only in my faulty (now-retired) local branch. Using a new local branch, forked off from very recent master, I don't see the problem anymore.

b = Buffer.alloc(s, 64, 1);

a = {
    var trig = Impulse.ar(0);
    RecordBuf.ar(Delay1.ar(trig), b, loop: 0, doneAction: 2);
    Silent.ar(1)
}.play;

b.getn(0, 5, _.postln);
--> [ 0, 1, 0, 0, 0 ]

Same for kr.

@jamshark70
Copy link
Contributor Author

jamshark70 commented Oct 11, 2023

I need to reopen this issue. I just got bitten by it in a class yesterday.

a = {
	var sig = Impulse.kr(0);
	var delay1 = Delay1.kr(sig);
	[sig, delay1].poll(sig);
	FreeSelf.kr(sig <= 0);
	Silent.ar(1)
}.play;

UGen Array [1]: 1
UGen Array [0]: 1

The context in class was to demonstrate the lowpass-ish behavior of a two point averaging filter: (sig * 0.5) + (Delay1.ar(sig) * 0.5). The impulse response of this filter should be 0.5, 0.5, 0, 0, 0, 0 ... but instead, I get:

b = Buffer.alloc(s, 2048, 1);

(
{
	var sig = Impulse.ar(0),
	delay1 = Delay1.ar(sig);
	RecordBuf.ar((sig + delay1) * 0.5, b, loop: 0, doneAction: 2)
}.play;
)

b.getToFloatArray(wait: -1, action: { |data| d = data.postln });

FloatArray[ 1.0, 0.5, 0.0, 0.0 ... ]  // no

EDIT: What I don't understand is why we are getting different behavior in different systems, at different times. According to https://github.com/supercollider/supercollider/blame/28aea6c19309ee496dc73fb32a85fd8e1dc25016/server/plugins/FilterUGens.cpp#L1951, the line unit->m_x1 = ZIN0(0); has never changed since the initial revision 😵

@jamshark70 jamshark70 reopened this Oct 11, 2023
@mtmccrea
Copy link
Member

This will output unit->m_x1, which has been set by Delay1_Ctor to the input. So yes, this is wrong.

Yes, this is wrong, and unit->m_x1 also needs to be reset to 0.0 at the tail of the ctor.

I'll bump this up to the top of the list for the next batch of init sample fixes.

EDIT: What I don't understand is why we are getting different behavior in different systems, at different times.

Impulse was fixed in the intervening years, so perhaps --> [ 0, 1, 0, 0, 0 ] was a case of two wrongs made a right, Impulse was fixed, and we're left with a right (Impulse) and a wrong (Delay1), which now gives [ 1.0, 1.0, 0.0, 0.0, 0.0 ]? 😵‍💫

@mtmccrea
Copy link
Member

mtmccrea commented Oct 13, 2023

PR opened: #6110

I also tested all examples in this thread to confirm they're fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issues that relate to unexpected/unwanted behavior. Don't use for PRs. comp: server plugins
Projects
None yet
Development

No branches or pull requests

3 participants