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

Does behavior of setTargetAtTime changes depending on (changes in) previous events? #2294

Closed
qsjn4ukr opened this issue Jan 27, 2021 · 5 comments

Comments

@qsjn4ukr
Copy link

According to the specification, the initial value, from which the exponentially approaching to the target value begins, is equal to the current value at the time of startTime parameter.
Suppose we have a sequence of events
SetTarget, SetTarget... SetTarget (currentTime is here, all the events in past)
It is clear that we have to consider all the sequence of previous events to find initial value, from which the automation after the last SetTarget goes.
What if we shoot now a setValueAtTime(value, startTime) with startTime less than startTime of the first event in the sequnce? Does this mean that we have to recalculate the whole sequence, change the initial value and change by jump the curve that is now rendered? Or this setValueAtTime be ignored just because it was called too late?

What needs to be clarified:
Can the initial value of the setTarget event be calculated before the event actually happens, and can it be changed afterwards by changes in previous events.

It seems that a change (insertion) of an event that precedes LinearRampToValue or ExponentialRampToValue event should lead to an instant change of the ramp, even if that is already in acton. Should it? Is behavior of the SetTarget not similar to that of the Linear- or ExponentialRampToValue events?

https://webaudio.github.io/web-audio-api/#dom-audioparam-settargetattime

@rtoy
Copy link
Member

rtoy commented Jan 27, 2021

One thing to keep in mind is the time for a linear or expoonential ramp is the end time of the event. For setTarget, it's the start time.

So if you have something like

t = context.currentTime;
setValueAtTime(0, t+1);
linearRampToValueAtTime(1, t+10);
// Wait 5 sec.
setValueAtTime(10, context.currentTime);

you should be a nice linear up ramp from time t+1 to time t+5. Then there's an instantaneous jump to 10 at time t+5. Then a linear ramp down to 1 until time t+10.

However, if you did something like:

t = context.currentTime;
setValueAtTime(10, t+1);
setTargetAtTime(0, t + 2);
setTargetAtTime(5, t + 10);
// Wait 5 sec.
setValueAtTime(3, context.currentTime);

the output would be a constant 10 until time t+2, at which you get a exponential approach to 0 starting at t+2. At time t+5, the value changes to 3 instantly (from wherever the setTarget value is), and stays at 3 until t+10 at which point an exponential approach to 5 begins.

Does this clarify things?

I don't think it's super clear, but the algorithm in Computation of Value plus the definitions of the events themselves makes the above examples behave as I said. (Assuming I didn't make a mistake.)

@qsjn4ukr
Copy link
Author

qsjn4ukr commented Jan 30, 2021

t = context.currentTime;
setValueAtTime(10, t+1);
setTargetAtTime(0, t + 2);
setTargetAtTime(5, t + 10);
// Wait 5 sec.
setValueAtTime(3, context.currentTime);

Question is: what if the last instruction is «setValueAtTime(3, t + 1.5);» instead?

@rtoy
Copy link
Member

rtoy commented Feb 2, 2021

As the spec says, if the specified time is before the current time, it gets clamped to the current time. Hence setValueAtTime(3, t + 1.5) is the same as setValueAtTime(3, context.currentTime).

Here is a small example to be used with https://hoch.github.io/canopy:

// @duration 5
// @sampleRate 8000

let src = new ConstantSourceNode(context);
src.connect(context.destination);

src.offset.setValueAtTime(10, 0.1)
    .setTargetAtTime(0, .2, .2)
    .setTargetAtTime(5, 1, .2);
context.suspend(0.5)
    .then(() => {
      src.offset.setValueAtTime(3, context.currentTime, .2);
    })
    .then(() => context.resume());

src.start();

I divided the times by 10 so things happen sooner.

Unfortunately, this won't work in Firefox which hasn't implemented context.suspend yet. It might be possible to fake that but I'm too lazy to try.

@qsjn4ukr
Copy link
Author

qsjn4ukr commented Feb 9, 2021

It seems that the word "clamped" did not fit on the screen when I read the specification. Everything is clear. The already runing SetTarget automation stops when method setValueAtTime/linearRampToValueAtTime/exponentialRampToValueAtTime with start/endTime <= currentTime is called. It is impossible to add an event in past.

@qsjn4ukr qsjn4ukr closed this as completed Feb 9, 2021
@rtoy
Copy link
Member

rtoy commented Feb 9, 2021

Thanks for confirming. We do want people to let us know if things could be explained better. It's always a hard trade-off because the spec is not a tutorial.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants